Big bugfixes from trying a Clone/fork bomb
[tpg/acess2.git] / Kernel / threads.c
index 325fa74..5d15c92 100644 (file)
@@ -35,12 +35,13 @@ extern void Proc_Start(void);
 extern tThread *Proc_GetCurThread(void);
 extern int     Proc_Clone(Uint *Err, Uint Flags);
 extern void    Proc_CallFaultHandler(tThread *Thread);
+extern int     GetCPUNum(void);
 
 // === PROTOTYPES ===
 void   Threads_Init(void);
- int   Threads_SetName(char *NewName);
+ int   Threads_SetName(const char *NewName);
 char   *Threads_GetName(int ID);
-void   Threads_SetTickets(tThread *Thread, int Num);
+void   Threads_SetPriority(tThread *Thread, int Pri);
 tThread        *Threads_CloneTCB(Uint *Err, Uint Flags);
  int   Threads_WaitTID(int TID, int *status);
 tThread        *Threads_GetThread(Uint TID);
@@ -61,6 +62,7 @@ tGID  Threads_GetGID(void);
  int   Threads_SetGID(Uint *Errno, tUID ID);
 void   Threads_Dump(void);
 void   Threads_DumpActive(void);
+
 void   Mutex_Acquire(tMutex *Mutex);
 void   Mutex_Release(tMutex *Mutex);
  int   Mutex_IsLocked(tMutex *Mutex);
@@ -123,12 +125,12 @@ void Threads_Init(void)
 }
 
 /**
- * \fn void Threads_SetName(char *NewName)
+ * \fn void Threads_SetName(const char *NewName)
  * \brief Sets the current thread's name
  * \param NewName      New name for the thread
  * \return Boolean Failure
  */
