-/**
- * \brief Acquire a heavy mutex
- * \param Mutex Mutex to acquire
- *
- * This type of mutex checks if the mutex is avaliable, and acquires it
- * if it is. Otherwise, the current thread is added to the mutex's wait
- * queue and the thread suspends. When the holder of the mutex completes,
- * the oldest thread (top thread) on the queue is given the lock and
- * restarted.
- */
-int Mutex_Acquire(tMutex *Mutex)
-{
- tThread *us = Proc_GetCurThread();
-
- // Get protector
- SHORTLOCK( &Mutex->Protector );
-
- //Log("Mutex_Acquire: (%p)", Mutex);
-
- // Check if the lock is already held
- if( Mutex->Owner ) {
- SHORTLOCK( &glThreadListLock );
- // - Remove from active list
- us = Threads_RemActive();
- us->Next = NULL;
- // - Mark as sleeping
- us->Status = THREAD_STAT_MUTEXSLEEP;
- us->WaitPointer = Mutex;
-
- // - Add to waiting
- if(Mutex->LastWaiting) {
- Mutex->LastWaiting->Next = us;
- Mutex->LastWaiting = us;
- }
- else {
- Mutex->Waiting = us;
- Mutex->LastWaiting = us;
- }
- #if 0
- {
- int i = 0;
- tThread *t;
- for( t = Mutex->Waiting; t; t = t->Next, i++ )
- Log("[%i] (tMutex)%p->Waiting[%i] = %p (%i %s)", us->TID, Mutex, i,
- t, t->TID, t->ThreadName);
- }
- #endif
-
- SHORTREL( &glThreadListLock );
- SHORTREL( &Mutex->Protector );
- while(us->Status == THREAD_STAT_MUTEXSLEEP) Threads_Yield();
- // We're only woken when we get the lock
- us->WaitPointer = NULL;
- }
- // Ooh, let's take it!
- else {
- 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
-
- return 0;
-}
-
-/**
- * \brief Release a held mutex
- * \param Mutex Mutex to release
- */
-void Mutex_Release(tMutex *Mutex)
-{
- SHORTLOCK( &Mutex->Protector );
- //Log("Mutex_Release: (%p)", Mutex);
- if( Mutex->Waiting ) {
- Mutex->Owner = Mutex->Waiting; // Set owner
- Mutex->Waiting = Mutex->Waiting->Next; // Next!
- // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
- // 2010-10-02 21:50 - Comemerating the death of the longest single
- // blocker in the Acess2 history. REMEMBER TO
- // FUCKING MAINTAIN YOUR FUCKING LISTS DIPWIT
- if( Mutex->LastWaiting == Mutex->Owner )
- Mutex->LastWaiting = NULL;
-
- // Wake new owner
- SHORTLOCK( &glThreadListLock );
- if( Mutex->Owner->Status != THREAD_STAT_ACTIVE )
- Threads_AddActive(Mutex->Owner);
- SHORTREL( &glThreadListLock );
- }
- else {
- 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
-}
-
-/**
- * \brief Is this mutex locked?
- * \param Mutex Mutex pointer
- */
-int Mutex_IsLocked(tMutex *Mutex)
-{
- return Mutex->Owner != NULL;
-}
-
-//
-// Initialise a semaphore
-//
-void Semaphore_Init(tSemaphore *Sem, int Value, int MaxValue, const char *Module, const char *Name)
-{
- Sem->Value = Value;
- Sem->ModName = Module;
- Sem->Name = Name;
-}
-//
-// Wait for items to be avaliable
-//
-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);
- }
-
- SHORTLOCK( &Sem->Protector );
-
- // Check if there's already items avaliable
- if( Sem->Value > 0 ) {
- // Take what we need
- if( MaxToTake && Sem->Value > MaxToTake )
- taken = MaxToTake;
- else
- taken = Sem->Value;
- Sem->Value -= taken;
- SHORTREL( &Sem->Protector );
- }
- 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;
- }
-
- 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;
-
- taken = us->RetStatus;
-
- // Get the lock again
- SHORTLOCK( &Sem->Protector );
- }
-
- // While there is space, and there are thread waiting
- // wake the first thread and give it what it wants (or what's left)
- while( (Sem->MaxValue == 0 || Sem->Value < Sem->MaxValue) && Sem->Signaling )
- {
- int given;
- tThread *toWake = Sem->Signaling;
-
- Sem->Signaling = Sem->Signaling->Next;
- // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
- if( Sem->Signaling == NULL )
- Sem->LastSignaling = NULL;
-
- // Figure out how much to give
- if( toWake->RetStatus && Sem->Value + toWake->RetStatus < Sem->MaxValue )
- given = toWake->RetStatus;
- else
- given = Sem->MaxValue - Sem->Value;
- Sem->Value -= given;
-
- // Save the number we gave to the thread's status
- toWake->RetStatus = given;
-
- // Wake the sleeper
- SHORTLOCK( &glThreadListLock );
- if( toWake->Status != THREAD_STAT_ACTIVE )
- Threads_AddActive(toWake);
- SHORTREL( &glThreadListLock );
- }
- SHORTREL( &Sem->Protector );
-
- return taken;
-}
-
-//
-// Add items to a semaphore
-//
-int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
-{
- int given;
- int added;
-
- if( AmmountToAdd < 0 ) {
- Log_Warning("Threads", "Semaphore_Signal: User bug - AmmountToAdd(%i) < 0, Sem=%p(%s)",
- AmmountToAdd, Sem, Sem->Name);
- }
- SHORTLOCK( &Sem->Protector );
-
- // Check if we have to block
- if( Sem->MaxValue && Sem->Value == Sem->MaxValue )
- {
- tThread *us;
- 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;
- }
-
- 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;
-
- // Get the lock again
- SHORTLOCK( &Sem->Protector );
- }
- // Non blocking
- else
- {
- // Figure out how much we need to take off
- if( Sem->MaxValue && Sem->Value + AmmountToAdd > Sem->MaxValue)
- added = Sem->MaxValue - Sem->Value;
- else
- added = AmmountToAdd;
- Sem->Value += added;
- }
-
- // While there are items avaliable, and there are thread waiting
- // wake the first thread and give it what it wants (or what's left)
- while( Sem->Value && Sem->Waiting )
- {
- tThread *toWake = Sem->Waiting;
-
- Sem->Waiting = Sem->Waiting->Next;
- // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
- if( Sem->Waiting == NULL )
- Sem->LastWaiting = NULL;
-
- // Figure out how much to give
- if( toWake->RetStatus && Sem->Value > toWake->RetStatus )
- given = toWake->RetStatus;
- else
- given = Sem->Value;
- Sem->Value -= given;
-
- // Save the number we gave to the thread's status
- toWake->RetStatus = given;
-
- // Wake the sleeper
- SHORTLOCK( &glThreadListLock );
- if( toWake->Status != THREAD_STAT_ACTIVE )
- Threads_AddActive(toWake);
- SHORTREL( &glThreadListLock );
- }
- SHORTREL( &Sem->Protector );
-
- return added;
-}
-
-//
-// Get the current value of a semaphore
-//
-int Semaphore_GetValue(tSemaphore *Sem)
-{
- return Sem->Value;
-}
-