X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fthreads.c;h=1781f69923440ef8a4e4f8f0ff2c84a170fef726;hb=986a763a1f3ee23b2fe3e809e2b5f023d9df6898;hp=956eede82281ff1e3153bc6da1d090c22943d478;hpb=51ab5f489bc356940c95cc936fd0508e8f07ea97;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/threads.c b/KernelLand/Kernel/threads.c index 956eede8..1781f699 100644 --- a/KernelLand/Kernel/threads.c +++ b/KernelLand/Kernel/threads.c @@ -1,5 +1,6 @@ /* - * Acess2 + * Acess2 Kernel + * - By John Hodge (thePowersGang) * threads.c * - Common Thread Control */ @@ -10,6 +11,7 @@ #include #include #include // VFS Handle maintainence +#include // Configuration #define DEBUG_TRACE_TICKETS 0 // Trace ticket counts @@ -29,6 +31,7 @@ #define MIN_PRIORITY 10 // === IMPORTS === +extern void User_Signal_Kill(int SigNum); // === TYPE === typedef struct @@ -46,7 +49,7 @@ void Threads_Delete(tThread *Thread); char *Threads_GetName(tTID ID); #if 0 void Threads_SetPriority(tThread *Thread, int Pri); -tThread *Threads_CloneTCB(Uint *Err, Uint Flags); +tThread *Threads_CloneTCB(Uint Flags); int Threads_WaitTID(int TID, int *status); tThread *Threads_GetThread(Uint TID); #endif @@ -56,6 +59,7 @@ void Threads_int_AddToList(tThreadList *List, tThread *Thread); void Threads_Exit(int TID, int Status); void Threads_Kill(tThread *Thread, int Status); void Threads_Yield(void); + int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock); void Threads_Sleep(void); int Threads_Wake(tThread *Thread); void Threads_AddActive(tThread *Thread); @@ -64,6 +68,14 @@ tThread *Threads_RemActive(void); void Threads_ToggleTrace(int TID); void Threads_Fault(int Num); void Threads_SegFault(tVAddr Addr); +void Threads_PostSignalTo(tThread *Thread, int SignalNum); +#if 0 +void Threads_PostSignal(int SignalNum); +void Threads_SignalGroup(tPGID PGID, int SignalNum); +#endif + int Threads_GetPendingSignal(void); +void Threads_SetSignalHandler(int SignalNum, void *Handler); +void *Threads_GetSignalHandler(int SignalNum); #if 0 int Threads_GetPID(void); int Threads_GetTID(void); @@ -72,12 +84,13 @@ tGID Threads_GetGID(void); int Threads_SetUID(Uint *Errno, tUID ID); int Threads_SetGID(Uint *Errno, tUID ID); #endif +void Threads_int_DumpThread(tThread *thread); void Threads_Dump(void); void Threads_DumpActive(void); // === GLOBALS === // -- Core Thread -- -struct sProcess gProcessZero = { +tProcess gProcessZero = { }; // Only used for the core kernel tThread gThreadZero = { @@ -88,6 +101,7 @@ tThread gThreadZero = { .Priority = DEFAULT_PRIORITY // Number of tickets }; // -- Processes -- +tProcess *gAllProcesses = &gProcessZero; // --- Locks --- tShortSpinlock glThreadListLock; ///\note NEVER use a heap function while locked // --- Current State --- @@ -125,14 +139,6 @@ void Threads_Init(void) Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack)); // Create Initial Task -// #if SCHEDULER_TYPE == SCHED_RR_PRI -// gaActiveThreads[gThreadZero.Priority].Head = &gThreadZero; -// gaActiveThreads[gThreadZero.Priority].Tail = &gThreadZero; -// #else -// gActiveThreads.Head = &gThreadZero; -// gActiveThreads.Tail = &gThreadZero; -// #endif - gAllThreads = &gThreadZero; giNumActiveThreads = 1; gThreadZero.Process = &gProcessZero; @@ -149,9 +155,38 @@ void Threads_Delete(tThread *Thread) Proc_ClearThread(Thread); Thread->Process->nThreads --; + + if( Thread->Process->FirstThread == Thread ) + { + Thread->Process->FirstThread = Thread->ProcessNext; + } + else + { + tThread *prev = Thread->Process->FirstThread; + while(prev && prev->ProcessNext != Thread) + prev = prev->ProcessNext; + if( !prev ) + Log_Error("Threads", "Thread %p(%i %s) is not on the process's list", + Thread, Thread->TID, Thread->ThreadName + ); + else + prev->ProcessNext = Thread->ProcessNext; + } + + // If the final thread is being terminated, clean up the process if( Thread->Process->nThreads == 0 ) { tProcess *proc = Thread->Process; + + // Remove from global process list + // TODO: RWLock + if(proc->Prev) + proc->Prev->Next = proc->Next; + else + gAllProcesses = proc->Next; + if(proc->Next) + proc->Next->Prev = proc->Prev; + // VFS Cleanup VFS_CloseAllUserHandles(); // Architecture cleanup @@ -313,23 +348,34 @@ tThread *Threads_CloneTCB(Uint Flags) new->Process = malloc( sizeof(struct sProcess) ); newproc = new->Process; newproc->PID = new->TID; + if( Flags & CLONE_PGID ) + newproc->PGID = oldproc->PGID; + else + newproc->PGID = newproc->PID; newproc->UID = oldproc->UID; newproc->GID = oldproc->GID; newproc->MaxFD = oldproc->MaxFD; - if( oldproc->CurrentWorkingDir ) - newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir ); - else - newproc->CurrentWorkingDir = NULL; - if( oldproc->RootDir ) - newproc->RootDir = strdup( oldproc->RootDir ); - else - newproc->RootDir = NULL; + newproc->CurrentWorkingDir = oldproc->CurrentWorkingDir ? strdup( oldproc->CurrentWorkingDir ) : NULL; + newproc->RootDir = oldproc->RootDir ? strdup( oldproc->RootDir ) : NULL; newproc->nThreads = 1; // Reference all handles in the VFS VFS_ReferenceUserHandles(); + + // Add to global list + newproc->Prev = NULL; + // TODO: RWLock + newproc->Next = gAllProcesses; + gAllProcesses = newproc; + + newproc->FirstThread = new; + new->ProcessNext = NULL; } else { new->Process->nThreads ++; + new->Process = cur->Process; + // TODO: Locking + new->ProcessNext = new->Process->FirstThread; + new->Process->FirstThread = new; } // Messages are not inherited @@ -418,9 +464,30 @@ tThread *Threads_CloneThreadZero(void) tTID Threads_WaitTID(int TID, int *Status) { // Any Child - if(TID == -1) { - Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child"); - return -1; + if(TID == -1) + { + Uint32 ev = Threads_WaitEvents(THREAD_EVENT_DEADCHILD); + tTID ret = -1; + if( ev & THREAD_EVENT_DEADCHILD ) + { + // A child died, get the TID + tThread *us = Proc_GetCurThread(); + ASSERT(us->LastDeadChild); + ret = us->LastDeadChild->TID; + // - Mark as dead (as opposed to undead) + ASSERT(us->LastDeadChild->Status == THREAD_STAT_ZOMBIE); + us->LastDeadChild->Status = THREAD_STAT_DEAD; + // - Set return status + if(Status) + *Status = us->LastDeadChild->RetStatus; + us->LastDeadChild = NULL; + Mutex_Release(&us->DeadChildLock); + } + else + { + Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child"); + } + return ret; } // Any peer/child thread @@ -436,33 +503,14 @@ tTID Threads_WaitTID(int TID, int *Status) } // Specific Thread - if(TID > 0) { - tThread *t = Threads_GetThread(TID); + if(TID > 0) + { tTID ret; - - // Wait for the thread to die! - // TODO: Handle child also being suspended if wanted - while(t->Status != THREAD_STAT_ZOMBIE) { - Threads_Sleep(); - Log_Debug("Threads", "%i waiting for %i, t->Status = %i", - Threads_GetTID(), t->TID, t->Status); - } - - // Set return status - ret = t->TID; - switch(t->Status) + // NOTE: Race condition - Other child dies, desired child dies, first death is 'lost' + while( (ret = Threads_WaitTID(-1, Status)) != TID ) { - case THREAD_STAT_ZOMBIE: - // Kill the thread - t->Status = THREAD_STAT_DEAD; - // TODO: Child return value? - if(Status) *Status = t->RetStatus; - // add to delete queue - Threads_Delete( t ); - break; - default: - if(Status) *Status = -1; - break; + if( ret == -1 ) + break; } return ret; } @@ -480,15 +528,13 @@ tThread *Threads_GetThread(Uint TID) tThread *thread; // Search global list - for(thread = gAllThreads; - thread; - thread = thread->GlobalNext) + for( thread = gAllThreads; thread; thread = thread->GlobalNext ) { if(thread->TID == TID) return thread; } - Log("Unable to find TID %i on main list\n", TID); + Log_Notice("Threads", "Unable to find TID %i on main list\n", TID); return NULL; } @@ -663,8 +709,10 @@ void Threads_Kill(tThread *Thread, int Status) Thread->Status = THREAD_STAT_ZOMBIE; SHORTREL( &glThreadListLock ); - // TODO: Send something like SIGCHLD - Threads_Wake( Thread->Parent ); + // TODO: It's possible that we could be timer-preempted here, should disable that... somehow + Mutex_Acquire( &Thread->Parent->DeadChildLock ); // released by parent + Thread->Parent->LastDeadChild = Thread; + Threads_PostEvent( Thread->Parent, THREAD_EVENT_DEADCHILD ); Log("Thread %i went *hurk* (%i)", Thread->TID, Status); @@ -685,6 +733,59 @@ void Threads_Yield(void) Proc_Reschedule(); } +/** + * \breif Wait for the thread status to not be a specified value + */ +void Threads_int_WaitForStatusEnd(enum eThreadStatus Status) +{ + tThread *us = Proc_GetCurThread(); + ASSERT(Status != THREAD_STAT_ACTIVE); + ASSERT(Status != THREAD_STAT_DEAD); + while( us->Status == Status ) + { + Proc_Reschedule(); + if( us->Status == Status ) + Debug("Thread %p(%i %s) rescheduled while in %s state for %p", + us, us->TID, us->ThreadName, + casTHREAD_STAT[Status], + __builtin_return_address(0)); + } +} + +int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock) +{ + SHORTLOCK( &glThreadListLock ); + tThread *us = Threads_RemActive(); + us->Next = NULL; + // - Mark as sleeping + us->Status = Status; + us->WaitPointer = Ptr; + us->RetStatus = Num; // Use RetStatus as a temp variable + + // - Add to waiting + if( ListTail ) { + if(*ListTail) { + (*ListTail)->Next = us; + } + else { + *ListHead = us; + } + *ListTail = us; + } + else { + *ListHead = us; + } + + //if( Proc_ThreadSync(us) ) + // return ; + SHORTREL( &glThreadListLock ); + if( Lock ) + SHORTREL( Lock ); + Threads_int_WaitForStatusEnd(Status); + us->WaitPointer = NULL; + return us->RetStatus; +} + /** * \fn void Threads_Sleep(void) * \brief Take the current process off the run queue @@ -716,12 +817,7 @@ void Threads_Sleep(void) // Release Spinlock SHORTREL( &glThreadListLock ); - - while(cur->Status != THREAD_STAT_ACTIVE) { - Proc_Reschedule(); - if( cur->Status != THREAD_STAT_ACTIVE ) - Log("%i - Huh? why am I up? zzzz...", cur->TID); - } + Threads_int_WaitForStatusEnd(THREAD_STAT_SLEEPING); } @@ -743,11 +839,11 @@ int Threads_Wake(tThread *Thread) return -EALREADY; case THREAD_STAT_SLEEPING: - SHORTLOCK( &glThreadListLock ); // Remove from sleeping queue + SHORTLOCK( &glThreadListLock ); Threads_int_DelFromQueue(&gSleepingThreads, Thread); - SHORTREL( &glThreadListLock ); + Threads_AddActive( Thread ); #if DEBUG_TRACE_STATE @@ -813,7 +909,7 @@ int Threads_Wake(tThread *Thread) return -ENOTIMPL; default: - Warning("Threads_Wake - Unknown process status (%i)\n", Thread->Status); + Log_Warning("Threads", "Threads_Wake - Unknown process status (%i)", Thread->Status); return -EINTERNAL; } } @@ -902,42 +998,8 @@ void Threads_AddActive(tThread *Thread) */ tThread *Threads_RemActive(void) { - #if 0 - tThread *ret = Proc_GetCurThread(); - - if( !IS_LOCKED(&glThreadListLock) ) { - Log_KernelPanic("Threads", "Threads_RemActive called without lock held"); - return NULL; - } - - // Delete from active queue - #if SCHEDULER_TYPE == SCHED_RR_PRI - if( !Threads_int_DelFromQueue(&gaActiveThreads[ret->Priority], ret) ) - #else - if( !Threads_int_DelFromQueue(&gActiveThreads, ret) ) - #endif - { - Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue", - ret, ret->TID, ret->ThreadName - ); - return NULL; - } - - ret->Next = NULL; - ret->Remaining = 0; - giNumActiveThreads --; - // no need to decrement tickets, scheduler did it for us - - #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS - Log("CPU%i %p (%i %s) removed, giFreeTickets = %i [nc]", - GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets); - #endif - - return ret; - #else return Proc_GetCurThread(); - #endif } /** @@ -1000,7 +1062,110 @@ void Threads_SegFault(tVAddr Addr) //Threads_Exit( 0, -1 ); } + +void Threads_PostSignalTo(tThread *Thread, int SignalNum) +{ + ASSERT(Thread); + Log_Debug("Threads", "Signalling %i(%s) with %i", Thread->TID, Thread->ThreadName, SignalNum); + Thread->PendingSignal = SignalNum; + Threads_PostEvent(Thread, THREAD_EVENT_SIGNAL); +} +void Threads_PostSignal(int SignalNum) +{ + Threads_PostSignalTo( Proc_GetCurThread(), SignalNum ); +} + +void Threads_SignalGroup(tPGID PGID, int Signal) +{ + for( tProcess *proc = gAllProcesses; proc; proc = proc->Next ) + { + if(proc->PGID == PGID) + { + Threads_PostSignalTo(proc->FirstThread, Signal); + } + } +} + +/** + */ +int Threads_GetPendingSignal(void) +{ + tThread *cur = Proc_GetCurThread(); + + // Atomic AND with 0 fetches and clears in one operation + int ret = __sync_fetch_and_and( &cur->PendingSignal, 0 ); + if( ret ) + { + Log_Debug("Threads", "Thread %i(%s) has signal %i pending", + cur->TID, cur->ThreadName, ret); + } + return ret; +} + +/* + * \brief Update the current thread's signal handler + */ +void Threads_SetSignalHandler(int SignalNum, void *Handler) +{ + if( SignalNum <= 0 || SignalNum >= NSIGNALS ) + return ; + if( !MM_IsUser(Handler) ) + return ; + Proc_GetCurThread()->Process->SignalHandlers[SignalNum] = Handler; +} + +/** + * \brief Gets the registered (or default, if none set) handler for a signal. + * \return Handler function pointer, OR NULL if no signal to be ignored + */ +void *Threads_GetSignalHandler(int SignalNum) +{ + // TODO: Core dump + void *User_Signal_Core = User_Signal_Kill; + + if( SignalNum <= 0 || SignalNum >= NSIGNALS ) + return NULL; + void *ret = Proc_GetCurThread()->Process->SignalHandlers[SignalNum]; + if( !ret || (SignalNum == SIGKILL || SignalNum == SIGSTOP) ) + { + // Defaults + switch(SignalNum) + { + case SIGHUP: + case SIGINT: + ret = User_Signal_Kill; + break; + case SIGQUIT: + case SIGILL: + case SIGABRT: + case SIGFPE: + ret = User_Signal_Core; + break; + case SIGKILL: + ret = User_Signal_Kill; + break; + case SIGSEGV: + ret = User_Signal_Core; + break; + case SIGPIPE: + case SIGALRM: + case SIGTERM: + ret = User_Signal_Kill; + break; + default: + ret = NULL; + break; + } + } + Log_Debug("Threads", "Handler %p for signal %i", ret, SignalNum); + return ret; +} + // --- Process Structure Access Functions --- +tPGID Threads_GetPGID(void) +{ + return Proc_GetCurThread()->Process->PGID; +} tPID Threads_GetPID(void) { return Proc_GetCurThread()->Process->PID; @@ -1063,6 +1228,50 @@ char **Threads_GetCWD(void) } // --- +void Threads_int_DumpThread(tThread *thread) +{ + if( !thread ) { + Log(" %p NULL", thread); + return ; + } + if( !CheckMem(thread, sizeof(tThread)) ) { + Log(" %p INVAL", thread); + return ; + } + tPID pid = (thread->Process ? thread->Process->PID : -1); + const char *statstr = (thread->Status < sizeof(casTHREAD_STAT)/sizeof(casTHREAD_STAT[0]) + ? casTHREAD_STAT[thread->Status] : ""); + Log(" %p %i (%i) - %s (CPU %i) - %i (%s)", + thread, thread->TID, pid, thread->ThreadName, thread->CurCPU, + thread->Status, statstr + ); + switch(thread->Status) + { + case THREAD_STAT_MUTEXSLEEP: + Log(" Mutex Pointer: %p", thread->WaitPointer); + break; + case THREAD_STAT_SEMAPHORESLEEP: + Log(" Semaphore Pointer: %p", thread->WaitPointer); + Log(" Semaphore Name: %s:%s", + ((tSemaphore*)thread->WaitPointer)->ModName, + ((tSemaphore*)thread->WaitPointer)->Name + ); + break; + case THREAD_STAT_EVENTSLEEP: + Log(" Event Mask: %x", thread->RetStatus); + break; + case THREAD_STAT_ZOMBIE: + Log(" Return Status: %i", thread->RetStatus); + break; + default: break; + } + Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum); + Log(" KStack %p", thread->KernelStack); + if( thread->bInstrTrace ) + Log(" Tracing Enabled"); + Proc_DumpThreadCPUState(thread); +} + /** * \fn void Threads_Dump(void) */ @@ -1085,16 +1294,10 @@ void Threads_DumpActive(void) #endif for(thread=list->Head;thread;thread=thread->Next) { - Log(" %p %i (%i) - %s (CPU %i)", - thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU); + Threads_int_DumpThread(thread); if(thread->Status != THREAD_STAT_ACTIVE) Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE); - Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum); - Log(" KStack 0x%x", thread->KernelStack); - if( thread->bInstrTrace ) - Log(" Tracing Enabled"); - Proc_DumpThreadCPUState(thread); } #if SCHEDULER_TYPE == SCHED_RR_PRI @@ -1108,39 +1311,13 @@ void Threads_DumpActive(void) */ void Threads_Dump(void) { - tThread *thread; - Log("--- Thread Dump ---"); Threads_DumpActive(); Log("All Threads:"); - for(thread=gAllThreads;thread;thread=thread->GlobalNext) + for(tThread *thread = gAllThreads; thread; thread = thread->GlobalNext) { - Log(" %p %i (%i) - %s (CPU %i)", - thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU); - Log(" State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]); - switch(thread->Status) - { - case THREAD_STAT_MUTEXSLEEP: - Log(" Mutex Pointer: %p", thread->WaitPointer); - break; - case THREAD_STAT_SEMAPHORESLEEP: - Log(" Semaphore Pointer: %p", thread->WaitPointer); - Log(" Semaphore Name: %s:%s", - ((tSemaphore*)thread->WaitPointer)->ModName, - ((tSemaphore*)thread->WaitPointer)->Name - ); - break; - case THREAD_STAT_ZOMBIE: - Log(" Return Status: %i", thread->RetStatus); - break; - default: break; - } - Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum); - Log(" KStack 0x%x", thread->KernelStack); - if( thread->bInstrTrace ) - Log(" Tracing Enabled"); - Proc_DumpThreadCPUState(thread); + Threads_int_DumpThread(thread); } }