X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fthreads.c;h=3ebc4dc6aa3428820b4f1d6e488520608e8d46f8;hb=cd0a4d84497fe89a8680ac0b881007ab6e97f44d;hp=dc79908d10879f3c77feb7e599eb178bb6bb2a59;hpb=9d85201216cb35e1b1e051b1d7cdc38eaa5befa4;p=tpg%2Facess2.git diff --git a/Kernel/threads.c b/Kernel/threads.c index dc79908d..3ebc4dc6 100644 --- a/Kernel/threads.c +++ b/Kernel/threads.c @@ -5,12 +5,14 @@ */ #include #include +#include #include #include // Configuration #define DEBUG_TRACE_TICKETS 0 // Trace ticket counts #define DEBUG_TRACE_STATE 0 // Trace state changes (sleep/wake) +#define SEMAPHORE_DEBUG 0 // --- Schedulers --- #define SCHED_UNDEF 0 @@ -33,6 +35,7 @@ const enum eConfigTypes cCONFIG_TYPES[] = { // === IMPORTS === extern void ArchThreads_Init(void); extern void Proc_CallFaultHandler(tThread *Thread); +extern void Proc_DumpThreadCPUState(tThread *Thread); extern int GetCPUNum(void); // === PROTOTYPES === @@ -58,6 +61,7 @@ void Threads_Sleep(void); void Threads_AddActive(tThread *Thread); tThread *Threads_RemActive(void); #endif +void Threads_ToggleTrace(int TID); void Threads_Fault(int Num); void Threads_SegFault(tVAddr Addr); #if 0 @@ -70,7 +74,6 @@ tGID Threads_GetGID(void); #endif void Threads_Dump(void); void Threads_DumpActive(void); - #if 0 int Mutex_Acquire(tMutex *Mutex); void Mutex_Release(tMutex *Mutex); @@ -81,11 +84,11 @@ void Mutex_Release(tMutex *Mutex); // -- Core Thread -- // Only used for the core kernel tThread gThreadZero = { - Status: THREAD_STAT_ACTIVE, // Status - ThreadName: (char*)"ThreadZero", // Name - Quantum: DEFAULT_QUANTUM, // Default Quantum - Remaining: DEFAULT_QUANTUM, // Current Quantum - Priority: DEFAULT_PRIORITY // Number of tickets + .Status = THREAD_STAT_ACTIVE, // Status + .ThreadName = (char*)"ThreadZero", // Name + .Quantum = DEFAULT_QUANTUM, // Default Quantum + .Remaining = DEFAULT_QUANTUM, // Current Quantum + .Priority = DEFAULT_PRIORITY // Number of tickets }; // -- Processes -- // --- Locks --- @@ -121,6 +124,9 @@ void Threads_Init(void) { ArchThreads_Init(); + Log_Debug("Threads", "Offsets of tThread"); + Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority)); + // Create Initial Task #if SCHEDULER_TYPE == SCHED_RR_PRI gaActiveThreads[gThreadZero.Priority] = &gThreadZero; @@ -183,6 +189,7 @@ void Threads_SetPriority(tThread *Thread, int Pri) if(Thread == NULL) Thread = Proc_GetCurThread(); // Bounds checking // - If < 0, set to lowest priority + // - Minumum priority is actualy a high number, 0 is highest if(Pri < 0) Pri = MIN_PRIORITY; if(Pri > MIN_PRIORITY) Pri = MIN_PRIORITY; @@ -207,7 +214,9 @@ void Threads_SetPriority(tThread *Thread, int Pri) #if SCHEDULER_TYPE == SCHED_LOTTERY giFreeTickets -= caiTICKET_COUNTS[Thread->Priority] - caiTICKET_COUNTS[Pri]; # if DEBUG_TRACE_TICKETS - Log("Threads_SetTickets: new giFreeTickets = %i", giFreeTickets); + Log("Threads_SetTickets: new giFreeTickets = %i [-%i+%i]", + giFreeTickets, + caiTICKET_COUNTS[Thread->Priority], caiTICKET_COUNTS[Pri]); # endif #endif Thread->Priority = Pri; @@ -216,6 +225,12 @@ void Threads_SetPriority(tThread *Thread, int Pri) else Thread->Priority = Pri; #endif + + #if DEBUG_TRACE_STATE + Log("Threads_SetPriority: %p(%i %s) pri set %i", + Thread, Thread->TID, Thread->ThreadName, + Pri); + #endif } /** @@ -232,10 +247,7 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags) // Allocate and duplicate new = malloc(sizeof(tThread)); - if(new == NULL) { - *Err = -ENOMEM; - return NULL; - } + if(new == NULL) { *Err = -ENOMEM; return NULL; } memcpy(new, cur, sizeof(tThread)); new->CurCPU = -1; @@ -247,6 +259,7 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags) // Get Thread ID new->TID = giNextTID++; new->Parent = cur; + new->bInstrTrace = 0; // Clone Name new->ThreadName = strdup(cur->ThreadName); @@ -333,6 +346,7 @@ tThread *Threads_CloneThreadZero(void) // Set State new->Remaining = new->Quantum = cur->Quantum; new->Priority = cur->Priority; + new->bInstrTrace = 0; // Set Signal Handlers new->CurFaultNum = 0; @@ -725,7 +739,7 @@ int Threads_Wake(tThread *Thread) switch(Thread->Status) { case THREAD_STAT_ACTIVE: - Log("Thread_Wake: Waking awake thread (%i)", Thread->TID); + Log("Threads_Wake - Waking awake thread (%i)", Thread->TID); return -EALREADY; case THREAD_STAT_SLEEPING: @@ -741,16 +755,66 @@ int Threads_Wake(tThread *Thread) SHORTREL( &glThreadListLock ); return -EOK; + case THREAD_STAT_SEMAPHORESLEEP: { + tSemaphore *sem; + tThread *th, *prev=NULL; + + sem = Thread->WaitPointer; + + SHORTLOCK( &sem->Protector ); + + // Remove from sleeping queue + for( th = sem->Waiting; th; prev = th, th = th->Next ) + if( th == Thread ) break; + if( th ) + { + if(prev) + prev->Next = Thread->Next; + else + sem->Waiting = Thread->Next; + if(sem->LastWaiting == Thread) + sem->LastWaiting = prev; + } + else + { + prev = NULL; + for( th = sem->Signaling; th; prev = th, th = th->Next ) + if( th == Thread ) break; + if( !th ) { + Log_Warning("Threads", "Thread %p(%i %s) is not on semaphore %p(%s:%s)", + Thread, Thread->TID, Thread->ThreadName, + sem, sem->ModName, sem->Name); + return -EINTERNAL; + } + + if(prev) + prev->Next = Thread->Next; + else + sem->Signaling = Thread->Next; + if(sem->LastSignaling == Thread) + sem->LastSignaling = prev; + } + + SHORTLOCK( &glThreadListLock ); + Threads_AddActive( Thread ); + SHORTREL( &glThreadListLock ); + + #if DEBUG_TRACE_STATE + Log("Threads_Sleep: %p(%i %s) woken from semaphore", Thread, Thread->TID, Thread->ThreadName); + #endif + SHORTREL( &sem->Protector ); + } return -EOK; + case THREAD_STAT_WAITING: - Warning("Thread_Wake - Waiting threads are not currently supported"); + Warning("Threads_Wake - Waiting threads are not currently supported"); return -ENOTIMPL; case THREAD_STAT_DEAD: - Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID); + Warning("Threads_Wake - Attempt to wake dead thread (%i)", Thread->TID); return -ENOTIMPL; default: - Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status); + Warning("Threads_Wake - Unknown process status (%i)\n", Thread->Status); return -EINTERNAL; } } @@ -771,6 +835,13 @@ int Threads_WakeTID(tTID TID) return ret; } +void Threads_ToggleTrace(int TID) +{ + tThread *thread = Threads_GetThread(TID); + if(!thread) return ; + thread->bInstrTrace = !thread->bInstrTrace; +} + /** * \brief Adds a thread to the active queue */ @@ -782,11 +853,13 @@ void Threads_AddActive(tThread *Thread) 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); + SHORTREL( &glThreadListLock ); + return ; } // Set state Thread->Status = THREAD_STAT_ACTIVE; - Thread->CurCPU = -1; +// Thread->CurCPU = -1; // Add to active list #if SCHEDULER_TYPE == SCHED_RR_PRI Thread->Next = gaActiveThreads[Thread->Priority]; @@ -800,11 +873,22 @@ void Threads_AddActive(tThread *Thread) giNumActiveThreads ++; #if SCHEDULER_TYPE == SCHED_LOTTERY - giFreeTickets += caiTICKET_COUNTS[ Thread->Priority ]; - # if DEBUG_TRACE_TICKETS - Log("Threads_AddActive: CPU%i %p %i (%s) added, new giFreeTickets = %i", - GetCPUNum(), Thread, Thread->TID, Thread->ThreadName, giFreeTickets); - # endif + { + int delta; + // Only change the ticket count if the thread is un-scheduled + if(Thread->CurCPU != -1) + delta = 0; + else + delta = caiTICKET_COUNTS[ Thread->Priority ]; + + giFreeTickets += delta; + # if DEBUG_TRACE_TICKETS + Log("CPU%i %p (%i %s) added, new giFreeTickets = %i [+%i]", + GetCPUNum(), Thread, Thread->TID, Thread->ThreadName, + giFreeTickets, delta + ); + # endif + } #endif SHORTREL( &glThreadListLock ); @@ -829,18 +913,20 @@ tThread *Threads_RemActive(void) #endif { SHORTREL( &glThreadListLock ); + Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue", + ret, ret->TID, ret->ThreadName + ); return NULL; } ret->Next = NULL; ret->Remaining = 0; - ret->CurCPU = -1; giNumActiveThreads --; // no need to decrement tickets, scheduler did it for us #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS - Log("Threads_RemActive: CPU%i %p %i (%s) removed, giFreeTickets = %i", + Log("CPU%i %p (%i %s) removed, giFreeTickets = %i [nc]", GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets); #endif @@ -867,8 +953,6 @@ void Threads_Fault(int Num) { tThread *thread = Proc_GetCurThread(); - Log_Log("Threads", "Threads_Fault: thread = %p", thread); - if(!thread) return ; Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler); @@ -975,6 +1059,9 @@ void Threads_DumpActive(void) Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE); Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum); Log(" KStack 0x%x", thread->KernelStack); + if( thread->bInstrTrace ) + Log(" Tracing Enabled"); + Proc_DumpThreadCPUState(thread); } #if SCHEDULER_TYPE == SCHED_RR_PRI @@ -1018,6 +1105,9 @@ void Threads_Dump(void) } Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum); Log(" KStack 0x%x", thread->KernelStack); + if( thread->bInstrTrace ) + Log(" Tracing Enabled"); + Proc_DumpThreadCPUState(thread); } } @@ -1045,6 +1135,7 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) // Clear Delete Queue // - I should probably put this in a worker thread to avoid calling free() in the scheduler // DEFINITELY - free() can deadlock in this case + // I'll do it when it becomes an issue while(gDeleteThreads) { thread = gDeleteThreads->Next; @@ -1065,7 +1156,10 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) } gDeleteThreads = thread; } - + + // Make sure the current (well, old) thread is marked as de-scheduled + if(Last) Last->CurCPU = -1; + // No active threads, just take a nap if(giNumActiveThreads == 0) { SHORTREL( &glThreadListLock ); @@ -1096,14 +1190,15 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) #if SCHEDULER_TYPE == SCHED_LOTTERY giFreeTickets += caiTICKET_COUNTS[ Last->Priority ]; # if DEBUG_TRACE_TICKETS - LogF(" CPU %i released %p (%i %s) into the pool (%i tickets in pool)\n", - CPU, Last, Last->TID, Last->ThreadName, giFreeTickets); + LogF("Log: CPU%i released %p (%i %s) into the pool (%i [+%i] tickets in pool)\n", + CPU, Last, Last->TID, Last->ThreadName, giFreeTickets, + caiTICKET_COUNTS[ Last->Priority ]); # endif #endif } #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS else - LogF(" CPU %i released %p (%i %s)->Status = %i (Released)\n", + LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released,not in pool)\n", CPU, Last, Last->TID, Last->ThreadName, Last->Status); #endif Last->CurCPU = -1; @@ -1162,12 +1257,13 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)", giFreeTickets, number); } - # if DEBUG_TRACE_TICKETS - LogF(" CPU%i giFreeTickets = %i, running %p (%i %s CPU=%i)\n", - CPU, giFreeTickets, thread, thread->TID, thread->ThreadName, thread->CurCPU); - # endif giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ]; + # if DEBUG_TRACE_TICKETS + LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n", + CPU, thread, thread->TID, thread->ThreadName, + giFreeTickets, caiTICKET_COUNTS[ thread->Priority ]); + # endif } // --- @@ -1240,16 +1336,7 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) return thread; } -/** - * \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. - */ +// Acquire mutex (see mutex.h for documentation) int Mutex_Acquire(tMutex *Mutex) { tThread *us = Proc_GetCurThread(); @@ -1278,6 +1365,12 @@ int Mutex_Acquire(tMutex *Mutex) 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; @@ -1309,10 +1402,7 @@ int Mutex_Acquire(tMutex *Mutex) return 0; } -/** - * \brief Release a held mutex - * \param Mutex Mutex to release - */ +// Release a mutex void Mutex_Release(tMutex *Mutex) { SHORTLOCK( &Mutex->Protector ); @@ -1345,10 +1435,7 @@ void Mutex_Release(tMutex *Mutex) #endif } -/** - * \brief Is this mutex locked? - * \param Mutex Mutex pointer - */ +// Check if a mutex is locked int Mutex_IsLocked(tMutex *Mutex) { return Mutex->Owner != NULL; @@ -1359,9 +1446,11 @@ int Mutex_IsLocked(tMutex *Mutex) // 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 @@ -1409,10 +1498,16 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) 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 ); - SHORTREL( &Sem->Protector ); while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield(); - // We're only woken when there's something avaliable + // We're only woken when there's something avaliable (or a signal arrives) us->WaitPointer = NULL; taken = us->RetStatus; @@ -1440,6 +1535,13 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) 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; @@ -1472,8 +1574,12 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) if( Sem->MaxValue && Sem->Value == Sem->MaxValue ) { tThread *us; - SHORTLOCK( &glThreadListLock ); + #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; @@ -1492,6 +1598,12 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) 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(); @@ -1520,12 +1632,13 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) { tThread *toWake = Sem->Waiting; + // Remove thread from list (double ended, so clear LastWaiting if needed) 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 + // 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 @@ -1535,10 +1648,20 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) // 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 );