X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fthreads.c;h=87001540d9a925108438f304a61ac81d654c3a61;hb=8c50e4a0672bdf9e9f6266fa5f485ad7f8b74f5b;hp=73c3f3c08b649d10d62c504a17ce2de0f8ea7dcc;hpb=4fc7efa62f7a33e0c8a499f5a175419c2d16c273;p=tpg%2Facess2.git diff --git a/Kernel/threads.c b/Kernel/threads.c index 73c3f3c0..87001540 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); @@ -1227,6 +1228,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);