OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
-OBJ += messages.o modules.o syscalls.o system.o threads.o
-OBJ += $(addprefix vfs/fs/, $(addsuffix .o,$(FILESYSTEMS)))
+OBJ += messages.o modules.o syscalls.o system.o
+OBJ += threads.o mutex.o semaphore.o
OBJ += drv/vterm.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
-#OBJ += drv/kb.o drv/dma.o drv/vga.o
OBJ += binary.o bin/elf.o bin/pe.o
OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
OBJ += vfs/memfile.o vfs/nodecache.o vfs/handle.o vfs/select.o vfs/mmap.o
extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3);
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
-extern tShortSpinlock glThreadListLock;
extern int giNumCPUs;
extern int giNextTID;
extern tThread gThreadZero;
__asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
}
+void Proc_ClearThread(tThread *Thread)
+{
+ if(Thread->SavedState.SSE) {
+ free(Thread->SavedState.SSE);
+ Thread->SavedState.SSE = NULL;
+ }
+}
+
int Proc_NewKThread(void (*Fcn)(void*), void *Data)
{
Uint esp;
* \brief Start preemptive multithreading (if needed)
*/
extern void Proc_Start(void);
+/**
+ * \brief Called just before a thread is freed
+ */
+extern void Proc_ClearThread(tThread *Thread);
/**
* \brief Get the ID of this CPU
* \return Zero based CPU ID
// === GLOBALS ===
extern BOOL gaThreads_NoTaskSwitch[MAX_CPUS];
+extern tShortSpinlock glThreadListLock;
// === FUNCTIONS ===
extern tThread *Proc_GetCurThread(void);
#include <threads_int.h>
#include <errno.h>
-// === IMPORTS ===
-extern tShortSpinlock glThreadListLock;
-
// === CODE ===
/**
* \fn int Proc_SendMessage(Uint *Err, Uint Dest, int Length, void *Data)
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * mutex.c
+ * - Mutexes
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <mutex.h>
+
+// === PROTOTYPES ===
+#if 0
+ int Mutex_Acquire(tMutex *Mutex);
+void Mutex_Release(tMutex *Mutex);
+ int Mutex_IsLocked(tMutex *Mutex);
+#endif
+
+// === CODE ===
+//
+// Acquire mutex (see mutex.h for documentation)
+//
+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 DEBUG_TRACE_STATE
+ Log("%p (%i %s) waiting on mutex %p",
+ us, us->TID, us->ThreadName, Mutex);
+ #endif
+
+ #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;
+}
+
+// Release a mutex
+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
+}
+
+// Check if a mutex is locked
+int Mutex_IsLocked(tMutex *Mutex)
+{
+ return Mutex->Owner != NULL;
+}
+
+// === EXPORTS ===
+EXPORT(Mutex_Acquire);
+EXPORT(Mutex_Release);
+EXPORT(Mutex_IsLocked);
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * semaphore.c
+ * - Semaphores
+ */
+#include <acess.h>
+#include <semaphore.h>
+#include <threads_int.h>
+
+#define SEMAPHORE_DEBUG 0 // Debug semaphores
+
+// === CODE ===
+//
+// Initialise a semaphore
+//
+void Semaphore_Init(tSemaphore *Sem, int Value, int MaxValue, const char *Module, const char *Name)
+{
+ memset(Sem, 0, sizeof(tSemaphore));
+ Sem->Value = Value;
+ Sem->ModName = Module;
+ Sem->Name = Name;
+ Sem->MaxValue = MaxValue;
+}
+//
+// 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;
+ }
+ 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;
+
+ // 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;
+
+
+ #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+ Log("%p (%i %s) woken by wait on %p %s:%s",
+ toWake, toWake->TID, toWake->ThreadName,
+ Sem, Sem->ModName, Sem->Name);
+ #endif
+
+ // 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 );
+
+ #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+ Log("Semaphore %p %s:%s took %i by wait",
+ Sem, Sem->ModName, Sem->Name, taken);
+ #endif
+
+ 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;
+ #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;
+
+ // 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;
+
+ // Remove thread from list (double ended, so clear LastWaiting if needed)
+ Sem->Waiting = Sem->Waiting->Next;
+ if( Sem->Waiting == NULL )
+ Sem->LastWaiting = NULL;
+
+ // Figure out how much to give to woken thread
+ // - Requested count is stored in ->RetStatus
+ 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;
+
+ if(toWake->bInstrTrace)
+ Log("%s(%i) given %i from %p", toWake->ThreadName, toWake->TID, given, Sem);
+ #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
+ Log("%p (%i %s) woken by signal on %p %s:%s",
+ toWake, toWake->TID, toWake->ThreadName,
+ Sem, Sem->ModName, Sem->Name);
+ #endif
+
+ // Wake the sleeper
+ if( toWake->Status != THREAD_STAT_ACTIVE )
+ Threads_AddActive(toWake);
+ else
+ Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName);
+ }
+ SHORTREL( &Sem->Protector );
+
+ return added;
+}
+
+//
+// Get the current value of a semaphore
+//
+int Semaphore_GetValue(tSemaphore *Sem)
+{
+ return Sem->Value;
+}
+
+// === EXPORTS ===
+EXPORT(Semaphore_Init);
+EXPORT(Semaphore_Wait);
+EXPORT(Semaphore_Signal);
#include <threads.h>
#include <threads_int.h>
#include <errno.h>
-#include <mutex.h>
-#include <semaphore.h>
#include <hal_proc.h>
+#include <semaphore.h>
// Configuration
#define DEBUG_TRACE_TICKETS 0 // Trace ticket counts
#define DEBUG_TRACE_STATE 0 // Trace state changes (sleep/wake)
-#define SEMAPHORE_DEBUG 0 // Debug semaphores
// --- Schedulers ---
#define SCHED_UNDEF 0
#endif
void Threads_Dump(void);
void Threads_DumpActive(void);
-#if 0
- int Mutex_Acquire(tMutex *Mutex);
-void Mutex_Release(tMutex *Mutex);
- int Mutex_IsLocked(tMutex *Mutex);
-#endif
// === GLOBALS ===
// -- Core Thread --
return thread;
}
-// Acquire mutex (see mutex.h for documentation)
-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 DEBUG_TRACE_STATE
- Log("%p (%i %s) waiting on mutex %p",
- us, us->TID, us->ThreadName, Mutex);
- #endif
-
- #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;
-}
-
-// Release a mutex
-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
-}
-
-// Check if a mutex is locked
-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)
-{
- memset(Sem, 0, sizeof(tSemaphore));
- Sem->Value = Value;
- Sem->ModName = Module;
- Sem->Name = Name;
- Sem->MaxValue = MaxValue;
-}
-//
-// 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;
- }
- 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;
-
- // 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;
-
-
- #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
- Log("%p (%i %s) woken by wait on %p %s:%s",
- toWake, toWake->TID, toWake->ThreadName,
- Sem, Sem->ModName, Sem->Name);
- #endif
-
- // 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 );
-
- #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
- Log("Semaphore %p %s:%s took %i by wait",
- Sem, Sem->ModName, Sem->Name, taken);
- #endif
-
- 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;
- #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;
-
- // 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;
-
- // Remove thread from list (double ended, so clear LastWaiting if needed)
- Sem->Waiting = Sem->Waiting->Next;
- if( Sem->Waiting == NULL )
- Sem->LastWaiting = NULL;
-
- // Figure out how much to give to woken thread
- // - Requested count is stored in ->RetStatus
- 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;
-
- if(toWake->bInstrTrace)
- Log("%s(%i) given %i from %p", toWake->ThreadName, toWake->TID, given, Sem);
- #if DEBUG_TRACE_STATE || SEMAPHORE_DEBUG
- Log("%p (%i %s) woken by signal on %p %s:%s",
- toWake, toWake->TID, toWake->ThreadName,
- Sem, Sem->ModName, Sem->Name);
- #endif
-
- // Wake the sleeper
-// SHORTLOCK( &glThreadListLock );
- if( toWake->Status != THREAD_STAT_ACTIVE )
- Threads_AddActive(toWake);
- else
- Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName);
-// SHORTREL( &glThreadListLock );
- }
- SHORTREL( &Sem->Protector );
-
- return added;
-}
-
-//
-// Get the current value of a semaphore
-//
-int Semaphore_GetValue(tSemaphore *Sem)
-{
- return Sem->Value;
-}
-
// === EXPORTS ===
EXPORT(Threads_GetUID);
EXPORT(Threads_GetGID);
-EXPORT(Mutex_Acquire);
-EXPORT(Mutex_Release);
-EXPORT(Mutex_IsLocked);
-EXPORT(Semaphore_Init);
-EXPORT(Semaphore_Wait);
-EXPORT(Semaphore_Signal);