X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fthreads.c;h=5d15c929c431324cbacffb06acd3ed8dbf29df2e;hb=270e5fe88b0666021a7a6393334db7feeb8245f8;hp=c9a123d14274c6c4589a04041e1addc7a8ea0bef;hpb=3e26f25f924611d86e26de937434e5edd2569c5e;p=tpg%2Facess2.git diff --git a/Kernel/threads.c b/Kernel/threads.c index c9a123d1..5d15c929 100644 --- a/Kernel/threads.c +++ b/Kernel/threads.c @@ -62,6 +62,7 @@ tGID Threads_GetGID(void); int Threads_SetGID(Uint *Errno, tUID ID); void Threads_Dump(void); void Threads_DumpActive(void); + void Mutex_Acquire(tMutex *Mutex); void Mutex_Release(tMutex *Mutex); int Mutex_IsLocked(tMutex *Mutex); @@ -278,6 +279,7 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags) SHORTLOCK( &glThreadListLock ); new->GlobalPrev = NULL; // Protect against bugs new->GlobalNext = gAllThreads; + gAllThreads->GlobalPrev = new; gAllThreads = new; SHORTREL( &glThreadListLock ); @@ -465,15 +467,15 @@ void Threads_Kill(tThread *Thread, int Status) tMsg *msg; // TODO: Kill all children - #if 0 + #if 1 { tThread *child; // TODO: I should keep a .Parent pointer, and a .Children list - for(child = gActiveThreads; + for(child = gAllThreads; child; - child = child->Next) + child = child->GlobalNext) { - if(child->PTID == Thread->TID) + if(child->Parent == Thread) Threads_Kill(child, -1); } } @@ -495,29 +497,52 @@ void Threads_Kill(tThread *Thread, int Status) // Lock thread list SHORTLOCK( &glThreadListLock ); - // Delete from active list - #if SCHEDULER_TYPE == SCHED_RR_PRI - if( !Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) ) - #else - if( !Threads_int_DelFromQueue( &gActiveThreads, Thread ) ) - #endif + switch(Thread->Status) { - Warning("Proc_Exit - Current thread is not on the active queue"); - SHORTREL( &glThreadListLock ); - SHORTREL( &Thread->IsLocked ); - return; - } + case THREAD_STAT_PREINIT: // Only on main list + break; - // Ensure that we are not rescheduled - Thread->Remaining = 0; // Clear Remaining Quantum - Thread->Quantum = 0; // Clear Quantum to indicate dead thread - - // Update bookkeeping - giNumActiveThreads --; - #if SCHEDULER_TYPE == SCHED_LOTTERY - if( Thread != Proc_GetCurThread() ) - giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ]; - #endif + // Currently active thread + case THREAD_STAT_ACTIVE: + #if SCHEDULER_TYPE == SCHED_RR_PRI + if( Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) ) + #else + if( Threads_int_DelFromQueue( &gActiveThreads, Thread ) ) + #endif + { + // Ensure that we are not rescheduled + Thread->Remaining = 0; // Clear Remaining Quantum + Thread->Quantum = 0; // Clear Quantum to indicate dead thread + + // Update bookkeeping + giNumActiveThreads --; + #if SCHEDULER_TYPE == SCHED_LOTTERY + if( Thread != Proc_GetCurThread() ) + giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ]; + #endif + } + else + { + Log_Warning("Threads", + "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list", + Thread, Thread->TID, Thread->ThreadName + ); + } + break; + case THREAD_STAT_SLEEPING: + if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) ) + { + Log_Warning("Threads", + "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list", + Thread, Thread->TID, Thread->ThreadName + ); + } + break; + default: + Log_Warning("Threads", "Threads_Kill - BUG Un-checked status (%i)", + Thread->Status); + break; + } // Save exit status Thread->RetStatus = Status; @@ -533,7 +558,7 @@ void Threads_Kill(tThread *Thread, int Status) Threads_Wake( Thread->Parent ); } - Log("Thread %i went *hurk* (%i)", Thread->TID, Thread->Status); + Log("Thread %i went *hurk* (%i)", Thread->TID, Status); // Release spinlocks SHORTREL( &glThreadListLock ); @@ -914,7 +939,9 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) while(gDeleteThreads) { thread = gDeleteThreads->Next; - if( IS_LOCKED(&gDeleteThreads->IsLocked) ) { // Only free if structure is unused + // Only free if structure is unused + if( !IS_LOCKED(&gDeleteThreads->IsLocked) ) + { // Set to dead gDeleteThreads->Status = THREAD_STAT_BURIED; // Free name @@ -1174,6 +1201,12 @@ void Mutex_Acquire(tMutex *Mutex) Mutex->Owner = us; SHORTREL( &Mutex->Protector ); } + + #if 0 + extern tMutex glPhysAlloc; + if( Mutex != &glPhysAlloc ) + LogF("Mutex %p taken by %i %p\n", Mutex, us->TID, __builtin_return_address(0)); + #endif } /** @@ -1204,6 +1237,12 @@ void Mutex_Release(tMutex *Mutex) Mutex->Owner = NULL; } SHORTREL( &Mutex->Protector ); + + #if 0 + extern tMutex glPhysAlloc; + if( Mutex != &glPhysAlloc ) + LogF("Mutex %p released by %i %p\n", Mutex, Threads_GetTID(), __builtin_return_address(0)); + #endif } /** @@ -1215,6 +1254,86 @@ int Mutex_IsLocked(tMutex *Mutex) return Mutex->Owner != NULL; } +/** + * \brief Initialise the semaphore + * \param Value Initial value of the semaphore + * \param Label Symbolic name + */ +void Semaphore_Init(tSemaphore *Sem, int Value, const char *Label) +{ + Sem->Value = Value; + Sem->Name = Label; +} + +/** + * \brief Acquire a "item" from the semaphore + */ +void Semaphore_Wait(tSemaphore *Sem) +{ + tThread *us; + + SHORTLOCK( &Sem->Protector ); + if( Sem->Value > 0 ) { + Sem->Value --; + SHORTREL( &Sem->Protector ); + return ; + } + + SHORTLOCK( &glThreadListLock ); + + // - Remove from active list + us = Threads_RemActive(); + us->Next = NULL; + // - Mark as sleeping + us->Status = THREAD_STAT_SEMAPHORESLEEP; + us->WaitPointer = Sem; + + // - Add to waiting + if(Sem->LastWaiting) { + Sem->LastWaiting->Next = us; + Sem->LastWaiting = us; + } + else { + Sem->Waiting = us; + Sem->LastWaiting = us; + } + + SHORTREL( &glThreadListLock ); + SHORTREL( &Sem->Protector ); + while(us->Status == THREAD_STAT_MUTEXSLEEP) Threads_Yield(); + // We're only woken when there's something avaliable + us->WaitPointer = NULL; +} + +/** + * \brief Add an "item" to the semaphore + */ +void Semaphore_Signal(tSemaphore *Sem) +{ + SHORTLOCK( &Sem->Protector ); + Sem->Value ++; + + if( Sem->Waiting ) + { + tThread *toWake = Sem->Waiting; + + Sem->Waiting = Sem->Waiting->Next; // Next! + // Reset ->LastWaiting to NULL if we have just removed the last waiting thread + if( Sem->Waiting == NULL ) + Sem->LastWaiting = NULL; + + // Wake new owner + SHORTLOCK( &glThreadListLock ); + if( toWake->Status != THREAD_STAT_ACTIVE ) + Threads_AddActive(toWake); + SHORTREL( &glThreadListLock ); + + // Decrement (the value is now "owned" by `toWake`) + Sem->Value --; + } + SHORTREL( &Sem->Protector ); +} + // === EXPORTS === EXPORT(Threads_GetUID); EXPORT(Threads_GetGID);