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);
SHORTLOCK( &glThreadListLock );
new->GlobalPrev = NULL; // Protect against bugs
new->GlobalNext = gAllThreads;
+ gAllThreads->GlobalPrev = new;
gAllThreads = new;
SHORTREL( &glThreadListLock );
tMsg *msg;
// TODO: Kill all children
- #if 0
+ #if 1
{
tThread *child;
// TODO: I should keep a .Parent pointer, and a .Children list
- for(child = gActiveThreads;
+ for(child = gAllThreads;
child;
- child = child->Next)
+ child = child->GlobalNext)
{
- if(child->PTID == Thread->TID)
+ if(child->Parent == Thread)
Threads_Kill(child, -1);
}
}
// Lock thread list
SHORTLOCK( &glThreadListLock );
- // Delete from active list
- #if SCHEDULER_TYPE == SCHED_RR_PRI
- if( !Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
- #else
- if( !Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
- #endif
+ switch(Thread->Status)
{
- Warning("Proc_Exit - Current thread is not on the active queue");
- SHORTREL( &glThreadListLock );
- SHORTREL( &Thread->IsLocked );
- return;
- }
+ case THREAD_STAT_PREINIT: // Only on main list
+ break;
- // Ensure that we are not rescheduled
- Thread->Remaining = 0; // Clear Remaining Quantum
- Thread->Quantum = 0; // Clear Quantum to indicate dead thread
-
- // Update bookkeeping
- giNumActiveThreads --;
- #if SCHEDULER_TYPE == SCHED_LOTTERY
- if( Thread != Proc_GetCurThread() )
- giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
- #endif
+ // Currently active thread
+ case THREAD_STAT_ACTIVE:
+ #if SCHEDULER_TYPE == SCHED_RR_PRI
+ if( Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
+ #else
+ if( Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
+ #endif
+ {
+ // Ensure that we are not rescheduled
+ Thread->Remaining = 0; // Clear Remaining Quantum
+ Thread->Quantum = 0; // Clear Quantum to indicate dead thread
+
+ // Update bookkeeping
+ giNumActiveThreads --;
+ #if SCHEDULER_TYPE == SCHED_LOTTERY
+ if( Thread != Proc_GetCurThread() )
+ giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
+ #endif
+ }
+ else
+ {
+ Log_Warning("Threads",
+ "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
+ Thread, Thread->TID, Thread->ThreadName
+ );
+ }
+ break;
+ case THREAD_STAT_SLEEPING:
+ if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) )
+ {
+ Log_Warning("Threads",
+ "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list",
+ Thread, Thread->TID, Thread->ThreadName
+ );
+ }
+ break;
+ default:
+ Log_Warning("Threads", "Threads_Kill - BUG Un-checked status (%i)",
+ Thread->Status);
+ break;
+ }
// Save exit status
Thread->RetStatus = Status;
Threads_Wake( Thread->Parent );
}
- Log("Thread %i went *hurk* (%i)", Thread->TID, Thread->Status);
+ Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
// Release spinlocks
SHORTREL( &glThreadListLock );
while(gDeleteThreads)
{
thread = gDeleteThreads->Next;
- if( IS_LOCKED(&gDeleteThreads->IsLocked) ) { // Only free if structure is unused
+ // Only free if structure is unused
+ if( !IS_LOCKED(&gDeleteThreads->IsLocked) )
+ {
// Set to dead
gDeleteThreads->Status = THREAD_STAT_BURIED;
// Free name
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
}
/**
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
}
/**
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);