From: John Hodge Date: Mon, 23 Aug 2010 15:40:09 +0000 (+0800) Subject: Unborking some threading code X-Git-Tag: rel0.06~47 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=15999a03acd4083fb2618c92bebbc557813c5084;p=tpg%2Facess2.git Unborking some threading code - As a side effect, There are FAR less calls to Threads_Yield around, most have been replaced with Threads_Sleep and a wake on message. - Also fixed a minor logging bug in PCI --- diff --git a/.gitignore b/.gitignore index a87df3d2..1edda841 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ *.dsm *.dmp *.kmd.* -Map.txt +Map*.txt +bochs*.txt +serial.txt diff --git a/Kernel/arch/x86/include/arch.h b/Kernel/arch/x86/include/arch.h index ede3bf05..0fec144e 100644 --- a/Kernel/arch/x86/include/arch.h +++ b/Kernel/arch/x86/include/arch.h @@ -57,29 +57,32 @@ static inline int IS_LOCKED(struct sShortSpinlock *Lock) { */ static inline void SHORTLOCK(struct sShortSpinlock *Lock) { int v = 1; + int IF; + // int val = GetCPUNum() + 1; - // Save interrupt state - __ASM__ ("pushf;\n\tpop %%eax" : "=a"(Lock->IF)); - Lock->IF &= 0x200; - - // Stop interrupts - __ASM__ ("cli"); + // Save interrupt state and clear interrupts + __ASM__ ("pushf;\n\tcli;\n\tpop %%eax" : "=a"(IF)); + IF &= 0x200; // Wait for another CPU to release while(v) - __ASM__("xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(&Lock->Lock)); + __ASM__("xchgl %%ecx, (%%edi)":"=c"(v):"a"(1),"D"(&Lock->Lock)); + + Lock->IF = IF; } /** * \brief Release a short lock * \param Lock Lock pointer */ static inline void SHORTREL(struct sShortSpinlock *Lock) { - Lock->Lock = 0; - #if 0 // Which is faster?, meh the test is simpler - __ASM__ ("pushf;\n\tor %0, (%%esp);\n\tpopf" : : "a"(Lock->IF)); - #else - if(Lock->IF) __ASM__ ("sti"); - #endif + // Lock->IF can change anytime once Lock->Lock is zeroed + if(Lock->IF) { + Lock->Lock = 0; + __ASM__ ("sti"); + } + else { + Lock->Lock = 0; + } } // === MACROS === diff --git a/Kernel/arch/x86/mm_phys.c b/Kernel/arch/x86/mm_phys.c index cb4f9e0b..3abe4133 100644 --- a/Kernel/arch/x86/mm_phys.c +++ b/Kernel/arch/x86/mm_phys.c @@ -7,7 +7,8 @@ #include #include -#define USE_STACK 1 +//#define USE_STACK 1 +#define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys #define REFERENCE_BASE 0xE0400000 @@ -143,6 +144,7 @@ tPAddr MM_AllocPhys(void) indx -= 1024; continue; } + if( gaPageBitmap[indx>>5] == -1 ) { indx -= 32; continue; @@ -174,11 +176,23 @@ tPAddr MM_AllocPhys(void) indx = (a << 10) | (b << 5) | c; #endif + if( indx < 0 ) { + Mutex_Release( &glPhysAlloc ); + Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p)", __builtin_return_address(0)); + LEAVE('i', 0); + return 0; + } + + if( indx > 0xFFFFF ) { + Panic("The fuck? Too many pages! (indx = 0x%x)", indx); + } + // Mark page used if(gaPageReferences) gaPageReferences[ indx ] = 1; gaPageBitmap[ indx>>5 ] |= 1 << (indx&31); + giPhysAlloc ++; // Get address ret = indx << 12; @@ -192,7 +206,9 @@ tPAddr MM_AllocPhys(void) Mutex_Release( &glPhysAlloc ); LEAVE('X', ret); - //Log("MM_AllocPhys: RETURN 0x%x", ret); + #if TRACE_ALLOCS + Log_Debug("PMem", "MM_AllocPhys: RETURN 0x%llx (%i free)", ret, giPageCount-giPhysAlloc); + #endif return ret; } @@ -309,6 +325,7 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits) gaPageReferences[idx*32+sidx] = 1; gaPageBitmap[ idx ] |= 1 << sidx; sidx ++; + giPhysAlloc ++; if(sidx == 32) { sidx = 0; idx ++; } } @@ -322,6 +339,10 @@ tPAddr MM_AllocPhysRange(int Pages, int MaxBits) Mutex_Release( &glPhysAlloc ); LEAVE('X', ret); + #if TRACE_ALLOCS + Log_Debug("PMem", "MM_AllocPhysRange: RETURN 0x%llx-0x%llx (%i free)", + ret, ret + (1<> 10 ] &= ~(1 << ((PAddr >> 5)&31)); diff --git a/Kernel/arch/x86/proc.asm b/Kernel/arch/x86/proc.asm index 9dc7f08a..80cc3cbb 100644 --- a/Kernel/arch/x86/proc.asm +++ b/Kernel/arch/x86/proc.asm @@ -205,7 +205,7 @@ Proc_ReturnToUser: ; Get and alter User SP mov ecx, edx - mov edx, [ebx+60] ; Get Signal Number from TCB + mov edx, [ebx+68] ; Get Signal Number from TCB (TODO: Get this from parameters) mov [ecx+4], edx ; Parameter (Signal/Error Number) mov [ecx], DWORD User_Syscall_RetAndExit ; Return Address diff --git a/Kernel/arch/x86_64/include/arch.h b/Kernel/arch/x86_64/include/arch.h index d4192341..6b75a7df 100644 --- a/Kernel/arch/x86_64/include/arch.h +++ b/Kernel/arch/x86_64/include/arch.h @@ -35,17 +35,17 @@ typedef Uint64 tVAddr; typedef Uint64 size_t; -typedef volatile int tSpinlock; -#define IS_LOCKED(lockptr) (!!(*(tSpinlock*)lockptr)) -#define _LOCK(lockptr,action) do {int v=1;\ - while(v)\ - __asm__ __volatile__("lock xchgl %0, (%2)":"=r"(v):"r"(1),"r"(lockptr));\ - if(v) action;\ - }while(0) -#define TIGHTLOCK(lockptr) _LOCK(lockptr, __asm__ __volatile__ ("hlt")); -#define LOCK(lockptr) _LOCK(lockptr, Threads_Yield()); -#define RELEASE(lockptr) __asm__ __volatile__("lock andl $0, (%0)"::"r"(lockptr)); -#define HALT() __asm__ __volatile__ ("hlt") +#define __ASM__ __asm__ __volatile__ + +// === MACROS === +/** + * \brief Halt the CPU + */ +#define HALT() __asm__ __volatile__ ("hlt") +/** + * \brief Fire a magic breakpoint (bochs) + */ +#define MAGIC_BREAK() __asm__ __volatile__ ("xchg %bx, %bx") // Systemcall Registers // TODO: Fix this structure @@ -71,5 +71,57 @@ typedef struct sSyscallRegs Uint Resvd5[1]; // SS } tSyscallRegs; +/** + * \brief Short Spinlock structure + */ +struct sShortSpinlock { + volatile int Lock; //!< Lock value + int IF; //!< Interrupt state on call to SHORTLOCK +}; +/** + * \brief Determine if a short spinlock is locked + * \param Lock Lock pointer + */ +static inline int IS_LOCKED(struct sShortSpinlock *Lock) { + return !!Lock->Lock; +} +/** + * \brief Acquire a Short Spinlock + * \param Lock Lock pointer + * + * This type of mutex should only be used for very short sections of code, + * or in places where a Mutex_* would be overkill, such as appending + * an element to linked list (usually two assignement lines in C) + * + * \note This type of lock halts interrupts, so ensure that no timing + * functions are called while it is held. + */ +static inline void SHORTLOCK(struct sShortSpinlock *Lock) { + int v = 1; + + // Save interrupt state + __ASM__ ("pushf;\n\tpop %%rax" : "=a"(Lock->IF)); + Lock->IF &= 0x200; + + // Stop interrupts + __ASM__ ("cli"); + + // Wait for another CPU to release + while(v) + __ASM__("xchgl %%eax, (%%rdi)":"=a"(v):"a"(1),"D"(&Lock->Lock)); +} +/** + * \brief Release a short lock + * \param Lock Lock pointer + */ +static inline void SHORTREL(struct sShortSpinlock *Lock) { + Lock->Lock = 0; + #if 0 // Which is faster?, meh the test is simpler + __ASM__ ("pushf;\n\tor %0, (%%rsp);\n\tpopf" : : "a"(Lock->IF)); + #else + if(Lock->IF) __ASM__ ("sti"); + #endif +} + #endif diff --git a/Kernel/arch/x86_64/include/mm_virt.h b/Kernel/arch/x86_64/include/mm_virt.h index ca508556..867aa3b0 100644 --- a/Kernel/arch/x86_64/include/mm_virt.h +++ b/Kernel/arch/x86_64/include/mm_virt.h @@ -37,7 +37,7 @@ * FE00 00000000 - FE80 00000000 39 512 GiB Fractal Mapping (PML4 508) * FE80 00000000 - FF00 00000000 39 512 GiB Temp Fractal Mapping * ---- GAP ---- 512 GiB -- UNUSED -- - * FF80 00000000 - FF80 80000000 39 2 GiB Local APIC + * FF80 00000000 - FF80 80000000 31 2 GiB Local APIC * ---- GAP ---- * FFFF 00000000 - FFFF 80000000 31 2 GiB User Code * FFFF 80000000 - FFFF FFFFFFFF 31 2 GiB Identity Map diff --git a/Kernel/arch/x86_64/mm_phys.c b/Kernel/arch/x86_64/mm_phys.c index 55fc68aa..c67b9052 100644 --- a/Kernel/arch/x86_64/mm_phys.c +++ b/Kernel/arch/x86_64/mm_phys.c @@ -31,7 +31,7 @@ void MM_DerefPhys(tPAddr PAddr); int MM_int_GetRangeID( tPAddr Addr ); // === GLOBALS === -tSpinlock glPhysicalPages; +tMutex glPhysicalPages; Uint64 *gaSuperBitmap = (void*)MM_PAGE_SUPBMP; // 1 bit = 64 Pages, 16 MiB Per Word Uint64 *gaMainBitmap = (void*)MM_PAGE_BITMAP; // 1 bit = 1 Page, 256 KiB per Word Uint64 *gaMultiBitmap = (void*)MM_PAGE_DBLBMP; // Each bit means that the page is being used multiple times @@ -328,7 +328,7 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) LOG("rangeID = %i", rangeID); - LOCK(&glPhysicalPages); + Mutex_Acquire(&glPhysicalPages); // Check if the range actually has any free pages while(giPhysRangeFree[rangeID] == 0 && rangeID) @@ -338,7 +338,7 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) // What the? Oh, man. No free pages if(giPhysRangeFree[rangeID] == 0) { - RELEASE(&glPhysicalPages); + Mutex_Release(&glPhysicalPages); // TODO: Page out // ATM. Just Warning Warning(" MM_AllocPhysRange: Out of free pages"); @@ -406,7 +406,7 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) nFree = 1; addr = giPhysRangeLast[ rangeID ]; // TODO - RELEASE(&glPhysicalPages); + Mutex_Release(&glPhysicalPages); // TODO: Page out // ATM. Just Warning Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Num); @@ -442,7 +442,7 @@ tPAddr MM_AllocPhysRange(int Num, int Bits) gaSuperBitmap[addr>>12] |= 1LL << ((addr >> 6) & 63); } - RELEASE(&glPhysicalPages); + Mutex_Release(&glPhysicalPages); LEAVE('x', ret << 12); return ret << 12; } diff --git a/Kernel/arch/x86_64/proc.c b/Kernel/arch/x86_64/proc.c index 81b8eeb8..c5c0c18e 100644 --- a/Kernel/arch/x86_64/proc.c +++ b/Kernel/arch/x86_64/proc.c @@ -36,7 +36,7 @@ extern void APStartup(void); // 16-bit AP startup code extern Uint GetRIP(void); // start.asm extern Uint64 gInitialPML4[512]; // start.asm extern char gInitialKernelStack[]; -extern tSpinlock glThreadListLock; +extern tShortSpinlock glThreadListLock; extern int giNumCPUs; extern int giNextTID; extern int giTotalTickets; diff --git a/Kernel/arch/x86_64/vm8086.c b/Kernel/arch/x86_64/vm8086.c index 68728c1c..1459c73e 100644 --- a/Kernel/arch/x86_64/vm8086.c +++ b/Kernel/arch/x86_64/vm8086.c @@ -16,7 +16,7 @@ void VM8086_Free(tVM8086 *State); // === GLOBALS === MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL); -tSpinlock glVM8086_Process; +tMutex glVM8086_Process; tPID gVM8086_WorkerPID; tTID gVM8086_CallingThread; tVM8086 volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions diff --git a/Kernel/drv/pci.c b/Kernel/drv/pci.c index b4881d3b..ec96d866 100644 --- a/Kernel/drv/pci.c +++ b/Kernel/drv/pci.c @@ -116,7 +116,7 @@ int PCI_Install(char **Arguments) } gPCI_Devices = tmpPtr; - Log_Log("PCI", "%i devices, filling structure"); + Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount); // Reset counts giPCI_DeviceCount = 0; diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index da82d674..c2f06854 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -39,7 +39,6 @@ enum eVT_InModes { typedef struct { int Mode; //!< Current Mode (see ::eTplTerminal_Modes) int Flags; //!< Flags (see VT_FLAG_*) - short NewWidth; //!< Un-applied dimensions (Width) short NewHeight; //!< Un-applied dimensions (Height) @@ -52,6 +51,8 @@ typedef struct { int WritePos; //!< Write Buffer Offset (Text Only) Uint32 CurColour; //!< Current Text Colour + tMutex ReadingLock; //!< Lock the VTerm when a process is reading from it + tTID ReadingThread; //!< Owner of the lock int InputRead; //!< Input buffer read position int InputWrite; //!< Input buffer write position char InputBuffer[MAX_INPUT_CHARS8]; @@ -402,6 +403,9 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) int pos = 0; tVTerm *term = &gVT_Terminals[ Node->Inode ]; + Mutex_Acquire( &term->ReadingLock ); + term->ReadingThread = Threads_GetTID(); + // Check current mode switch(term->Mode) { @@ -409,7 +413,8 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) case TERM_MODE_TEXT: while(pos < Length) { - while(term->InputRead == term->InputWrite) Threads_Yield(); + //TODO: Sleep instead + while(term->InputRead == term->InputWrite) Threads_Sleep(); ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead]; pos ++; @@ -423,7 +428,7 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) default: while(pos < Length) { - while(term->InputRead == term->InputWrite) Threads_Yield(); + while(term->InputRead == term->InputWrite) Threads_Sleep(); ((Uint32*)Buffer)[pos] = ((Uint32*)term->InputBuffer)[term->InputRead]; pos ++; term->InputRead ++; @@ -431,6 +436,10 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) } break; } + + term->ReadingThread = -1; + Mutex_Release( &term->ReadingLock ); + return 0; } @@ -818,6 +827,11 @@ void VT_KBCallBack(Uint32 Codepoint) term->InputRead %= MAX_INPUT_CHARS32; } } + + // Wake up the thread waiting on us + if( term->ReadingThread >= 0 ) { + Threads_WakeTID(term->ReadingThread); + } } /** @@ -868,17 +882,6 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) } while(c == ';'); } - /* - // Get string (what does this do?) - if(c == '"') { - c = Buffer[j++]; - while(c != '"') - c = Buffer[j++]; - } - */ - - //Log_Debug("VTerm", "argc = %i", argc); - // Get Command if( ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { diff --git a/Kernel/include/threads.h b/Kernel/include/threads.h index 6c292307..3b6e9c60 100644 --- a/Kernel/include/threads.h +++ b/Kernel/include/threads.h @@ -18,14 +18,20 @@ typedef struct sMessage typedef struct sThread { // --- threads.c's - struct sThread *Next; //!< Next thread in list + /** + * \brief Next thread in current list + * \note Required to be first for linked list hacks to work + */ + struct sThread *Next; + struct sThread *GlobalNext; //!< Next thread in global list + struct sThread *GlobalPrev; //!< Previous thread in global list tShortSpinlock IsLocked; //!< Thread's spinlock volatile int Status; //!< Thread Status int RetStatus; //!< Return Status Uint TID; //!< Thread ID Uint TGID; //!< Thread Group (Process) - Uint PTID; //!< Parent Thread ID + struct sThread *Parent; //!< Parent Thread Uint UID, GID; //!< User and Group char *ThreadName; //!< Name of thread @@ -56,12 +62,13 @@ typedef struct sThread enum { - THREAD_STAT_NULL, - THREAD_STAT_ACTIVE, - THREAD_STAT_SLEEPING, - THREAD_STAT_WAITING, - THREAD_STAT_ZOMBIE, - THREAD_STAT_DEAD + THREAD_STAT_NULL, // Invalid process + THREAD_STAT_ACTIVE, // Running and schedulable process + THREAD_STAT_SLEEPING, // Message Sleep + THREAD_STAT_OFFSLEEP, // Mutex Sleep (or waiting on a thread) + THREAD_STAT_WAITING, // ??? + THREAD_STAT_ZOMBIE, // Died, just not removed + THREAD_STAT_DEAD // Why do we care about these??? }; enum eFaultNumbers diff --git a/Kernel/threads.c b/Kernel/threads.c index 99a9add6..5d8e4013 100644 --- a/Kernel/threads.c +++ b/Kernel/threads.c @@ -7,7 +7,8 @@ #include #include -#define DEBUG_TRACE_TICKETS 0 +#define DEBUG_TRACE_TICKETS 0 // Trace ticket counts +#define DEBUG_TRACE_STATE 0 // Trace state changes (sleep/wake) // === CONSTANTS === #define DEFAULT_QUANTUM 10 @@ -42,6 +43,7 @@ void Threads_Yield(void); void Threads_Sleep(void); int Threads_Wake(tThread *Thread); void Threads_AddActive(tThread *Thread); +tThread *Threads_RemActive(void); int Threads_GetPID(void); int Threads_GetTID(void); tUID Threads_GetUID(void); @@ -68,10 +70,10 @@ tThread gThreadZero = { tShortSpinlock glThreadListLock; ///\note NEVER use a heap function while locked // --- Current State --- volatile int giNumActiveThreads = 0; -//volatile int giTotalTickets = 0; volatile int giFreeTickets = 0; volatile Uint giNextTID = 1; // --- Thread Lists --- +tThread *gAllThreads = NULL; // All allocated threads tThread *gActiveThreads = NULL; // Currently Running Threads tThread *gSleepingThreads = NULL; // Sleeping Threads tThread *gDeleteThreads = NULL; // Threads to delete @@ -169,7 +171,7 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags) // Get Thread ID new->TID = giNextTID++; - new->PTID = cur->TID; + new->Parent = cur; // Clone Name new->ThreadName = strdup(cur->ThreadName); @@ -208,6 +210,13 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags) } } + // Maintain a global list of threads + SHORTLOCK( &glThreadListLock ); + new->GlobalPrev = NULL; // Protect against bugs + new->GlobalNext = gAllThreads; + gAllThreads = new; + SHORTREL( &glThreadListLock ); + return new; } @@ -225,25 +234,27 @@ Uint *Threads_GetCfgPtr(int Id) } /** - * \fn void Threads_WaitTID(int TID, int *status) + * \fn tTID Threads_WaitTID(int TID, int *status) * \brief Wait for a task to change state + * \return TID of child that changed state */ int Threads_WaitTID(int TID, int *status) { // Any Child if(TID == -1) { - + Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child"); return -1; } // Any peer/child thread if(TID == 0) { - + Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling"); return -1; } // TGID = abs(TID) if(TID < -1) { + Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID"); return -1; } @@ -254,17 +265,25 @@ int Threads_WaitTID(int TID, int *status) int ret; if(initStatus != THREAD_STAT_ZOMBIE) { - while(t->Status == initStatus) { - Threads_Yield(); + // TODO: Handle child also being suspended if wanted + while(t->Status != THREAD_STAT_ZOMBIE) { + Threads_Sleep(); + Log_Debug("Threads", "%i waiting for %i, t->Status = %i", + Threads_GetTID(), t->TID, t->Status); } } + Log_Debug("Threads", "%i waiting for %i, t->Status = %i", + Threads_GetTID(), t->TID, t->Status); ret = t->RetStatus; switch(t->Status) { case THREAD_STAT_ZOMBIE: + // Kill the thread t->Status = THREAD_STAT_DEAD; + // TODO: Child return value? if(status) *status = 0; + // add to delete queue Threads_AddToDelete( t ); break; default: @@ -286,19 +305,10 @@ tThread *Threads_GetThread(Uint TID) { tThread *thread; - // Search Active List - for(thread = gActiveThreads; - thread; - thread = thread->Next) - { - if(thread->TID == TID) - return thread; - } - - // Search Sleeping List - for(thread = gSleepingThreads; + // Search global list + for(thread = gAllThreads; thread; - thread = thread->Next) + thread = thread->GlobalNext) { if(thread->TID == TID) return thread; @@ -398,7 +408,7 @@ void Threads_Kill(tThread *Thread, int Status) prev = Threads_int_GetPrev( &gActiveThreads, Thread ); if(!prev) { Warning("Proc_Exit - Current thread is not on the active queue"); - Thread->IsLocked.Lock = 0; // We can't use SHORTREL as that starts IRQs again + SHORTREL( &Thread->IsLocked ); SHORTREL( &glThreadListLock ); return; } @@ -418,9 +428,8 @@ void Threads_Kill(tThread *Thread, int Status) giNumActiveThreads --; if( Thread != Proc_GetCurThread() ) giFreeTickets -= Thread->NumTickets; - //Log("Threads_Kill: giFreeTickets = %i", giFreeTickets); - // Mark thread as a zombie + // Save exit status Thread->RetStatus = Status; // Don't Zombie if we are being killed as part of a tree @@ -430,14 +439,16 @@ void Threads_Kill(tThread *Thread, int Status) Threads_AddToDelete( Thread ); } else { Thread->Status = THREAD_STAT_ZOMBIE; + // Wake parent + Threads_Wake( Thread->Parent ); } + Log("Thread %i went *hurk* (%i)", Thread->TID, Thread->Status); + // Release spinlocks - Thread->IsLocked.Lock = 0; // Released first so that it IS released + SHORTREL( &Thread->IsLocked ); SHORTREL( &glThreadListLock ); - //Log("Thread %i went *hurk*", Thread->TID); - if(Status != -1) HALT(); } @@ -458,45 +469,32 @@ void Threads_Yield(void) void Threads_Sleep(void) { tThread *cur = Proc_GetCurThread(); - tThread *thread; //Log_Log("Threads", "%i going to sleep", cur->TID); // Acquire Spinlock SHORTLOCK( &glThreadListLock ); - // Get thread before current thread - thread = Threads_int_GetPrev( &gActiveThreads, cur ); - if(!thread) { - Warning("Threads_Sleep - Current thread is not on the active queue"); - Threads_Dump(); - SHORTREL( &glThreadListLock ); - return; - } - // Don't sleep if there is a message waiting if( cur->Messages ) { SHORTREL( &glThreadListLock ); return; } - // Unset remaining timeslices (force a task switch on timer fire) - cur->Remaining = 0; - - // Remove from active list - thread->Next = cur->Next; + // Remove us from running queue + Threads_RemActive(); // Add to Sleeping List (at the top) cur->Next = gSleepingThreads; gSleepingThreads = cur; - // Reduce the active count & ticket count - giNumActiveThreads --; - // - No need to alter giFreeTickets (we're being executed) - // Mark thread as sleeping cur->Status = THREAD_STAT_SLEEPING; + #if DEBUG_TRACE_STATE + Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName); + #endif + // Release Spinlock SHORTREL( &glThreadListLock ); @@ -509,6 +507,7 @@ void Threads_Sleep(void) * \brief Wakes a sleeping/waiting thread up * \param Thread Thread to wake * \return Boolean Failure (Returns ERRNO) + * \note Should be called with the scheduler lock held */ int Threads_Wake(tThread *Thread) { @@ -522,30 +521,35 @@ int Threads_Wake(tThread *Thread) case THREAD_STAT_ACTIVE: Log("Thread_Wake: Waking awake thread (%i)", Thread->TID); return -EALREADY; + case THREAD_STAT_SLEEPING: // TODO: Comment better - //Log_Log("Threads", "Waking %i (%p) from sleeping (CPU=%i)", - // Thread->TID, Thread, Thread->CurCPU); - SHORTLOCK( &glThreadListLock ); + // Remove from sleeping queue prev = Threads_int_GetPrev(&gSleepingThreads, Thread); - prev->Next = Thread->Next; // Remove from sleeping queue - Thread->Next = gActiveThreads; // Add to active queue + prev->Next = Thread->Next; + // Add to active queue + Thread->Next = gActiveThreads; gActiveThreads = Thread; + // Update bookkeeping giNumActiveThreads ++; - // Thread can't be the current, so no need to check - Thread->CurCPU = -1; giFreeTickets += Thread->NumTickets; #if DEBUG_TRACE_TICKETS - Log("Threads_Wake: giFreeTickets = %i", giFreeTickets); + Log("Threads_Wake: new giFreeTickets = %i", giFreeTickets); #endif + Thread->CurCPU = -1; Thread->Status = THREAD_STAT_ACTIVE; - SHORTREL( &glThreadListLock ); + #if DEBUG_TRACE_STATE + Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName); + #endif return -EOK; + case THREAD_STAT_WAITING: Warning("Thread_Wake - Waiting threads are not currently supported"); return -ENOTIMPL; + case THREAD_STAT_DEAD: Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID); return -ENOTIMPL; + default: Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status); return -EINTERNAL; @@ -560,9 +564,13 @@ int Threads_Wake(tThread *Thread) int Threads_WakeTID(tTID TID) { tThread *thread = Threads_GetThread(TID); + int ret; if(!thread) return -ENOENT; - return Threads_Wake( thread ); + SHORTLOCK( &glThreadListLock ); + ret = Threads_Wake( thread ); + SHORTREL( &glThreadListLock ); + return ret; } /** @@ -572,24 +580,42 @@ int Threads_WakeTID(tTID TID) void Threads_AddActive(tThread *Thread) { SHORTLOCK( &glThreadListLock ); + // Add to active list Thread->Next = gActiveThreads; gActiveThreads = Thread; + // Update bookkeeping giNumActiveThreads ++; - // Thread can't be the current, so no need to check giFreeTickets += Thread->NumTickets; #if DEBUG_TRACE_TICKETS - Log("Threads_AddActive: giFreeTickets = %i", giFreeTickets); + Log("Threads_AddActive: new giFreeTickets = %i", giFreeTickets); #endif SHORTREL( &glThreadListLock ); } +/** + * \brief Removes the current thread from the active queue + * \warning This should ONLY be called with task switches disabled + * \return Current thread pointer + */ +tThread *Threads_RemActive(void) +{ + tThread *ret = Proc_GetCurThread(); + tThread *prev = Threads_int_GetPrev(&gActiveThreads, ret); + if(!prev) return NULL; + ret->Remaining = 0; + ret->CurCPU = -1; + prev->Next = ret->Next; + giNumActiveThreads --; + return ret; +} + /** * \fn void Threads_SetFaultHandler(Uint Handler) * \brief Sets the signal handler for a signal */ void Threads_SetFaultHandler(Uint Handler) { - Log_Log("Threads", "Threads_SetFaultHandler: Handler = %p", Handler); + //Log_Debug("Threads", "Threads_SetFaultHandler: Handler = %p", Handler); Proc_GetCurThread()->FaultHandler = Handler; } @@ -655,7 +681,7 @@ int Threads_SetUID(Uint *Errno, tUID ID) *Errno = -EACCES; return -1; } - Log("Threads_SetUID - Setting User ID to %i", ID); + Log_Debug("Threads", "TID %i's UID set to %i", t->TID, ID); t->UID = ID; return 0; } @@ -667,7 +693,7 @@ int Threads_SetGID(Uint *Errno, tGID ID) *Errno = -EACCES; return -1; } - Log("Threads_SetGID - Setting Group ID to %i", ID); + Log_Debug("Threads", "TID %i's GID set to %i", t->TID, ID); t->GID = ID; return 0; } @@ -685,14 +711,17 @@ void Threads_Dump(void) { Log(" %i (%i) - %s (CPU %i)", thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU); + Log(" State: %i", thread->Status); Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum); Log(" KStack 0x%x", thread->KernelStack); } - Log("Sleeping Threads:"); - for(thread=gSleepingThreads;thread;thread=thread->Next) + + Log("All Threads:"); + for(thread=gAllThreads;thread;thread=thread->GlobalNext) { - Log(" %i (%i) - %s", - thread->TID, thread->TGID, thread->ThreadName); + Log(" %i (%i) - %s (CPU %i)", + thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU); + Log(" State: %i", thread->Status); Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum); Log(" KStack 0x%x", thread->KernelStack); } @@ -708,22 +737,26 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) { tThread *thread; int ticket; - int number; + int number; - // TODO: Enable the code to tell if the current CPU has the lock or - // another does. - - // Check if the thread list is locked by other code - // - If so, don't switch (give it a chance to complete) - if( IS_LOCKED(&glThreadListLock) ) - return Last; + // Lock thread list + SHORTLOCK( &glThreadListLock ); // Clear Delete Queue while(gDeleteThreads) { thread = gDeleteThreads->Next; if( IS_LOCKED(&gDeleteThreads->IsLocked) ) { // Only free if structure is unused - gDeleteThreads->Status = THREAD_STAT_NULL; + // Set to dead + gDeleteThreads->Status = THREAD_STAT_DEAD; + // Free name + if( IsHeap(gDeleteThreads->ThreadName) ) + free(gDeleteThreads->ThreadName); + // Remove from global list + if( gDeleteThreads == gAllThreads ) + gAllThreads = gDeleteThreads->GlobalNext; + else + gDeleteThreads->GlobalPrev->GlobalNext = gDeleteThreads->GlobalNext; free( gDeleteThreads ); } gDeleteThreads = thread; @@ -731,19 +764,13 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) // No active threads, just take a nap if(giNumActiveThreads == 0) { + SHORTREL( &glThreadListLock ); #if DEBUG_TRACE_TICKETS Log("No active threads"); #endif return NULL; } - // Lock thread list - // - HLT lock (Used because only another CPU can obtain the lock, - // but it has a potentially long lock period) - // - Well, this CPU can obtain the lock, but that is aliveviated by - // the above. - SHORTLOCK( &glThreadListLock ); - // Special case: 1 thread if(giNumActiveThreads == 1) { if( gActiveThreads->CurCPU == -1 ) @@ -759,8 +786,8 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) if( Last->Status == THREAD_STAT_ACTIVE ) { giFreeTickets += Last->NumTickets; #if DEBUG_TRACE_TICKETS - LogF(" CPU %i released %p (%s) into the pool (%i tickets in pool)\n", - CPU, Last, Last->ThreadName, Last->NumTickets); + LogF(" CPU %i released %p (%i %s) into the pool (%i tickets in pool)\n", + CPU, Last, Last->TID, Last->ThreadName, giFreeTickets); #endif } #if DEBUG_TRACE_TICKETS @@ -819,8 +846,8 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last) //Threads_Dump(); #if DEBUG_TRACE_TICKETS - LogF(" CPU%i giFreeTickets = %i, giving %p (%s CPU=%i)\n", - CPU, giFreeTickets, thread, thread->ThreadName, thread->CurCPU); + LogF(" CPU%i giFreeTickets = %i, giving %p (%i %s CPU=%i)\n", + CPU, giFreeTickets, thread, thread->TID, thread->ThreadName, thread->CurCPU); #endif SHORTREL( &glThreadListLock ); @@ -852,7 +879,6 @@ void Threads_SegFault(tVAddr Addr) void Mutex_Acquire(tMutex *Mutex) { tThread *us = Proc_GetCurThread(); - tThread *prev; // Get protector SHORTLOCK( &Mutex->Protector ); @@ -863,11 +889,9 @@ void Mutex_Acquire(tMutex *Mutex) if( Mutex->Owner ) { SHORTLOCK( &glThreadListLock ); // - Remove from active list - us->Remaining = 0; - prev = Threads_int_GetPrev(&gActiveThreads, us); - prev->Next = us->Next; - giNumActiveThreads --; - us->Status = THREAD_STAT_SLEEPING; + Threads_RemActive(); + // - Mark as sleeping + us->Status = THREAD_STAT_OFFSLEEP; // - Add to waiting if(Mutex->LastWaiting) { @@ -880,7 +904,7 @@ void Mutex_Acquire(tMutex *Mutex) } SHORTREL( &glThreadListLock ); SHORTREL( &Mutex->Protector ); - while(us->Status == THREAD_STAT_SLEEPING) HALT(); + while(us->Status == THREAD_STAT_OFFSLEEP) HALT(); // We're only woken when we get the lock } // Ooh, let's take it! diff --git a/Modules/Network/NE2000/ne2000.c b/Modules/Network/NE2000/ne2000.c index 5cd23d25..d77bfb86 100644 --- a/Modules/Network/NE2000/ne2000.c +++ b/Modules/Network/NE2000/ne2000.c @@ -162,7 +162,7 @@ int Ne2k_Install(char **Options) outb( base + CURR, RX_FIRST ); // Current RX page outb( base + CMD, 0x21 ); // No DMA and Stop outb( base + DCR, 0x49 ); // Set WORD mode - outb( base + IMR, 0x00 ); + outb( base + IMR, 0x00 ); // Interrupt Mask Register outb( base + ISR, 0xFF ); outb( base + RCR, 0x20 ); // Reciever to Monitor outb( base + TCR, 0x02 ); // Transmitter OFF (TCR.LB = 1, Internal Loopback)