Kernel - Planning SMP fix with sleep edge case
[tpg/acess2.git] / KernelLand / Kernel / semaphore.c
index 2c9fc94..e817574 100644 (file)
@@ -50,6 +50,11 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
        }
        else
        {
+               #if 0
+               Threads_int_Sleep(THREAD_STAT_SEMAPHORESLEEP,
+                       Sem, MaxToTake,
+                       &Sem->Waiting, &Sem->LastWaiting, &Sem->Protector);
+               #endif
                SHORTLOCK( &glThreadListLock );
                
                // - Remove from active list
@@ -75,20 +80,15 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
                        us, us->TID, us->ThreadName,
                        Sem, Sem->ModName, Sem->Name);
                #endif
-               
-               SHORTREL( &Sem->Protector );    // Release first to make sure it is released
+               SHORTREL( &Sem->Protector );
                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);
-               }
+               // NOTE: This can break in SMP
+               // Sleep until woken (either by getting what we need, or a timer event)
+               Threads_int_WaitForStatusEnd( THREAD_STAT_SEMAPHORESLEEP );
+               // We're only woken when there's something avaliable (or a signal arrives)
                #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
-               Log("Semaphore %p %s:%s woken", Sem, Sem->ModName, Sem->Name);
+               Log("Semaphore %p %s:%s woken from wait", 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;
@@ -190,7 +190,7 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
                
                SHORTREL( &glThreadListLock );  
                SHORTREL( &Sem->Protector );
-               while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield();
+               Threads_int_WaitForStatusEnd(THREAD_STAT_SEMAPHORESLEEP);
                // We're only woken when there's something avaliable
                us->WaitPointer = NULL;
                
@@ -244,13 +244,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
 //

UCC git Repository :: git.ucc.asn.au