Unborking some threading code
authorJohn Hodge <[email protected]>
Mon, 23 Aug 2010 15:40:09 +0000 (23:40 +0800)
committerJohn Hodge <[email protected]>
Mon, 23 Aug 2010 15:40:09 +0000 (23:40 +0800)
- 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

14 files changed:
.gitignore
Kernel/arch/x86/include/arch.h
Kernel/arch/x86/mm_phys.c
Kernel/arch/x86/proc.asm
Kernel/arch/x86_64/include/arch.h
Kernel/arch/x86_64/include/mm_virt.h
Kernel/arch/x86_64/mm_phys.c
Kernel/arch/x86_64/proc.c
Kernel/arch/x86_64/vm8086.c
Kernel/drv/pci.c
Kernel/drv/vterm.c
Kernel/include/threads.h
Kernel/threads.c
Modules/Network/NE2000/ne2000.c

index a87df3d..1edda84 100644 (file)
@@ -14,4 +14,6 @@
 *.dsm
 *.dmp
 *.kmd.*
-Map.txt
+Map*.txt
+bochs*.txt
+serial.txt
index ede3bf0..0fec144 100644 (file)
@@ -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 ===
index cb4f9e0..3abe413 100644 (file)
@@ -7,7 +7,8 @@
 #include <mboot.h>
 #include <mm_virt.h>
 
-#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<<Pages)-1, giPageCount-giPhysAlloc);
+       #endif
        return ret;
 }
 
@@ -384,7 +405,11 @@ void MM_DerefPhys(tPAddr PAddr)
        // Mark as free in bitmaps
        if( gaPageReferences[ PAddr ] == 0 )
        {
+               #if TRACE_ALLOCS
+               Log_Debug("PMem", "MM_DerefPhys: Free'd 0x%x (%i free)", PAddr, giPageCount-giPhysAlloc);
+               #endif
                //LOG("Freed 0x%x by %p\n", PAddr<<12, __builtin_return_address(0));
+               giPhysAlloc --;
                gaPageBitmap[ PAddr / 32 ] &= ~(1 << (PAddr&31));
                if(gaPageReferences[ PAddr ] == 0)
                        gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
index 9dc7f08..80cc3cb 100644 (file)
@@ -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
        
index d419234..6b75a7d 100644 (file)
@@ -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
 
index ca50855..867aa3b 100644 (file)
@@ -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
index 55fc68a..c67b905 100644 (file)
@@ -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;
 }
index 81b8eeb..c5c0c18 100644 (file)
@@ -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;
index 68728c1..1459c73 100644 (file)
@@ -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
index b4881d3..ec96d86 100644 (file)
@@ -116,7 +116,7 @@ int PCI_Install(char **Arguments)
        }\r
        gPCI_Devices = tmpPtr;\r
        \r
-       Log_Log("PCI", "%i devices, filling structure");\r
+       Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);\r
        \r
        // Reset counts\r
        giPCI_DeviceCount = 0;\r
index da82d67..c2f0685 100644 (file)
@@ -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'))
                {
index 6c29230..3b6e9c6 100644 (file)
@@ -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
index 99a9add..5d8e401 100644 (file)
@@ -7,7 +7,8 @@
 #include <threads.h>
 #include <errno.h>
 
-#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!
index 5cd23d2..d77bfb8 100644 (file)
@@ -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)

UCC git Repository :: git.ucc.asn.au