Kernel/threads - Fixed infinite fault loop if thread/proces pointer is bad
[tpg/acess2.git] / KernelLand / Kernel / threads.c
index e22994b..67a2f63 100644 (file)
@@ -11,6 +11,7 @@
 #include <hal_proc.h>
 #include <semaphore.h>
 #include <vfs_threads.h>       // VFS Handle maintainence
+#include <events.h>
 
 // Configuration
 #define DEBUG_TRACE_TICKETS    0       // Trace ticket counts
@@ -65,6 +66,10 @@ tThread      *Threads_RemActive(void);
 void   Threads_ToggleTrace(int TID);
 void   Threads_Fault(int Num);
 void   Threads_SegFault(tVAddr Addr);
+void   Threads_PostSignal(int SignalNum);
+ int   Threads_GetPendingSignal(void);
+void   Threads_SetSignalHandler(int SignalNum, void *Handler);
+void   *Threads_GetSignalHandler(int SignalNum);
 #if 0
  int   Threads_GetPID(void);
  int   Threads_GetTID(void);
@@ -73,6 +78,7 @@ tGID  Threads_GetGID(void);
  int   Threads_SetUID(Uint *Errno, tUID ID);
  int   Threads_SetGID(Uint *Errno, tUID ID);
 #endif
+void   Threads_int_DumpThread(tThread *thread);
 void   Threads_Dump(void);
 void   Threads_DumpActive(void);
 
@@ -343,9 +349,16 @@ tThread *Threads_CloneTCB(Uint Flags)
                newproc->nThreads = 1;
                // Reference all handles in the VFS
                VFS_ReferenceUserHandles();
+
+               newproc->FirstThread = new;
+               new->ProcessNext = NULL;
        }
        else {
                new->Process->nThreads ++;
+               new->Process = cur->Process;
+               // TODO: Locking
+               new->ProcessNext = new->Process->FirstThread;
+               new->Process->FirstThread = new;
        }
        
        // Messages are not inherited
@@ -434,9 +447,30 @@ tThread *Threads_CloneThreadZero(void)
 tTID Threads_WaitTID(int TID, int *Status)
 {      
        // Any Child
-       if(TID == -1) {
-               Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
-               return -1;
+       if(TID == -1)
+       {
+               Uint32 ev = Threads_WaitEvents(THREAD_EVENT_DEADCHILD);
+               tTID    ret = -1;
+               if( ev & THREAD_EVENT_DEADCHILD )
+               {
+                       // A child died, get the TID
+                       tThread *us = Proc_GetCurThread();
+                       ASSERT(us->LastDeadChild);
+                       ret = us->LastDeadChild->TID;
+                       // - Mark as dead (as opposed to undead)
+                       ASSERT(us->LastDeadChild->Status == THREAD_STAT_ZOMBIE);
+                       us->LastDeadChild->Status = THREAD_STAT_DEAD;
+                       // - Set return status
+                       if(Status)
+                               *Status = us->LastDeadChild->RetStatus;
+                       us->LastDeadChild = NULL;
+                       Mutex_Release(&us->DeadChildLock);
+               }
+               else
+               {
+                       Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
+               }
+               return ret;
        }
        
        // Any peer/child thread
@@ -452,33 +486,14 @@ tTID Threads_WaitTID(int TID, int *Status)
        }
        
        // Specific Thread
-       if(TID > 0) {
-               tThread *t = Threads_GetThread(TID);
+       if(TID > 0)
+       {
                tTID    ret;
-               
-               // Wait for the thread to die!
-               // 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);
-               }
-               
-               // Set return status
-               ret = t->TID;
-               switch(t->Status)
+               // NOTE: Race condition - Other child dies, desired child dies, first death is 'lost'
+               while( (ret = Threads_WaitTID(-1, Status)) != TID )
                {
-               case THREAD_STAT_ZOMBIE:
-                       // Kill the thread
-                       t->Status = THREAD_STAT_DEAD;
-                       // TODO: Child return value?
-                       if(Status)      *Status = t->RetStatus;
-                       // add to delete queue
-                       Threads_Delete( t );
-                       break;
-               default:
-                       if(Status)      *Status = -1;
-                       break;
+                       if( ret == -1 )
+                               break;
                }
                return ret;
        }
@@ -496,15 +511,13 @@ tThread *Threads_GetThread(Uint TID)
        tThread *thread;
        
        // Search global list
-       for(thread = gAllThreads;
-               thread;
-               thread = thread->GlobalNext)
+       for( thread = gAllThreads; thread; thread = thread->GlobalNext )
        {
                if(thread->TID == TID)
                        return thread;
        }
 
-       Log("Unable to find TID %i on main list\n", TID);
+       Log_Notice("Threads", "Unable to find TID %i on main list\n", TID);
        
        return NULL;
 }
