X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fthreads.c;h=2f8d933179d5a557dd79ced9f44f0177fd844ced;hb=066ea7cb8cd5c873734405d0b713cb330c79ed49;hp=ecddf94552f9bff3a4c9762c4a7501dbcd0a498b;hpb=9c61cf12758c0977ee1dc5791cba638fd3437ba6;p=tpg%2Facess2.git diff --git a/Kernel/threads.c b/Kernel/threads.c index ecddf945..2f8d9331 100644 --- a/Kernel/threads.c +++ b/Kernel/threads.c @@ -7,11 +7,14 @@ #include #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 // Debug semaphores // --- Schedulers --- #define SCHED_UNDEF 0 @@ -19,10 +22,10 @@ #define SCHED_RR_SIM 2 // Single Queue Round Robin #define SCHED_RR_PRI 3 // Multi Queue Round Robin // Set scheduler type -#define SCHEDULER_TYPE SCHED_LOTTERY +#define SCHEDULER_TYPE SCHED_RR_PRI // === CONSTANTS === -#define DEFAULT_QUANTUM 10 +#define DEFAULT_QUANTUM 5 #define DEFAULT_PRIORITY 5 #define MIN_PRIORITY 10 const enum eConfigTypes cCONFIG_TYPES[] = { @@ -32,10 +35,6 @@ 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 === void Threads_Init(void); @@ -125,6 +124,7 @@ void Threads_Init(void) Log_Debug("Threads", "Offsets of tThread"); Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority)); + Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack)); // Create Initial Task #if SCHEDULER_TYPE == SCHED_RR_PRI @@ -233,12 +233,10 @@ void Threads_SetPriority(tThread *Thread, int Pri) } /** - * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags) * \brief Clone the TCB of the current thread - * \param Err Error pointer * \param Flags Flags for something... (What is this for?) */ -tThread *Threads_CloneTCB(Uint *Err, Uint Flags) +tThread *Threads_CloneTCB(Uint Flags) { tThread *cur, *new; int i; @@ -246,7 +244,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) { errno = -ENOMEM; return NULL; } memcpy(new, cur, sizeof(tThread)); new->CurCPU = -1; @@ -309,14 +307,12 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags) } /** - * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags) - * \brief Clone the TCB of the current thread + * \brief Clone the TCB of the kernel thread */ tThread *Threads_CloneThreadZero(void) { - tThread *cur, *new; + tThread *new; int i; - cur = Proc_GetCurThread(); // Allocate and duplicate new = malloc(sizeof(tThread)); @@ -343,28 +339,17 @@ tThread *Threads_CloneThreadZero(void) new->LastMessage = NULL; // Set State - new->Remaining = new->Quantum = cur->Quantum; - new->Priority = cur->Priority; + new->Remaining = new->Quantum = DEFAULT_QUANTUM; + new->Priority = DEFAULT_PRIORITY; new->bInstrTrace = 0; // Set Signal Handlers new->CurFaultNum = 0; - new->FaultHandler = cur->FaultHandler; + new->FaultHandler = 0; for( i = 0; i < NUM_CFG_ENTRIES; i ++ ) { - switch(cCONFIG_TYPES[i]) - { - default: - new->Config[i] = cur->Config[i]; - break; - case CFGT_HEAPSTR: - if(cur->Config[i]) - new->Config[i] = (Uint) strdup( (void*)cur->Config[i] ); - else - new->Config[i] = 0; - break; - } + new->Config[i] = 0; } // Maintain a global list of threads @@ -633,7 +618,7 @@ void Threads_Kill(tThread *Thread, int Status) } break; - // Brains!... You cannot kill + // Brains!... You cannot kill something that is already dead case THREAD_STAT_ZOMBIE: Log_Warning("Threads", "Threads_Kill - Thread %p(%i,%s) is undead, you cannot kill it", Thread, Thread->TID, Thread->ThreadName); @@ -649,28 +634,29 @@ void Threads_Kill(tThread *Thread, int Status) // Save exit status Thread->RetStatus = Status; - + + SHORTREL( &Thread->IsLocked ); + // Don't Zombie if we are being killed because our parent is if(Status == -1) { Thread->Status = THREAD_STAT_DEAD; Threads_AddToDelete( Thread ); + SHORTREL( &glThreadListLock ); } else { Thread->Status = THREAD_STAT_ZOMBIE; + SHORTREL( &glThreadListLock ); // Wake parent Threads_Wake( Thread->Parent ); } 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(isCurThread) { + if(isCurThread) + { for( ;; ) - HALT(); + Proc_Reschedule(); } } @@ -679,10 +665,8 @@ void Threads_Kill(tThread *Thread, int Status) */ void Threads_Yield(void) { - tThread *thread = Proc_GetCurThread(); - thread->Remaining = 0; - //while(thread->Remaining == 0) - HALT(); +// Log("Threads_Yield: by %p", __builtin_return_address(0)); + Proc_Reschedule(); } /** @@ -718,13 +702,16 @@ void Threads_Sleep(void) // Release Spinlock SHORTREL( &glThreadListLock ); - - while(cur->Status != THREAD_STAT_ACTIVE) HALT(); + + while(cur->Status != THREAD_STAT_ACTIVE) { + Proc_Reschedule(); + if( cur->Status != THREAD_STAT_ACTIVE ) + Log("%i - Huh? why am I up? zzzz...", cur->TID); + } } /** - * \fn int Threads_Wake( tThread *Thread ) * \brief Wakes a sleeping/waiting thread up * \param Thread Thread to wake * \return Boolean Failure (Returns ERRNO) @@ -746,14 +733,63 @@ int Threads_Wake(tThread *Thread) // Remove from sleeping queue Threads_int_DelFromQueue(&gSleepingThreads, Thread); + SHORTREL( &glThreadListLock ); Threads_AddActive( Thread ); #if DEBUG_TRACE_STATE Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName); #endif - 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; + } + + Thread->RetStatus = 0; // It didn't get anything + Threads_AddActive( Thread ); + + #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("Threads_Wake - Waiting threads are not currently supported"); return -ENOTIMPL; @@ -800,7 +836,8 @@ void Threads_AddActive(tThread *Thread) 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", + Log_Warning("Threads", "WTF, %p CPU%i %p (%i %s) is adding %p (%i %s) when it is active", + __builtin_return_address(0), GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName); SHORTREL( &glThreadListLock ); return ; @@ -808,14 +845,25 @@ void Threads_AddActive(tThread *Thread) // Set state Thread->Status = THREAD_STAT_ACTIVE; +// Thread->CurCPU = -1; // Add to active list - #if SCHEDULER_TYPE == SCHED_RR_PRI - Thread->Next = gaActiveThreads[Thread->Priority]; - gaActiveThreads[Thread->Priority] = Thread; - #else - Thread->Next = gActiveThreads; - gActiveThreads = Thread; - #endif + { + tThread *tmp, *prev = NULL; + #if SCHEDULER_TYPE == SCHED_RR_PRI + for( tmp = gaActiveThreads[Thread->Priority]; tmp; prev = tmp, tmp = tmp->Next ); + if(prev) + prev->Next = Thread; + else + gaActiveThreads[Thread->Priority] = Thread; + #else + for( tmp = gActiveThreads; tmp; prev = tmp, tmp = tmp->Next ); + if(prev) + prev->Next = Thread; + else + gActiveThreads = Thread; + #endif + Thread->Next = NULL; + } // Update bookkeeping giNumActiveThreads ++; @@ -844,14 +892,17 @@ void Threads_AddActive(tThread *Thread) /** * \brief Removes the current thread from the active queue - * \warning This should ONLY be called with task switches disabled + * \warning This should ONLY be called with the lock held * \return Current thread pointer */ tThread *Threads_RemActive(void) { tThread *ret = Proc_GetCurThread(); - - SHORTLOCK( &glThreadListLock ); + + if( !IS_LOCKED(&glThreadListLock) ) { + Log_KernelPanic("Threads", "Threads_RemActive called without lock held"); + return NULL; + } // Delete from active queue #if SCHEDULER_TYPE == SCHED_RR_PRI @@ -861,6 +912,9 @@ 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; } @@ -875,8 +929,6 @@ tThread *Threads_RemActive(void) GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets); #endif - SHORTREL( &glThreadListLock ); - return ret; } @@ -898,8 +950,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); @@ -918,6 +968,7 @@ void Threads_Fault(int Num) // Double Fault? Oh, F**k if(thread->CurFaultNum != 0) { + Log_Warning("Threads", "Threads_Fault: Double fault on %i", thread->TID); Threads_Kill(thread, -1); // For now, just kill HALT(); } @@ -933,7 +984,10 @@ void Threads_Fault(int Num) */ void Threads_SegFault(tVAddr Addr) { - Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr); + tThread *cur = Proc_GetCurThread(); + cur->bInstrTrace = 0; + Log_Warning("Threads", "Thread #%i committed a segfault at address %p", cur->TID, Addr); + MM_DumpTables(0, USER_MAX); Threads_Fault( 1 ); //Threads_Exit( 0, -1 ); } @@ -1075,13 +1129,13 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) if( gaThreads_NoTaskSwitch[CPU] ) return Last; - // Lock thread list SHORTLOCK( &glThreadListLock ); // 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; @@ -1102,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 ); @@ -1223,7 +1280,7 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) } // If we fall onto the same queue again, special handling is // needed - if( i == Last->Priority ) { + if( Last && Last->Status == THREAD_STAT_ACTIVE && i == Last->Priority ) { tThread *savedThread = thread; // Find the next unscheduled thread in the list @@ -1244,6 +1301,9 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) SHORTREL(&glThreadListLock); return NULL; } + if( thread->Status != THREAD_STAT_ACTIVE ) { + LogF("Oops, Thread %i (%s) is not active\n", thread->TID, thread->ThreadName); + } } #elif SCHEDULER_TYPE == SCHED_RR_SIM { @@ -1273,6 +1333,7 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) // Make the new thread non-schedulable thread->CurCPU = CPU; + thread->Remaining = thread->Quantum; SHORTREL( &glThreadListLock ); @@ -1417,7 +1478,6 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) else taken = Sem->Value; Sem->Value -= taken; - SHORTREL( &Sem->Protector ); } else { @@ -1441,16 +1501,25 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) Sem->LastWaiting = us; } - #if DEBUG_TRACE_STATE + #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( &glThreadListLock ); - SHORTREL( &Sem->Protector ); - while(us->Status == THREAD_STAT_SEMAPHORESLEEP) Threads_Yield(); - // We're only woken when there's something avaliable + 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; @@ -1479,7 +1548,7 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) Sem->Value -= given; - #if DEBUG_TRACE_STATE + #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); @@ -1496,6 +1565,11 @@ int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) } 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; } @@ -1541,7 +1615,7 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) Sem->LastSignaling = us; } - #if DEBUG_TRACE_STATE + #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); @@ -1593,17 +1667,19 @@ int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) if(toWake->bInstrTrace) Log("%s(%i) given %i from %p", toWake->ThreadName, toWake->TID, given, Sem); - #if DEBUG_TRACE_STATE + #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 ); +// SHORTLOCK( &glThreadListLock ); if( toWake->Status != THREAD_STAT_ACTIVE ) Threads_AddActive(toWake); - SHORTREL( &glThreadListLock ); + else + Warning("Thread %p (%i %s) is already awake", toWake, toWake->TID, toWake->ThreadName); +// SHORTREL( &glThreadListLock ); } SHORTREL( &Sem->Protector );