-int Threads_SetName(char *NewName)
+int Threads_SetName(const char *NewName)
 {
        tThread *cur = Proc_GetCurThread();
        char    *oldname = cur->ThreadName;
@@ -277,6 +279,7 @@ tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
        SHORTLOCK( &glThreadListLock );
        new->GlobalPrev = NULL; // Protect against bugs
        new->GlobalNext = gAllThreads;
+       gAllThreads->GlobalPrev = new;
        gAllThreads = new;
        SHORTREL( &glThreadListLock );
        
@@ -464,15 +467,15 @@ void Threads_Kill(tThread *Thread, int Status)
        tMsg    *msg;
        
        // TODO: Kill all children
-       #if 0
+       #if 1
        {
                tThread *child;
                // TODO: I should keep a .Parent pointer, and a .Children list
-               for(child = gActiveThreads;
+               for(child = gAllThreads;
                        child;
-                       child = child->Next)
+                       child = child->GlobalNext)
                {
-                       if(child->PTID == Thread->TID)
+                       if(child->Parent == Thread)
                                Threads_Kill(child, -1);
                }
        }
@@ -494,29 +497,52 @@ void Threads_Kill(tThread *Thread, int Status)
        // Lock thread list
        SHORTLOCK( &glThreadListLock );
        
-       // Delete from active list
-       #if SCHEDULER_TYPE == SCHED_RR_PRI
-       if( !Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
-       #else
-       if( !Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
-       #endif
+       switch(Thread->Status)
        {
-               Warning("Proc_Exit - Current thread is not on the active queue");
-               SHORTREL( &glThreadListLock );
-               SHORTREL( &Thread->IsLocked );
-               return;
-       }
+       case THREAD_STAT_PREINIT:       // Only on main list
+               break;
        
-       // Ensure that we are not rescheduled
-       Thread->Remaining = 0;  // Clear Remaining Quantum
-       Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
-       
-       // Update bookkeeping
-       giNumActiveThreads --;
-       #if SCHEDULER_TYPE == SCHED_LOTTERY
-       if( Thread != Proc_GetCurThread() )
-               giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
-       #endif
+       // Currently active thread
+       case THREAD_STAT_ACTIVE:
+               #if SCHEDULER_TYPE == SCHED_RR_PRI
+               if( Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
+               #else
+               if( Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
+               #endif
+               {
+                       // Ensure that we are not rescheduled
+                       Thread->Remaining = 0;  // Clear Remaining Quantum
+                       Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
+                       
+                       // Update bookkeeping
+                       giNumActiveThreads --;
+                       #if SCHEDULER_TYPE == SCHED_LOTTERY
+                       if( Thread != Proc_GetCurThread() )
+                               giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
+                       #endif
+               }
+               else
+               {
+                       Log_Warning("Threads",
+                               "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
+                               Thread, Thread->TID, Thread->ThreadName
+                               );
+               }
+               break;
+       case THREAD_STAT_SLEEPING:
+               if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) )
+               {
+                       Log_Warning("Threads",
+                               "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list",
+                               Thread, Thread->TID, Thread->ThreadName
+                               );
+               }
+               break;
+       default:
+               Log_Warning("Threads", "Threads_Kill - BUG Un-checked status (%i)",
+                       Thread->Status);
+               break;
+       }
        
        // Save exit status
        Thread->RetStatus = Status;
@@ -532,7 +558,7 @@ void Threads_Kill(tThread *Thread, int Status)
                Threads_Wake( Thread->Parent );
        }
        
-       Log("Thread %i went *hurk* (%i)", Thread->TID, Thread->Status);
+       Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
        
        // Release spinlocks
        SHORTREL( &glThreadListLock );
@@ -662,6 +688,12 @@ void Threads_AddActive(tThread *Thread)
 {
        SHORTLOCK( &glThreadListLock );
        
+       if( Thread->Status == THREAD_STAT_ACTIVE ) {
+               tThread *cur = Proc_GetCurThread();
+               Warning("WTF, CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
+                       GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName);
+       }
+       
        // Set state
        Thread->Status = THREAD_STAT_ACTIVE;
        Thread->CurCPU = -1;
@@ -680,8 +712,8 @@ void Threads_AddActive(tThread *Thread)
        #if SCHEDULER_TYPE == SCHED_LOTTERY
        giFreeTickets += caiTICKET_COUNTS[ Thread->Priority ];
        # if DEBUG_TRACE_TICKETS
-       Log("Threads_AddActive: %p %i (%s) added, new giFreeTickets = %i",
-               Thread, Thread->TID, Thread->ThreadName, giFreeTickets);
+       Log("Threads_AddActive: CPU%i %p %i (%s) added, new giFreeTickets = %i",
+               GetCPUNum(), Thread, Thread->TID, Thread->ThreadName, giFreeTickets);
        # endif
        #endif
        
@@ -710,6 +742,7 @@ tThread *Threads_RemActive(void)
                return NULL;
        }
        
+       ret->Next = NULL;
        ret->Remaining = 0;
        ret->CurCPU = -1;
        
@@ -717,8 +750,8 @@ tThread *Threads_RemActive(void)
        // no need to decrement tickets, scheduler did it for us
        
        #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
-       Log("Threads_RemActive: %p %i (%s) removed, giFreeTickets = %i",
-               ret, ret->TID, ret->ThreadName, giFreeTickets);
+       Log("Threads_RemActive: CPU%i %p %i (%s) removed, giFreeTickets = %i",
+               GetCPUNum(), ret, ret->TID, ret->ThreadName, giFreeTickets);
        #endif
        
        SHORTREL( &glThreadListLock );
@@ -835,8 +868,8 @@ void Threads_DumpActive(void)
                for(thread=gActiveThreads;thread;thread=thread->Next)
        #endif
                {
-                       Log(" %i (%i) - %s (CPU %i)",
-                               thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+                       Log(" %p %i (%i) - %s (CPU %i)",
+                               thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
                        if(thread->Status != THREAD_STAT_ACTIVE)
                                Log("  ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE);
                        Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
@@ -862,9 +895,19 @@ void Threads_Dump(void)
        Log("All Threads:");
        for(thread=gAllThreads;thread;thread=thread->GlobalNext)
        {
-               Log(" %i (%i) - %s (CPU %i)",
-                       thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
-               Log("  State %i", thread->Status);
+               Log(" %p %i (%i) - %s (CPU %i)",
+                       thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+               Log("  State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
+               switch(thread->Status)
+               {
+               case THREAD_STAT_MUTEXSLEEP:
+                       Log("  Mutex Pointer: %p", thread->WaitPointer);
+                       break;
+               case THREAD_STAT_ZOMBIE:
+                       Log("  Return Status: %i", thread->RetStatus);
+                       break;
+               default:        break;
+               }
                Log("  Priority %i, Quantum %i", thread->Priority, thread->Quantum);
                Log("  KStack 0x%x", thread->KernelStack);
        }
@@ -896,9 +939,11 @@ tThread *Threads_GetNextToRun(int CPU, tThread *Last)
        while(gDeleteThreads)
        {
                thread = gDeleteThreads->Next;
-               if( IS_LOCKED(&gDeleteThreads->IsLocked) ) {    // Only free if structure is unused
+               // Only free if structure is unused
+               if( !IS_LOCKED(&gDeleteThreads->IsLocked) )
+               {
                        // Set to dead
-                       gDeleteThreads->Status = THREAD_STAT_DEAD;
+                       gDeleteThreads->Status = THREAD_STAT_BURIED;
                        // Free name
                        if( IsHeap(gDeleteThreads->ThreadName) )
                                free(gDeleteThreads->ThreadName);
@@ -1121,8 +1166,10 @@ void Mutex_Acquire(tMutex *Mutex)
                SHORTLOCK( &glThreadListLock );
                // - Remove from active list
                us = Threads_RemActive();
+               us->Next = NULL;
                // - Mark as sleeping
-               us->Status = THREAD_STAT_OFFSLEEP;
+               us->Status = THREAD_STAT_MUTEXSLEEP;
+               us->WaitPointer = Mutex;
                
                // - Add to waiting
                if(Mutex->LastWaiting) {
@@ -1133,16 +1180,33 @@ void Mutex_Acquire(tMutex *Mutex)
                        Mutex->Waiting = us;
                        Mutex->LastWaiting = us;
                }
+               #if 0
+               {
+                        int    i = 0;
+                       tThread *t;
+                       for( t = Mutex->Waiting; t; t = t->Next, i++ )
+                               Log("[%i] (tMutex)%p->Waiting[%i] = %p (%i %s)", us->TID, Mutex, i,
+                                       t, t->TID, t->ThreadName);
+               }
+               #endif
+               
                SHORTREL( &glThreadListLock );
                SHORTREL( &Mutex->Protector );
-               while(us->Status == THREAD_STAT_OFFSLEEP)       Threads_Yield();
+               while(us->Status == THREAD_STAT_MUTEXSLEEP)     Threads_Yield();
                // We're only woken when we get the lock
+               us->WaitPointer = NULL;
        }
        // Ooh, let's take it!
        else {
                Mutex->Owner = us;
                SHORTREL( &Mutex->Protector );
        }
+       
+       #if 0
+       extern tMutex   glPhysAlloc;
+       if( Mutex != &glPhysAlloc )
+               LogF("Mutex %p taken by %i %p\n", Mutex, us->TID, __builtin_return_address(0));
+       #endif
 }
 
 /**
@@ -1173,6 +1237,12 @@ void Mutex_Release(tMutex *Mutex)
                Mutex->Owner = NULL;
        }
        SHORTREL( &Mutex->Protector );
+       
+       #if 0
+       extern tMutex   glPhysAlloc;
+       if( Mutex != &glPhysAlloc )
+               LogF("Mutex %p released by %i %p\n", Mutex, Threads_GetTID(), __builtin_return_address(0));
+       #endif
 }
 
 /**
@@ -1184,6 +1254,86 @@ int Mutex_IsLocked(tMutex *Mutex)
        return Mutex->Owner != NULL;
 }
 
+/**
+ * \brief Initialise the semaphore
+ * \param Value        Initial value of the semaphore
+ * \param Label        Symbolic name
+ */
+void Semaphore_Init(tSemaphore *Sem, int Value, const char *Label)
+{
+       Sem->Value = Value;
+       Sem->Name = Label;
+}
+
+/**
+ * \brief Acquire a "item" from the semaphore
+ */
+void Semaphore_Wait(tSemaphore *Sem)
+{
+       tThread *us;
+       
+       SHORTLOCK( &Sem->Protector );
+       if( Sem->Value > 0 ) {
+               Sem->Value --;
+               SHORTREL( &Sem->Protector );
+               return ;
+       }
+       
+       SHORTLOCK( &glThreadListLock );
+       
+       // - Remove from active list
+       us = Threads_RemActive();
+       us->Next = NULL;
+       // - Mark as sleeping
+       us->Status = THREAD_STAT_SEMAPHORESLEEP;
+       us->WaitPointer = Sem;
+       
+       // - Add to waiting
+       if(Sem->LastWaiting) {
+               Sem->LastWaiting->Next = us;
+               Sem->LastWaiting = us;
+       }
+       else {
+               Sem->Waiting = us;
+               Sem->LastWaiting = us;
+       }
+       
+       SHORTREL( &glThreadListLock );
+       SHORTREL( &Sem->Protector );
+       while(us->Status == THREAD_STAT_MUTEXSLEEP)     Threads_Yield();
+       // We're only woken when there's something avaliable
+       us->WaitPointer = NULL;
+}
+
+/**
+ * \brief Add an "item" to the semaphore
+ */
+void Semaphore_Signal(tSemaphore *Sem)
+{
+       SHORTLOCK( &Sem->Protector );
+       Sem->Value ++;
+       
+       if( Sem->Waiting )
+       {
+               tThread *toWake = Sem->Waiting;
+               
+               Sem->Waiting = Sem->Waiting->Next;      // Next!
+               // Reset ->LastWaiting to NULL if we have just removed the last waiting thread
+               if( Sem->Waiting == NULL )
+                       Sem->LastWaiting = NULL;
+               
+               // Wake new owner
+               SHORTLOCK( &glThreadListLock );
+               if( toWake->Status != THREAD_STAT_ACTIVE )
+                       Threads_AddActive(toWake);
+               SHORTREL( &glThreadListLock );
+               
+               // Decrement (the value is now "owned" by `toWake`)
+               Sem->Value --;
+       }
+       SHORTREL( &Sem->Protector );
+}
+
 // === EXPORTS ===
 EXPORT(Threads_GetUID);
 EXPORT(Threads_GetGID);

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