@@ -679,8 +692,10 @@ void Threads_Kill(tThread *Thread, int Status)
 
        Thread->Status = THREAD_STAT_ZOMBIE;
        SHORTREL( &glThreadListLock );
-       // TODO: Send something like SIGCHLD
-       Threads_Wake( Thread->Parent );
+       // TODO: It's possible that we could be timer-preempted here, should disable that... somehow
+       Mutex_Acquire( &Thread->Parent->DeadChildLock );        // released by parent
+       Thread->Parent->LastDeadChild = Thread;
+       Threads_PostEvent( Thread->Parent, THREAD_EVENT_DEADCHILD );
        
        Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
        
@@ -701,6 +716,22 @@ void Threads_Yield(void)
        Proc_Reschedule();
 }
 
+/**
+ * \breif Wait for the thread status to not be a specified value
+ */
+void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
+{
+       tThread *us = Proc_GetCurThread();
+       ASSERT(Status != THREAD_STAT_ACTIVE);
+       ASSERT(Status != THREAD_STAT_DEAD);
+       while( us->Status == Status )
+       {
+               Proc_Reschedule();
+               if( us->Status == Status )
+                       Debug("Thread %p(%i %s) rescheduled while in %s state", casTHREAD_STAT[Status]);
+       }
+}
+
 /**
  * \fn void Threads_Sleep(void)
  * \brief Take the current process off the run queue
@@ -732,12 +763,7 @@ void Threads_Sleep(void)
        
        // Release Spinlock
        SHORTREL( &glThreadListLock );
-
-       while(cur->Status != THREAD_STAT_ACTIVE) {
-               Proc_Reschedule();
-               if( cur->Status != THREAD_STAT_ACTIVE )
-                       Log("%i - Huh? why am I up? zzzz...", cur->TID);
-       }
+       Threads_int_WaitForStatusEnd(THREAD_STAT_SLEEPING);
 }
 
 
@@ -759,11 +785,11 @@ int Threads_Wake(tThread *Thread)
                return -EALREADY;
        
        case THREAD_STAT_SLEEPING:
-               SHORTLOCK( &glThreadListLock );
                // Remove from sleeping queue
+               SHORTLOCK( &glThreadListLock );
                Threads_int_DelFromQueue(&gSleepingThreads, Thread);
-               
                SHORTREL( &glThreadListLock );
+               
                Threads_AddActive( Thread );
                
                #if DEBUG_TRACE_STATE
@@ -829,7 +855,7 @@ int Threads_Wake(tThread *Thread)
                return -ENOTIMPL;
        
        default:
-               Warning("Threads_Wake - Unknown process status (%i)\n", Thread->Status);
+               Log_Warning("Threads", "Threads_Wake - Unknown process status (%i)", Thread->Status);
                return -EINTERNAL;
        }
 }
@@ -982,6 +1008,62 @@ void Threads_SegFault(tVAddr Addr)
        //Threads_Exit( 0, -1 );
 }
 
+
+void Threads_PostSignal(int SignalNum)
+{
+       tThread *cur = Proc_GetCurThread();
+       cur->PendingSignal = SignalNum;
+       Threads_PostEvent(cur, THREAD_EVENT_SIGNAL);
+}
+
+/**
+ */
+int Threads_GetPendingSignal(void)
+{
+       tThread *cur = Proc_GetCurThread();
+       
+       // Atomic AND with 0 fetches and clears in one operation
+       return __sync_fetch_and_and( &cur->PendingSignal, 0 );
+}
+
+/*
+ * \brief Update the current thread's signal handler
+ */
+void Threads_SetSignalHandler(int SignalNum, void *Handler)
+{
+       if( SignalNum <= 0 || SignalNum >= NSIGNALS )
+               return ;
+       if( !MM_IsUser(Handler) )
+               return ;
+       Proc_GetCurThread()->Process->SignalHandlers[SignalNum] = Handler;
+}
+
+/**
+ * \return 0  Ignore
+ */
+void *Threads_GetSignalHandler(int SignalNum)
+{
+       if( SignalNum <= 0 || SignalNum >= NSIGNALS )
+               return NULL;
+       void *ret = Proc_GetCurThread()->Process->SignalHandlers[SignalNum];
+       if( !ret )
+       {
+               // Defaults
+               switch(SignalNum)
+               {
+               case SIGINT:
+               case SIGKILL:
+               case SIGSEGV:
+//                     ret = User_Signal_Kill;
+                       break;
+               default:
+                       ret = NULL;
+                       break;
+               }
+       }
+       return ret;
+}
+
 // --- Process Structure Access Functions ---
 tPGID Threads_GetPGID(void)
 {
@@ -1049,6 +1131,50 @@ char **Threads_GetCWD(void)
 }
 // ---
 
