extern tThread *Proc_GetCurThread(void);
extern int Proc_Clone(Uint *Err, Uint Flags);
extern void Proc_CallFaultHandler(tThread *Thread);
+extern int GetCPUNum(void);
// === PROTOTYPES ===
void Threads_Init(void);
- int Threads_SetName(char *NewName);
+ int Threads_SetName(const char *NewName);
char *Threads_GetName(int ID);
void Threads_SetPriority(tThread *Thread, int Pri);
tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
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);
}
/**
- * \fn void Threads_SetName(char *NewName)
+ * \fn void Threads_SetName(const char *NewName)
* \brief Sets the current thread's name
* \param NewName New name for the thread
* \return Boolean Failure
*/
-int Threads_SetName(char *NewName)
+int Threads_SetName(const char *NewName)
{
tThread *cur = Proc_GetCurThread();
char *oldname = cur->ThreadName;
SHORTLOCK( &glThreadListLock );
new->GlobalPrev = NULL; // Protect against bugs
new->GlobalNext = gAllThreads;
+ gAllThreads->GlobalPrev = new;
gAllThreads = new;
SHORTREL( &glThreadListLock );
void Threads_Kill(tThread *Thread, int Status)
{
tMsg *msg;
+ int isCurThread = Thread == Proc_GetCurThread();
// 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");
+ case THREAD_STAT_PREINIT: // Only on main list
+ break;
+
+ // 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;
+ // Kill it while it sleeps!
+ 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;
+
+ // Brains!... You cannot kill
+ case THREAD_STAT_ZOMBIE:
+ Log_Warning("Threads", "Threads_Kill - Thread %p(%i,%s) is undead, you cannot kill it",
+ Thread, Thread->TID, Thread->ThreadName);
SHORTREL( &glThreadListLock );
SHORTREL( &Thread->IsLocked );
- return;
- }
-
- // Ensure that we are not rescheduled
- Thread->Remaining = 0; // Clear Remaining Quantum
- Thread->Quantum = 0; // Clear Quantum to indicate dead thread
+ return ;
- // Update bookkeeping
- giNumActiveThreads --;
- #if SCHEDULER_TYPE == SCHED_LOTTERY
- if( Thread != Proc_GetCurThread() )
- giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
- #endif
+ 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 );
SHORTREL( &Thread->IsLocked ); // TODO: We may not actually be released...
// And, reschedule
- if(Status != -1) {
+ if(isCurThread) {
for( ;; )
HALT();
}
{
SHORTLOCK( &glThreadListLock );
+ if( Thread->Status == THREAD_STAT_ACTIVE ) {
+ tThread *cur = Proc_GetCurThread();
+ Warning("WTF, CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
+ GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName);
+ }
+
// Set state
Thread->Status = THREAD_STAT_ACTIVE;
Thread->CurCPU = -1;
#if SCHEDULER_TYPE == SCHED_LOTTERY
giFreeTickets += caiTICKET_COUNTS[ Thread->Priority ];
# if DEBUG_TRACE_TICKETS
- Log("Threads_AddActive: %p %i (%s) added, new giFreeTickets = %i",
- Thread, Thread->TID, Thread->ThreadName, giFreeTickets);
+ Log("Threads_AddActive: CPU%i %p %i (%s) added, new giFreeTickets = %i",
+ GetCPUNum(), Thread, Thread->TID, Thread->ThreadName, giFreeTickets);
# endif
#endif
// no need to decrement tickets, scheduler did it for us
#if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
- Log("Threads_RemActive: %p %i (%s) removed, giFreeTickets = %i",
- ret, ret->TID, ret->ThreadName, giFreeTickets);
+ Log("Threads_RemActive: CPU%i %p %i (%s) removed, giFreeTickets = %i",
+ GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets);
#endif
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);