X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fsemaphore.c;h=d4ec73139c6831a19dd512d6643020f21a043986;hb=6274aaa8894e14462a36c69090e2f9235f130e31;hp=d4583e7491f06cf9d22e14a6f1ebe36e3fb19122;hpb=48743e39650eb1ef988380e9d95f27fd40d3a9ce;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/semaphore.c b/KernelLand/Kernel/semaphore.c index d4583e74..d4ec7313 100644 --- a/KernelLand/Kernel/semaphore.c +++ b/KernelLand/Kernel/semaphore.c @@ -5,6 +5,7 @@ * semaphore.c * - Semaphores */ +#define DEBUG 0 #include #include #include @@ -17,6 +18,7 @@ // void Semaphore_Init(tSemaphore *Sem, int Value, int MaxValue, const char *Module, const char *Name) { + LOG("Init %p to %i/%i (%s:%s)", Sem, Value, MaxValue, Module, Name); memset(Sem, 0, sizeof(tSemaphore)); Sem->Value = Value; Sem->ModName = Module; @@ -28,14 +30,17 @@ void Semaphore_Init(tSemaphore *Sem, int Value, int MaxValue, const char *Module // int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) { - tThread *us; int taken; if( MaxToTake < 0 ) { Log_Warning("Threads", "Semaphore_Wait: User bug - MaxToTake(%i) < 0, Sem=%p(%s)", MaxToTake, Sem, Sem->Name); + MaxToTake = 0; } + LOG("Waiting on %p for %i (%i/%i used atm) - (%s:%s)", + Sem, MaxToTake, Sem->Value, Sem->MaxValue, Sem->ModName, Sem->Name); SHORTLOCK( &Sem->Protector ); + LOG("Protector grabbed"); // Check if there's already items avaliable if( Sem->Value > 0 ) @@ -49,48 +54,9 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) } else { - SHORTLOCK( &glThreadListLock ); - - // - Remove from active list - us = Threads_RemActive(); - us->Next = NULL; - // - Mark as sleeping - us->Status = THREAD_STAT_SEMAPHORESLEEP; - us->WaitPointer = Sem; - us->RetStatus = MaxToTake; // Use RetStatus as a temp variable - - // - Add to waiting - if(Sem->LastWaiting) { - Sem->LastWaiting->Next = us; - Sem->LastWaiting = us; - } - else { - Sem->Waiting = us; - Sem->LastWaiting = us; - } - - #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG - Log("%p (%i %s) waiting on semaphore %p %s:%s", - us, us->TID, us->ThreadName, - Sem, Sem->ModName, Sem->Name); - #endif - - SHORTREL( &Sem->Protector ); // Release first to make sure it is released - SHORTREL( &glThreadListLock ); - while( us->Status == THREAD_STAT_SEMAPHORESLEEP ) - { - Threads_Yield(); - if(us->Status == THREAD_STAT_SEMAPHORESLEEP) - Log_Warning("Threads", "Semaphore %p %s:%s re-schedulued while asleep", - Sem, Sem->ModName, Sem->Name); - } - #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG - Log("Semaphore %p %s:%s woken", Sem, Sem->ModName, Sem->Name); - #endif - // We're only woken when there's something avaliable (or a signal arrives) - us->WaitPointer = NULL; - - taken = us->RetStatus; + taken = Threads_int_Sleep(THREAD_STAT_SEMAPHORESLEEP, + Sem, MaxToTake, + &Sem->Waiting, &Sem->LastWaiting, &Sem->Protector); // Get the lock again SHORTLOCK( &Sem->Protector ); @@ -126,10 +92,8 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) toWake->RetStatus = given; // Wake the sleeper - SHORTLOCK( &glThreadListLock ); if( toWake->Status != THREAD_STAT_ACTIVE ) Threads_AddActive(toWake); - SHORTREL( &glThreadListLock ); } SHORTREL( &Sem->Protector ); @@ -158,44 +122,13 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) // Check if we have to block if( Sem->MaxValue && Sem->Value == Sem->MaxValue ) { - tThread *us; #if 0 Log_Debug("Threads", "Semaphore_Signal: IDLE Sem = %s:%s", Sem->ModName, Sem->Name); Log_Debug("Threads", "Semaphore_Signal: Sem->Value(%i) == Sem->MaxValue(%i)", Sem->Value, Sem->MaxValue); #endif - - SHORTLOCK( &glThreadListLock ); - // - Remove from active list - us = Threads_RemActive(); - us->Next = NULL; - // - Mark as sleeping - us->Status = THREAD_STAT_SEMAPHORESLEEP; - us->WaitPointer = Sem; - us->RetStatus = AmmountToAdd; // Use RetStatus as a temp variable - - // - Add to waiting - if(Sem->LastSignaling) { - Sem->LastSignaling->Next = us; - Sem->LastSignaling = us; - } - else { - Sem->Signaling = us; - Sem->LastSignaling = us; - } - - #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG - Log("%p (%i %s) signaling semaphore %p %s:%s", - us, us->TID, us->ThreadName, - Sem, Sem->ModName, Sem->Name); - #endif - - SHORTREL( &glThreadListLock ); - SHORTREL( &Sem->Protector ); - while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield(); - // We're only woken when there's something avaliable - us->WaitPointer = NULL; - - added = us->RetStatus; + added = Threads_int_Sleep(THREAD_STAT_SEMAPHORESLEEP, + Sem, AmmountToAdd, + &Sem->Signaling, &Sem->LastSignaling, &Sem->Protector); // Get the lock again SHORTLOCK( &Sem->Protector ); @@ -245,13 +178,44 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) if( toWake->Status != THREAD_STAT_ACTIVE ) Threads_AddActive(toWake); else - Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName); + Warning("Thread %p (%i %s) is already awake", + toWake, toWake->TID, toWake->ThreadName); } SHORTREL( &Sem->Protector ); return added; } +void Semaphore_ForceWake(tThread *Thread) +{ + if( !CPU_HAS_LOCK(&Thread->IsLocked) ) { + Log_Error("Semaphore", "Force wake should be called with the thread lock held"); + return ; + } + if( Thread->Status != THREAD_STAT_SEMAPHORESLEEP ) { + Log_Error("Semaphore", "_ForceWake called on non-semaphore thread"); + return ; + } + + tSemaphore *sem = Thread->WaitPointer; + SHORTLOCK( &sem->Protector ); + tThread *prev = NULL; + if( sem->Waiting == Thread ) + sem->Waiting = sem->Waiting->Next; + else + { + for( prev = sem->Waiting; prev && prev->Next != Thread; prev = prev->Next ) + ; + if( prev ) + prev->Next = Thread->Next; + } + if( sem->LastWaiting == Thread ) + sem->LastWaiting = prev; + SHORTREL( &sem->Protector ); + Thread->RetStatus = 0; + Threads_AddActive(Thread); +} + // // Get the current value of a semaphore //