+void Threads_int_DumpThread(tThread *thread)
+{
+       if( !thread ) {
+               Log(" %p NULL", thread);
+               return ;
+       }
+       if( !CheckMem(thread, sizeof(tThread)) ) {
+               Log(" %p INVAL", thread);
+               return ;
+       }
+       tPID    pid = (thread->Process ? thread->Process->PID : -1);
+       const char      *statstr = (thread->Status < sizeof(casTHREAD_STAT)/sizeof(casTHREAD_STAT[0])
+               ? casTHREAD_STAT[thread->Status] : "");
+       Log(" %p %i (%i) - %s (CPU %i) - %i (%s)",
+               thread, thread->TID, pid, thread->ThreadName, thread->CurCPU,
+               thread->Status, statstr
+               );
+       switch(thread->Status)
+       {
+       case THREAD_STAT_MUTEXSLEEP:
+               Log("  Mutex Pointer: %p", thread->WaitPointer);
+               break;
+       case THREAD_STAT_SEMAPHORESLEEP:
+               Log("  Semaphore Pointer: %p", thread->WaitPointer);
+               Log("  Semaphore Name: %s:%s", 
+                       ((tSemaphore*)thread->WaitPointer)->ModName,
+                       ((tSemaphore*)thread->WaitPointer)->Name
+                       );
+               break;
+       case THREAD_STAT_EVENTSLEEP:
+               // TODO: Event mask
+               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 %p", thread->KernelStack);
+       if( thread->bInstrTrace )
+               Log("  Tracing Enabled");
+       Proc_DumpThreadCPUState(thread);
+}
+
 /**
  * \fn void Threads_Dump(void)
  */
@@ -1071,16 +1197,10 @@ void Threads_DumpActive(void)
        #endif
                for(thread=list->Head;thread;thread=thread->Next)
                {
-                       Log(" %p %i (%i) - %s (CPU %i)",
-                               thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
+                       Threads_int_DumpThread(thread);
                        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);
-                       Log("  KStack 0x%x", thread->KernelStack);
-                       if( thread->bInstrTrace )
-                               Log("  Tracing Enabled");
-                       Proc_DumpThreadCPUState(thread);
                }
        
        #if SCHEDULER_TYPE == SCHED_RR_PRI
@@ -1094,39 +1214,13 @@ void Threads_DumpActive(void)
  */
 void Threads_Dump(void)
 {
-       tThread *thread;
-       
        Log("--- Thread Dump ---");
        Threads_DumpActive();
        
        Log("All Threads:");
-       for(thread=gAllThreads;thread;thread=thread->GlobalNext)
+       for(tThread *thread = gAllThreads; thread; thread = thread->GlobalNext)
        {
-               Log(" %p %i (%i) - %s (CPU %i)",
-                       thread, thread->TID, thread->Process->PID, 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_SEMAPHORESLEEP:
-                       Log("  Semaphore Pointer: %p", thread->WaitPointer);
-                       Log("  Semaphore Name: %s:%s", 
-                               ((tSemaphore*)thread->WaitPointer)->ModName,
-                               ((tSemaphore*)thread->WaitPointer)->Name
-                               );
-                       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);
-               if( thread->bInstrTrace )
-                       Log("  Tracing Enabled");
-               Proc_DumpThreadCPUState(thread);
+               Threads_int_DumpThread(thread);
        }
 }
 

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