* semaphore.c
* - Semaphores
*/
+#define DEBUG 0
#include <acess.h>
#include <semaphore.h>
#include <threads_int.h>
//
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;
//
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 )
}
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 );
// 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 );
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
//