3 * - By John Hodge (thePowersGang)
5 * - Common Thread Control
9 #include <threads_int.h>
12 #include <semaphore.h>
13 #include <vfs_threads.h> // VFS Handle maintainence
16 #define DEBUG_TRACE_TICKETS 0 // Trace ticket counts
17 #define DEBUG_TRACE_STATE 0 // Trace state changes (sleep/wake)
21 #define SCHED_LOTTERY 1 // Lottery scheduler
22 #define SCHED_RR_SIM 2 // Single Queue Round Robin
23 #define SCHED_RR_PRI 3 // Multi Queue Round Robin
25 #define SCHEDULER_TYPE SCHED_RR_PRI
28 #define DEFAULT_QUANTUM 5
29 #define DEFAULT_PRIORITY 5
30 #define MIN_PRIORITY 10
42 void Threads_Init(void);
44 void Threads_Delete(tThread *Thread);
45 int Threads_SetName(const char *NewName);
47 char *Threads_GetName(tTID ID);
49 void Threads_SetPriority(tThread *Thread, int Pri);
50 tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
51 int Threads_WaitTID(int TID, int *status);
52 tThread *Threads_GetThread(Uint TID);
54 tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread);
55 void Threads_int_AddToList(tThreadList *List, tThread *Thread);
57 void Threads_Exit(int TID, int Status);
58 void Threads_Kill(tThread *Thread, int Status);
59 void Threads_Yield(void);
60 void Threads_Sleep(void);
61 int Threads_Wake(tThread *Thread);
62 void Threads_AddActive(tThread *Thread);
63 tThread *Threads_RemActive(void);
65 void Threads_ToggleTrace(int TID);
66 void Threads_Fault(int Num);
67 void Threads_SegFault(tVAddr Addr);
69 int Threads_GetPID(void);
70 int Threads_GetTID(void);
71 tUID Threads_GetUID(void);
72 tGID Threads_GetGID(void);
73 int Threads_SetUID(Uint *Errno, tUID ID);
74 int Threads_SetGID(Uint *Errno, tUID ID);
76 void Threads_Dump(void);
77 void Threads_DumpActive(void);
81 struct sProcess gProcessZero = {
83 // Only used for the core kernel
84 tThread gThreadZero = {
85 .Status = THREAD_STAT_ACTIVE, // Status
86 .ThreadName = (char*)"ThreadZero", // Name
87 .Quantum = DEFAULT_QUANTUM, // Default Quantum
88 .Remaining = DEFAULT_QUANTUM, // Current Quantum
89 .Priority = DEFAULT_PRIORITY // Number of tickets
93 tShortSpinlock glThreadListLock; ///\note NEVER use a heap function while locked
94 // --- Current State ---
95 volatile int giNumActiveThreads = 0; // Number of threads on the active queue
96 volatile Uint giNextTID = 1; // Next TID to allocate
97 // --- Thread Lists ---
98 tThread *gAllThreads = NULL; // All allocated threads
99 tThreadList gSleepingThreads; // Sleeping Threads
100 int giNumCPUs = 1; // Number of CPUs
101 BOOL gaThreads_NoTaskSwitch[MAX_CPUS]; // Disables task switches for each core (Pseudo-IF)
102 // --- Scheduler Types ---
103 #if SCHEDULER_TYPE == SCHED_LOTTERY
104 const int caiTICKET_COUNTS[MIN_PRIORITY+1] = {100,81,64,49,36,25,16,9,4,1,0};
105 volatile int giFreeTickets = 0; // Number of tickets held by non-scheduled threads
106 tThreadList gActiveThreads; // Currently Running Threads
107 #elif SCHEDULER_TYPE == SCHED_RR_SIM
108 tThreadList gActiveThreads; // Currently Running Threads
109 #elif SCHEDULER_TYPE == SCHED_RR_PRI
110 tThreadList gaActiveThreads[MIN_PRIORITY+1]; // Active threads for each priority level
112 # error "Unkown scheduler type"
117 * \fn void Threads_Init(void)
118 * \brief Initialse the thread list
120 void Threads_Init(void)
124 Log_Debug("Threads", "Offsets of tThread");
125 Log_Debug("Threads", ".Priority = %i", offsetof(tThread, Priority));
126 Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
128 // Create Initial Task
129 gAllThreads = &gThreadZero;
130 giNumActiveThreads = 1;
131 gThreadZero.Process = &gProcessZero;
136 void Threads_Delete(tThread *Thread)
139 Thread->Status = THREAD_STAT_BURIED;
141 // Clear out process state
142 Proc_ClearThread(Thread);
144 Thread->Process->nThreads --;
146 if( Thread->Process->FirstThread == Thread )
148 Thread->Process->FirstThread = Thread->ProcessNext;
152 tThread *prev = Thread->Process->FirstThread;
153 while(prev && prev->ProcessNext != Thread)
154 prev = prev->ProcessNext;
156 Log_Error("Threads", "Thread %p(%i %s) is not on the process's list",
157 Thread, Thread->TID, Thread->ThreadName
160 prev->ProcessNext = Thread->ProcessNext;
163 // If the final thread is being terminated, clean up the process
164 if( Thread->Process->nThreads == 0 )
166 tProcess *proc = Thread->Process;
168 VFS_CloseAllUserHandles();
169 // Architecture cleanup
170 Proc_ClearProcess( proc );
171 // VFS Configuration strings
172 if( proc->CurrentWorkingDir)
173 free( proc->CurrentWorkingDir );
175 free( proc->RootDir );
176 // Process descriptor
181 if( IsHeap(Thread->ThreadName) )
182 free(Thread->ThreadName);
184 // Remove from global list
185 // TODO: Lock this too
186 if( Thread == gAllThreads )
187 gAllThreads = Thread->GlobalNext;
189 Thread->GlobalPrev->GlobalNext = Thread->GlobalNext;
195 * \fn void Threads_SetName(const char *NewName)
196 * \brief Sets the current thread's name
197 * \param NewName New name for the thread
198 * \return Boolean Failure
200 int Threads_SetName(const char *NewName)
202 tThread *cur = Proc_GetCurThread();
203 char *oldname = cur->ThreadName;
205 // NOTE: There is a possibility of non-thread safety here
206 // A thread could read the current name pointer before it is zeroed
208 cur->ThreadName = NULL;
210 if( IsHeap(oldname) ) free( oldname );
211 cur->ThreadName = strdup(NewName);
213 Log_Debug("Threads", "Thread renamed to '%s'", NewName);
219 * \fn char *Threads_GetName(int ID)
220 * \brief Gets a thread's name
221 * \param ID Thread ID (-1 indicates current thread)
222 * \return Pointer to name
223 * \retval NULL Failure
225 char *Threads_GetName(tTID ID)
228 return Proc_GetCurThread()->ThreadName;
230 return Threads_GetThread(ID)->ThreadName;
234 * \fn void Threads_SetPriority(tThread *Thread, int Pri)
235 * \brief Sets the priority of a task
236 * \param Thread Thread to update ticket count (NULL means current thread)
237 * \param Pri New priority
239 void Threads_SetPriority(tThread *Thread, int Pri)
241 // Get current thread
242 if(Thread == NULL) Thread = Proc_GetCurThread();
244 // - If < 0, set to lowest priority
245 // - Minumum priority is actualy a high number, 0 is highest
246 if(Pri < 0) Pri = MIN_PRIORITY;
247 if(Pri > MIN_PRIORITY) Pri = MIN_PRIORITY;
249 // Do we actually have to do anything?
250 if( Pri == Thread->Priority ) return;
252 #if SCHEDULER_TYPE == SCHED_RR_PRI
253 if( Thread != Proc_GetCurThread() )
255 SHORTLOCK( &glThreadListLock );
256 // Remove from old priority
257 Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
259 Threads_int_AddToList( &gaActiveThreads[Pri], Thread );
260 Thread->Priority = Pri;
261 SHORTREL( &glThreadListLock );
264 Thread->Priority = Pri;
266 // If this isn't the current thread, we need to lock
267 if( Thread != Proc_GetCurThread() )
269 SHORTLOCK( &glThreadListLock );
271 #if SCHEDULER_TYPE == SCHED_LOTTERY
272 giFreeTickets -= caiTICKET_COUNTS[Thread->Priority] - caiTICKET_COUNTS[Pri];
273 # if DEBUG_TRACE_TICKETS
274 Log("Threads_SetTickets: new giFreeTickets = %i [-%i+%i]",
276 caiTICKET_COUNTS[Thread->Priority], caiTICKET_COUNTS[Pri]);
279 Thread->Priority = Pri;
280 SHORTREL( &glThreadListLock );
283 Thread->Priority = Pri;
286 #if DEBUG_TRACE_STATE
287 Log("Threads_SetPriority: %p(%i %s) pri set %i",
288 Thread, Thread->TID, Thread->ThreadName,
294 * \brief Clone the TCB of the current thread
295 * \param Flags Flags for something... (What is this for?)
297 tThread *Threads_CloneTCB(Uint Flags)
300 cur = Proc_GetCurThread();
302 // Allocate and duplicate
303 new = malloc(sizeof(tThread));
304 if(new == NULL) { errno = -ENOMEM; return NULL; }
305 memcpy(new, cur, sizeof(tThread));
309 memset( &new->IsLocked, 0, sizeof(new->IsLocked));
310 new->Status = THREAD_STAT_PREINIT;
314 new->TID = giNextTID++;
316 new->bInstrTrace = 0;
319 new->ThreadName = strdup(cur->ThreadName);
321 // Set Thread Group ID (PID)
322 if(Flags & CLONE_VM) {
323 tProcess *newproc, *oldproc;
324 oldproc = cur->Process;
325 new->Process = malloc( sizeof(struct sProcess) );
326 newproc = new->Process;
327 newproc->PID = new->TID;
328 if( Flags & CLONE_PGID )
329 newproc->PGID = oldproc->PGID;
331 newproc->PGID = newproc->PID;
332 newproc->UID = oldproc->UID;
333 newproc->GID = oldproc->GID;
334 newproc->MaxFD = oldproc->MaxFD;
335 if( oldproc->CurrentWorkingDir )
336 newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir );
338 newproc->CurrentWorkingDir = NULL;
339 if( oldproc->RootDir )
340 newproc->RootDir = strdup( oldproc->RootDir );
342 newproc->RootDir = NULL;
343 newproc->nThreads = 1;
344 // Reference all handles in the VFS
345 VFS_ReferenceUserHandles();
348 new->Process->nThreads ++;
351 // Messages are not inherited
352 new->Messages = NULL;
353 new->LastMessage = NULL;
356 new->Remaining = new->Quantum = cur->Quantum;
357 new->Priority = cur->Priority;
360 // Set Signal Handlers
361 new->CurFaultNum = 0;
362 new->FaultHandler = cur->FaultHandler;
364 // Maintain a global list of threads
365 SHORTLOCK( &glThreadListLock );
366 new->GlobalPrev = NULL; // Protect against bugs
367 new->GlobalNext = gAllThreads;
368 gAllThreads->GlobalPrev = new;
370 SHORTREL( &glThreadListLock );
376 * \brief Clone the TCB of the kernel thread
378 tThread *Threads_CloneThreadZero(void)
382 // Allocate and duplicate
383 new = malloc(sizeof(tThread));
387 memcpy(new, &gThreadZero, sizeof(tThread));
389 new->Process->nThreads ++;
393 memset( &new->IsLocked, 0, sizeof(new->IsLocked));
394 new->Status = THREAD_STAT_PREINIT;
398 new->TID = giNextTID++;
402 new->ThreadName = NULL;
404 // Messages are not inherited
405 new->Messages = NULL;
406 new->LastMessage = NULL;
409 new->Remaining = new->Quantum = DEFAULT_QUANTUM;
410 new->Priority = DEFAULT_PRIORITY;
411 new->bInstrTrace = 0;
413 // Set Signal Handlers
414 new->CurFaultNum = 0;
415 new->FaultHandler = 0;
417 // Maintain a global list of threads
418 SHORTLOCK( &glThreadListLock );
419 new->GlobalPrev = NULL; // Protect against bugs
420 new->GlobalNext = gAllThreads;
421 gAllThreads->GlobalPrev = new;
423 SHORTREL( &glThreadListLock );
429 * \brief Wait for a task to change state
430 * \param TID Thread ID to wait on (-1: Any child thread, 0: Any Child/Sibling, <-1: -PID)
431 * \param Status Thread return status
432 * \return TID of child that changed state
434 tTID Threads_WaitTID(int TID, int *Status)
438 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
442 // Any peer/child thread
444 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
450 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
456 tThread *t = Threads_GetThread(TID);
459 // Wait for the thread to die!
460 // TODO: Handle child also being suspended if wanted
461 while(t->Status != THREAD_STAT_ZOMBIE) {
463 Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
464 Threads_GetTID(), t->TID, t->Status);
471 case THREAD_STAT_ZOMBIE:
473 t->Status = THREAD_STAT_DEAD;
474 // TODO: Child return value?
475 if(Status) *Status = t->RetStatus;
476 // add to delete queue
480 if(Status) *Status = -1;
490 * \brief Gets a thread given its TID
491 * \param TID Thread ID
492 * \return Thread pointer
494 tThread *Threads_GetThread(Uint TID)
498 // Search global list
499 for(thread = gAllThreads;
501 thread = thread->GlobalNext)
503 if(thread->TID == TID)
507 Log("Unable to find TID %i on main list\n", TID);
513 * \brief Deletes an entry from a list
514 * \param List Pointer to the list head
515 * \param Thread Thread to find
518 tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread)
520 tThread *ret, *prev = NULL;
522 for(ret = List->Head;
523 ret && ret != Thread;
524 prev = ret, ret = ret->Next
527 // Is the thread on the list
529 //LogF("%p(%s) is not on list %p\n", Thread, Thread->ThreadName, List);
534 List->Head = Thread->Next;
535 //LogF("%p(%s) removed from head of %p\n", Thread, Thread->ThreadName, List);
538 prev->Next = Thread->Next;
539 //LogF("%p(%s) removed from %p (prev=%p)\n", Thread, Thread->ThreadName, List, prev);
541 if( Thread->Next == NULL )
547 void Threads_int_AddToList(tThreadList *List, tThread *Thread)
550 List->Tail->Next = Thread;
558 * \brief Exit the current process (or another?)
559 * \param TID Thread ID to kill
560 * \param Status Exit status
562 void Threads_Exit(int TID, int Status)
565 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
567 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
569 // Halt forever, just in case
574 * \fn void Threads_Kill(tThread *Thread, int Status)
575 * \brief Kill a thread
576 * \param Thread Thread to kill
577 * \param Status Status code to return to the parent
579 void Threads_Kill(tThread *Thread, int Status)
582 int isCurThread = Thread == Proc_GetCurThread();
584 // TODO: Disown all children?
588 // TODO: I should keep a .Children list
589 for(child = gAllThreads;
591 child = child->GlobalNext)
593 if(child->Parent == Thread)
594 child->Parent = &gThreadZero;
599 ///\note Double lock is needed due to overlap of lock areas
601 // Lock thread (stop us recieving messages)
602 SHORTLOCK( &Thread->IsLocked );
604 // Clear Message Queue
605 while( Thread->Messages )
607 msg = Thread->Messages->Next;
608 free( Thread->Messages );
609 Thread->Messages = msg;
613 SHORTLOCK( &glThreadListLock );
615 switch(Thread->Status)
617 case THREAD_STAT_PREINIT: // Only on main list
620 // Currently active thread
621 case THREAD_STAT_ACTIVE:
622 if( Thread != Proc_GetCurThread() )
624 #if SCHEDULER_TYPE == SCHED_RR_PRI
625 tThreadList *list = &gaActiveThreads[Thread->Priority];
627 tThreadList *list = &gActiveThreads;
629 if( Threads_int_DelFromQueue( list, Thread ) )
634 Log_Warning("Threads",
635 "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
636 Thread, Thread->TID, Thread->ThreadName
639 #if SCHEDULER_TYPE == SCHED_LOTTERY
640 giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
643 // Ensure that we are not rescheduled
644 Thread->Remaining = 0; // Clear Remaining Quantum
645 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
647 // Update bookkeeping
648 giNumActiveThreads --;
650 // Kill it while it sleeps!
651 case THREAD_STAT_SLEEPING:
652 if( !Threads_int_DelFromQueue( &gSleepingThreads, Thread ) )
654 Log_Warning("Threads",
655 "Threads_Kill - Thread %p(%i,%s) marked as sleeping, but not on list",
656 Thread, Thread->TID, Thread->ThreadName
661 // Brains!... You cannot kill something that is already dead
662 case THREAD_STAT_ZOMBIE:
663 Log_Warning("Threads", "Threads_Kill - Thread %p(%i,%s) is undead, you cannot kill it",
664 Thread, Thread->TID, Thread->ThreadName);
665 SHORTREL( &glThreadListLock );
666 SHORTREL( &Thread->IsLocked );
670 Log_Warning("Threads", "Threads_Kill - BUG Un-checked status (%i)",
676 Thread->RetStatus = Status;
678 SHORTREL( &Thread->IsLocked );
680 Thread->Status = THREAD_STAT_ZOMBIE;
681 SHORTREL( &glThreadListLock );
682 // TODO: Send something like SIGCHLD
683 Threads_Wake( Thread->Parent );
685 Log("Thread %i went *hurk* (%i)", Thread->TID, Status);
696 * \brief Yield remainder of the current thread's timeslice
698 void Threads_Yield(void)
700 // Log("Threads_Yield: by %p", __builtin_return_address(0));
705 * \fn void Threads_Sleep(void)
706 * \brief Take the current process off the run queue
708 void Threads_Sleep(void)
710 tThread *cur = Proc_GetCurThread();
713 SHORTLOCK( &glThreadListLock );
715 // Don't sleep if there is a message waiting
716 if( cur->Messages ) {
717 SHORTREL( &glThreadListLock );
721 // Remove us from running queue
723 // Mark thread as sleeping
724 cur->Status = THREAD_STAT_SLEEPING;
726 // Add to Sleeping List (at the top)
727 Threads_int_AddToList( &gSleepingThreads, cur );
729 #if DEBUG_TRACE_STATE
730 Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
734 SHORTREL( &glThreadListLock );
736 while(cur->Status != THREAD_STAT_ACTIVE) {
738 if( cur->Status != THREAD_STAT_ACTIVE )
739 Log("%i - Huh? why am I up? zzzz...", cur->TID);
745 * \brief Wakes a sleeping/waiting thread up
746 * \param Thread Thread to wake
747 * \return Boolean Failure (Returns ERRNO)
748 * \warning This should ONLY be called with task switches disabled
750 int Threads_Wake(tThread *Thread)
755 switch(Thread->Status)
757 case THREAD_STAT_ACTIVE:
758 Log("Threads_Wake - Waking awake thread (%i)", Thread->TID);
761 case THREAD_STAT_SLEEPING:
762 SHORTLOCK( &glThreadListLock );
763 // Remove from sleeping queue
764 Threads_int_DelFromQueue(&gSleepingThreads, Thread);
766 SHORTREL( &glThreadListLock );
767 Threads_AddActive( Thread );
769 #if DEBUG_TRACE_STATE
770 Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName);
774 case THREAD_STAT_SEMAPHORESLEEP: {
776 tThread *th, *prev=NULL;
778 sem = Thread->WaitPointer;
780 SHORTLOCK( &sem->Protector );
782 // Remove from sleeping queue
783 for( th = sem->Waiting; th; prev = th, th = th->Next )
784 if( th == Thread ) break;
788 prev->Next = Thread->Next;
790 sem->Waiting = Thread->Next;
791 if(sem->LastWaiting == Thread)
792 sem->LastWaiting = prev;
797 for( th = sem->Signaling; th; prev = th, th = th->Next )
798 if( th == Thread ) break;
800 Log_Warning("Threads", "Thread %p(%i %s) is not on semaphore %p(%s:%s)",
801 Thread, Thread->TID, Thread->ThreadName,
802 sem, sem->ModName, sem->Name);
807 prev->Next = Thread->Next;
809 sem->Signaling = Thread->Next;
810 if(sem->LastSignaling == Thread)
811 sem->LastSignaling = prev;
814 Thread->RetStatus = 0; // It didn't get anything
815 Threads_AddActive( Thread );
817 #if DEBUG_TRACE_STATE
818 Log("Threads_Sleep: %p(%i %s) woken from semaphore", Thread, Thread->TID, Thread->ThreadName);
820 SHORTREL( &sem->Protector );
823 case THREAD_STAT_WAITING:
824 Warning("Threads_Wake - Waiting threads are not currently supported");
827 case THREAD_STAT_DEAD:
828 Warning("Threads_Wake - Attempt to wake dead thread (%i)", Thread->TID);
832 Warning("Threads_Wake - Unknown process status (%i)\n", Thread->Status);
838 * \brief Wake a thread given the TID
839 * \param TID Thread ID to wake
840 * \return Boolean Faulure (errno)
842 int Threads_WakeTID(tTID TID)
844 tThread *thread = Threads_GetThread(TID);
848 ret = Threads_Wake( thread );
849 //Log_Debug("Threads", "TID %i woke %i (%p)", Threads_GetTID(), TID, thread);
853 void Threads_ToggleTrace(int TID)
855 tThread *thread = Threads_GetThread(TID);
857 thread->bInstrTrace = !thread->bInstrTrace;
861 * \brief Adds a thread to the active queue
863 void Threads_AddActive(tThread *Thread)
865 SHORTLOCK( &glThreadListLock );
867 if( Thread->Status == THREAD_STAT_ACTIVE ) {
868 tThread *cur = Proc_GetCurThread();
869 Log_Warning("Threads", "WTF, %p CPU%i %p (%i %s) is adding %p (%i %s) when it is active",
870 __builtin_return_address(0),
871 GetCPUNum(), cur, cur->TID, cur->ThreadName, Thread, Thread->TID, Thread->ThreadName);
872 SHORTREL( &glThreadListLock );
877 Thread->Status = THREAD_STAT_ACTIVE;
878 // Thread->CurCPU = -1;
879 // Add to active list
881 #if SCHEDULER_TYPE == SCHED_RR_PRI
882 tThreadList *list = &gaActiveThreads[Thread->Priority];
884 tThreadList *list = &gActiveThreads;
886 Threads_int_AddToList( list, Thread );
889 // Update bookkeeping
890 giNumActiveThreads ++;
892 #if SCHEDULER_TYPE == SCHED_LOTTERY
895 // Only change the ticket count if the thread is un-scheduled
896 if(Thread->CurCPU != -1)
899 delta = caiTICKET_COUNTS[ Thread->Priority ];
901 giFreeTickets += delta;
902 # if DEBUG_TRACE_TICKETS
903 Log("CPU%i %p (%i %s) added, new giFreeTickets = %i [+%i]",
904 GetCPUNum(), Thread, Thread->TID, Thread->ThreadName,
911 SHORTREL( &glThreadListLock );
915 * \brief Removes the current thread from the active queue
916 * \warning This should ONLY be called with the lock held
917 * \return Current thread pointer
919 tThread *Threads_RemActive(void)
921 giNumActiveThreads --;
922 return Proc_GetCurThread();
926 * \fn void Threads_SetFaultHandler(Uint Handler)
927 * \brief Sets the signal handler for a signal
929 void Threads_SetFaultHandler(Uint Handler)
931 //Log_Debug("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
932 Proc_GetCurThread()->FaultHandler = Handler;
936 * \fn void Threads_Fault(int Num)
937 * \brief Calls a fault handler
939 void Threads_Fault(int Num)
941 tThread *thread = Proc_GetCurThread();
945 Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
947 switch(thread->FaultHandler)
950 Threads_Kill(thread, -1);
953 case 1: // Dump Core?
954 Threads_Kill(thread, -1);
959 // Double Fault? Oh, F**k
960 if(thread->CurFaultNum != 0) {
961 Log_Warning("Threads", "Threads_Fault: Double fault on %i", thread->TID);
962 Threads_Kill(thread, -1); // For now, just kill
966 thread->CurFaultNum = Num;
968 Proc_CallFaultHandler(thread);
972 * \fn void Threads_SegFault(tVAddr Addr)
973 * \brief Called when a Segment Fault occurs
975 void Threads_SegFault(tVAddr Addr)
977 tThread *cur = Proc_GetCurThread();
978 cur->bInstrTrace = 0;
979 Log_Warning("Threads", "Thread #%i committed a segfault at address %p", cur->TID, Addr);
980 MM_DumpTables(0, USER_MAX);
982 //Threads_Exit( 0, -1 );
985 // --- Process Structure Access Functions ---
986 tPGID Threads_GetPGID(void)
988 return Proc_GetCurThread()->Process->PGID;
990 tPID Threads_GetPID(void)
992 return Proc_GetCurThread()->Process->PID;
994 tTID Threads_GetTID(void)
996 return Proc_GetCurThread()->TID;
998 tUID Threads_GetUID(void)
1000 return Proc_GetCurThread()->Process->UID;
1002 tGID Threads_GetGID(void)
1004 return Proc_GetCurThread()->Process->GID;
1007 int Threads_SetUID(tUID ID)
1009 tThread *t = Proc_GetCurThread();
1010 if( t->Process->UID != 0 ) {
1014 Log_Debug("Threads", "PID %i's UID set to %i", t->Process->PID, ID);
1015 t->Process->UID = ID;
1019 int Threads_SetGID(tGID ID)
1021 tThread *t = Proc_GetCurThread();
1022 if( t->Process->UID != 0 ) {
1026 Log_Debug("Threads", "PID %i's GID set to %i", t->Process->PID, ID);
1027 t->Process->GID = ID;
1031 // --- Per-thread storage ---
1032 int *Threads_GetErrno(void)
1034 return &Proc_GetCurThread()->_errno;
1037 // --- Configuration ---
1038 int *Threads_GetMaxFD(void)
1040 return &Proc_GetCurThread()->Process->MaxFD;
1042 char **Threads_GetChroot(void)
1044 return &Proc_GetCurThread()->Process->RootDir;
1046 char **Threads_GetCWD(void)
1048 return &Proc_GetCurThread()->Process->CurrentWorkingDir;
1053 * \fn void Threads_Dump(void)
1055 void Threads_DumpActive(void)
1059 #if SCHEDULER_TYPE == SCHED_RR_PRI
1063 Log("Active Threads: (%i reported)", giNumActiveThreads);
1065 #if SCHEDULER_TYPE == SCHED_RR_PRI
1066 for( i = 0; i < MIN_PRIORITY+1; i++ )
1068 list = &gaActiveThreads[i];
1070 list = &gActiveThreads;
1072 for(thread=list->Head;thread;thread=thread->Next)
1074 Log(" %p %i (%i) - %s (CPU %i)",
1075 thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
1076 if(thread->Status != THREAD_STAT_ACTIVE)
1077 Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)",
1078 thread->Status, THREAD_STAT_ACTIVE);
1079 Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum);
1080 Log(" KStack 0x%x", thread->KernelStack);
1081 if( thread->bInstrTrace )
1082 Log(" Tracing Enabled");
1083 Proc_DumpThreadCPUState(thread);
1086 #if SCHEDULER_TYPE == SCHED_RR_PRI
1092 * \fn void Threads_Dump(void)
1093 * \brief Dumps a list of currently running threads
1095 void Threads_Dump(void)
1099 Log("--- Thread Dump ---");
1100 Threads_DumpActive();
1102 Log("All Threads:");
1103 for(thread=gAllThreads;thread;thread=thread->GlobalNext)
1105 Log(" %p %i (%i) - %s (CPU %i)",
1106 thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
1107 Log(" State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
1108 switch(thread->Status)
1110 case THREAD_STAT_MUTEXSLEEP:
1111 Log(" Mutex Pointer: %p", thread->WaitPointer);
1113 case THREAD_STAT_SEMAPHORESLEEP:
1114 Log(" Semaphore Pointer: %p", thread->WaitPointer);
1115 Log(" Semaphore Name: %s:%s",
1116 ((tSemaphore*)thread->WaitPointer)->ModName,
1117 ((tSemaphore*)thread->WaitPointer)->Name
1120 case THREAD_STAT_ZOMBIE:
1121 Log(" Return Status: %i", thread->RetStatus);
1125 Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum);
1126 Log(" KStack 0x%x", thread->KernelStack);
1127 if( thread->bInstrTrace )
1128 Log(" Tracing Enabled");
1129 Proc_DumpThreadCPUState(thread);
1134 * \brief Gets the next thread to run
1135 * \param CPU Current CPU
1136 * \param Last The thread the CPU was running
1138 tThread *Threads_GetNextToRun(int CPU, tThread *Last)
1142 // If this CPU has the lock, we must let it complete
1143 if( CPU_HAS_LOCK( &glThreadListLock ) )
1146 // Don't change threads if the current CPU has switches disabled
1147 if( gaThreads_NoTaskSwitch[CPU] )
1151 SHORTLOCK( &glThreadListLock );
1153 // Make sure the current (well, old) thread is marked as de-scheduled
1154 if(Last) Last->CurCPU = -1;
1156 // No active threads, just take a nap
1157 if(giNumActiveThreads == 0) {
1158 SHORTREL( &glThreadListLock );
1159 #if DEBUG_TRACE_TICKETS
1160 Log("No active threads");
1166 #if SCHEDULER_TYPE != SCHED_RR_PRI
1167 // Special case: 1 thread
1168 if(giNumActiveThreads == 1) {
1169 if( gActiveThreads.Head->CurCPU == -1 )
1170 gActiveThreads.Head->CurCPU = CPU;
1172 SHORTREL( &glThreadListLock );
1174 if( gActiveThreads.Head->CurCPU == CPU )
1175 return gActiveThreads.Head;
1177 return NULL; // CPU has nothing to do
1182 // Allow the old thread to be scheduled again
1184 if( Last->Status == THREAD_STAT_ACTIVE ) {
1186 #if SCHEDULER_TYPE == SCHED_LOTTERY
1187 giFreeTickets += caiTICKET_COUNTS[ Last->Priority ];
1188 # if DEBUG_TRACE_TICKETS
1189 LogF("Log: CPU%i released %p (%i %s) into the pool (%i [+%i] tickets in pool)\n",
1190 CPU, Last, Last->TID, Last->ThreadName, giFreeTickets,
1191 caiTICKET_COUNTS[ Last->Priority ]);
1195 #if SCHEDULER_TYPE == SCHED_RR_PRI
1196 list = &gaActiveThreads[ Last->Priority ];
1198 list = &gActiveThreads;
1200 // Add to end of list
1201 Threads_int_AddToList( list, Last );
1203 #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
1205 LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released,not in pool)\n",
1206 CPU, Last, Last->TID, Last->ThreadName, Last->Status);
1212 // Lottery Scheduler
1214 #if SCHEDULER_TYPE == SCHED_LOTTERY
1219 for(thread = gActiveThreads.Head; thread; thread = thread->Next)
1221 if(thread->Status != THREAD_STAT_ACTIVE)
1222 Panic("Bookkeeping fail - %p %i(%s) is on the active queue with a status of %i",
1223 thread, thread->TID, thread->ThreadName, thread->Status);
1224 if(thread->Next == thread) {
1225 Panic("Bookkeeping fail - %p %i(%s) loops back on itself",
1226 thread, thread->TID, thread->ThreadName, thread->Status);
1228 number += caiTICKET_COUNTS[ thread->Priority ];
1230 if(number != giFreeTickets) {
1231 Panic("Bookkeeping fail (giFreeTickets(%i) != number(%i)) - CPU%i",
1232 giFreeTickets, number, CPU);
1236 // No free tickets (all tasks delegated to cores)
1237 if( giFreeTickets == 0 ) {
1238 SHORTREL(&glThreadListLock);
1242 // Get the ticket number
1243 ticket = number = rand() % giFreeTickets;
1245 // Find the next thread
1246 for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
1248 if( caiTICKET_COUNTS[ thread->Priority ] > number) break;
1249 number -= caiTICKET_COUNTS[ thread->Priority ];
1252 // If we didn't find a thread, something went wrong
1256 for(thread=gActiveThreads;thread;thread=thread->Next) {
1257 if(thread->CurCPU >= 0) continue;
1258 number += caiTICKET_COUNTS[ thread->Priority ];
1260 Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
1261 giFreeTickets, number);
1266 prev->Next = thread->Next;
1268 gActiveThreads.Head = thread->Next;
1270 gActiveThreads.Tail = prev;
1272 giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ];
1273 # if DEBUG_TRACE_TICKETS
1274 LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n",
1275 CPU, thread, thread->TID, thread->ThreadName,
1276 giFreeTickets, caiTICKET_COUNTS[ thread->Priority ]);
1281 // Priority based round robin scheduler
1283 #elif SCHEDULER_TYPE == SCHED_RR_PRI
1287 for( i = 0; i < MIN_PRIORITY + 1; i ++ )
1289 if( !gaActiveThreads[i].Head )
1292 thread = gaActiveThreads[i].Head;
1295 gaActiveThreads[i].Head = thread->Next;
1297 gaActiveThreads[i].Tail = NULL;
1298 thread->Next = NULL;
1304 SHORTREL(&glThreadListLock);
1307 if( thread->Status != THREAD_STAT_ACTIVE ) {
1308 LogF("Oops, Thread %i (%s) is not active\n", thread->TID, thread->ThreadName);
1311 #elif SCHEDULER_TYPE == SCHED_RR_SIM
1313 // Get the next thread off the list
1314 thread = gActiveThreads.Head;
1315 gActiveThreads.Head = thread->Next;
1317 gaActiveThreads.Tail = NULL;
1318 thread->Next = NULL;
1322 SHORTREL(&glThreadListLock);
1327 # error "Unimplemented scheduling algorithm"
1330 // Make the new thread non-schedulable
1331 thread->CurCPU = CPU;
1332 thread->Remaining = thread->Quantum;
1334 SHORTREL( &glThreadListLock );
1340 EXPORT(Threads_GetUID);
1341 EXPORT(Threads_GetGID);