4 * - Common Thread Control
11 #define DEFAULT_QUANTUM 10
12 #define DEFAULT_TICKETS 5
13 #define MAX_TICKETS 10
14 const enum eConfigTypes cCONFIG_TYPES[] = {
15 CFGT_HEAPSTR, // CFG_VFS_CWD
16 CFGT_INT, // CFG_VFS_MAXFILES
21 extern void ArchThreads_Init(void);
22 extern void Proc_Start(void);
23 extern tThread *Proc_GetCurThread(void);
24 extern int Proc_Clone(Uint *Err, Uint Flags);
25 extern void Proc_CallFaultHandler(tThread *Thread);
28 void Threads_Init(void);
29 int Threads_SetName(char *NewName);
30 char *Threads_GetName(int ID);
31 void Threads_SetTickets(int Num);
32 tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
33 int Threads_WaitTID(int TID, int *status);
34 tThread *Threads_GetThread(Uint TID);
35 void Threads_AddToDelete(tThread *Thread);
36 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
37 void Threads_Exit(int TID, int Status);
38 void Threads_Kill(tThread *Thread, int Status);
39 void Threads_Yield(void);
40 void Threads_Sleep(void);
41 void Threads_Wake(tThread *Thread);
42 void Threads_AddActive(tThread *Thread);
43 int Threads_GetPID(void);
44 int Threads_GetTID(void);
45 tUID Threads_GetUID(void);
46 int Threads_SetUID(Uint *Errno, tUID ID);
47 tGID Threads_GetGID(void);
48 int Threads_SetGID(Uint *Errno, tUID ID);
49 void Threads_Dump(void);
53 tThread gThreadZero = {
54 NULL, 0, // Next, Lock
55 THREAD_STAT_ACTIVE, // Status
59 0, // Parent Thread ID
66 0, 0, // Current Fault, Fault Handler
68 NULL, NULL, // Messages, Last Message
69 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
71 {0} // Default config to zero
75 tSpinlock glThreadListLock = 0; ///\note NEVER use a heap function while locked
76 // --- Current State ---
77 volatile int giNumActiveThreads = 0;
78 volatile int giTotalTickets = 0;
79 volatile Uint giNextTID = 1;
80 // --- Thread Lists ---
81 tThread *gActiveThreads = NULL; // Currently Running Threads
82 tThread *gSleepingThreads = NULL; // Sleeping Threads
83 tThread *gDeleteThreads = NULL; // Threads to delete
88 * \fn void Threads_Init(void)
89 * \brief Initialse the thread list
91 void Threads_Init(void)
95 // Create Initial Task
96 gActiveThreads = &gThreadZero;
97 giTotalTickets = gThreadZero.NumTickets;
98 giNumActiveThreads = 1;
102 if(Proc_Clone(0, 0) == 0)
104 tThread *cur = Proc_GetCurThread();
105 cur->ThreadName = "Idle Thread";
106 Threads_SetTickets(0); // Never called randomly
107 cur->Quantum = 1; // 1 slice quantum
108 for(;;) HALT(); // Just yeilds
116 * \fn void Threads_SetName(char *NewName)
117 * \brief Sets the current thread's name
119 int Threads_SetName(char *NewName)
121 tThread *cur = Proc_GetCurThread();
122 if( IsHeap(cur->ThreadName) )
123 free( cur->ThreadName );
124 cur->ThreadName = malloc(strlen(NewName)+1);
125 strcpy(cur->ThreadName, NewName);
130 * \fn char *Threads_GetName(int ID)
131 * \brief Gets a thread's name
133 char *Threads_GetName(int ID)
136 return Proc_GetCurThread()->ThreadName;
142 * \fn void Threads_SetTickets(int Num)
143 * \brief Sets the 'priority' of a task
145 void Threads_SetTickets(int Num)
147 tThread *cur = Proc_GetCurThread();
149 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
151 LOCK( &glThreadListLock );
152 giTotalTickets -= cur->NumTickets;
153 cur->NumTickets = Num;
154 giTotalTickets += Num;
155 //LOG("giTotalTickets = %i", giTotalTickets);
156 RELEASE( &glThreadListLock );
160 * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
162 tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
166 cur = Proc_GetCurThread();
168 new = malloc(sizeof(tThread));
173 memcpy(new, cur, sizeof(tThread));
177 new->Status = THREAD_STAT_ACTIVE;
181 new->TID = giNextTID++;
182 new->PTID = cur->TID;
185 new->ThreadName = strdup(cur->ThreadName);
187 // Set Thread Group ID (PID)
189 new->TGID = new->TID;
191 new->TGID = cur->TGID;
193 // Messages are not inherited
194 new->Messages = NULL;
195 new->LastMessage = NULL;
198 new->Remaining = new->Quantum = cur->Quantum;
199 new->NumTickets = cur->NumTickets;
201 // Set Signal Handlers
202 new->CurFaultNum = 0;
203 new->FaultHandler = cur->FaultHandler;
205 for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
207 switch(cCONFIG_TYPES[i])
210 new->Config[i] = cur->Config[i];
214 new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
225 * \fn Uint *Threads_GetCfgPtr(int Id)
227 Uint *Threads_GetCfgPtr(int Id)
229 if(Id < 0 || Id >= NUM_CFG_ENTRIES) {
230 Warning("Threads_GetCfgPtr: Index %i is out of bounds", Id);
234 return &Proc_GetCurThread()->Config[Id];
238 * \fn void Threads_WaitTID(int TID, int *status)
239 * \brief Wait for a task to change state
241 int Threads_WaitTID(int TID, int *status)
249 // Any peer/child thread
262 tThread *t = Threads_GetThread(TID);
263 int initStatus = t->Status;
266 if(initStatus != THREAD_STAT_ZOMBIE) {
267 while(t->Status == initStatus) {
275 case THREAD_STAT_ZOMBIE:
276 t->Status = THREAD_STAT_DEAD;
277 if(status) *status = 0;
278 Threads_AddToDelete( t );
281 if(status) *status = -1;
291 * \fn tThread *Threads_GetThread(Uint TID)
292 * \brief Gets a thread given its TID
294 tThread *Threads_GetThread(Uint TID)
298 // Search Active List
299 for(thread = gActiveThreads;
301 thread = thread->Next)
303 if(thread->TID == TID)
307 // Search Sleeping List
308 for(thread = gSleepingThreads;
310 thread = thread->Next)
312 if(thread->TID == TID)
320 * \fn void Threads_AddToDelete(tThread *Thread)
321 * \brief Adds a thread to the delete queue
323 void Threads_AddToDelete(tThread *Thread)
325 // Add to delete queue
327 Thread->Next = gDeleteThreads;
328 gDeleteThreads = Thread;
331 gDeleteThreads = Thread;
336 * \fn tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
337 * \brief Gets the previous entry in a thead linked list
339 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
343 if(*List == Thread) {
344 return (tThread*)List;
347 ret->Next && ret->Next != Thread;
350 // Error if the thread is not on the list
351 if(!ret->Next || ret->Next != Thread) {
359 * \fn void Threads_Exit(int TID, int Status)
360 * \brief Exit the current process
362 void Threads_Exit(int TID, int Status)
365 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
367 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
368 for(;;) HALT(); // Just in case
372 * \fn void Threads_Kill(tThread *Thread, int Status)
373 * \brief Kill a thread
374 * \param Thread Thread to kill
375 * \param Status Status code to return to the parent
377 void Threads_Kill(tThread *Thread, int Status)
386 for(child = gActiveThreads;
390 if(child->PTID == Thread->TID)
391 Threads_Kill(child, -1);
396 ///\note Double lock is needed due to overlap of locks
398 // Lock thread (stop us recieving messages)
399 LOCK( &Thread->IsLocked );
402 LOCK( &glThreadListLock );
404 // Get previous thread on list
405 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
407 Warning("Proc_Exit - Current thread is not on the active queue");
411 // Clear Message Queue
412 while( Thread->Messages )
414 msg = Thread->Messages->Next;
415 free( Thread->Messages );
416 Thread->Messages = msg;
419 Thread->Remaining = 0; // Clear Remaining Quantum
420 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
421 prev->Next = Thread->Next; // Remove from active
423 giNumActiveThreads --;
424 giTotalTickets -= Thread->NumTickets;
426 // Mark thread as a zombie
427 Thread->RetStatus = Status;
429 // Don't Zombie if we are being killed as part of a tree
432 Thread->Status = THREAD_STAT_DEAD;
433 Threads_AddToDelete( Thread );
435 Thread->Status = THREAD_STAT_ZOMBIE;
439 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
440 RELEASE( &glThreadListLock );
442 //Log("Thread %i went *hurk*", Thread->TID);
444 if(Status != -1) HALT();
448 * \fn void Threads_Yield(void)
449 * \brief Yield remainder of timeslice
451 void Threads_Yield(void)
453 Proc_GetCurThread()->Remaining = 0;
458 * \fn void Threads_Sleep(void)
459 * \brief Take the current process off the run queue
461 void Threads_Sleep(void)
463 tThread *cur = Proc_GetCurThread();
466 //Log_Log("Threads", "%i going to sleep", cur->TID);
469 LOCK( &glThreadListLock );
471 // Get thread before current thread
472 thread = Threads_int_GetPrev( &gActiveThreads, cur );
474 Warning("Threads_Sleep - Current thread is not on the active queue");
479 // Don't sleep if there is a message waiting
480 if( cur->Messages ) {
481 RELEASE( &glThreadListLock );
485 // Unset remaining timeslices (force a task switch on timer fire)
488 // Remove from active list
489 thread->Next = cur->Next;
491 // Add to Sleeping List (at the top)
492 cur->Next = gSleepingThreads;
493 gSleepingThreads = cur;
495 // Reduce the active count & ticket count
496 giNumActiveThreads --;
497 giTotalTickets -= cur->NumTickets;
499 // Mark thread as sleeping
500 cur->Status = THREAD_STAT_SLEEPING;
503 RELEASE( &glThreadListLock );
505 while(cur->Status != THREAD_STAT_ACTIVE) HALT();
510 * \fn void Threads_Wake( tThread *Thread )
511 * \brief Wakes a sleeping/waiting thread up
513 void Threads_Wake(tThread *Thread)
516 switch(Thread->Status)
518 case THREAD_STAT_ACTIVE: break;
519 case THREAD_STAT_SLEEPING:
520 //Log_Log("Threads", "Waking %i (%p) from sleeping", Thread->TID, Thread);
521 LOCK( &glThreadListLock );
522 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
523 prev->Next = Thread->Next; // Remove from sleeping queue
524 Thread->Next = gActiveThreads; // Add to active queue
525 gActiveThreads = Thread;
526 giNumActiveThreads ++;
527 giTotalTickets += Thread->NumTickets;
528 Thread->Status = THREAD_STAT_ACTIVE;
529 RELEASE( &glThreadListLock );
531 case THREAD_STAT_WAITING:
532 Warning("Thread_Wake - Waiting threads are not currently supported");
534 case THREAD_STAT_DEAD:
535 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
538 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
543 void Threads_WakeTID(tTID Thread)
545 Threads_Wake( Threads_GetThread(Thread) );
549 * \fn void Threads_AddActive(tThread *Thread)
550 * \brief Adds a thread to the active queue
552 void Threads_AddActive(tThread *Thread)
554 LOCK( &glThreadListLock );
555 Thread->Next = gActiveThreads;
556 gActiveThreads = Thread;
557 giNumActiveThreads ++;
558 giTotalTickets += Thread->NumTickets;
559 //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
560 // giNumActiveThreads, giTotalTickets);
561 RELEASE( &glThreadListLock );
565 * \fn void Threads_SetFaultHandler(Uint Handler)
566 * \brief Sets the signal handler for a signal
568 void Threads_SetFaultHandler(Uint Handler)
570 Log_Log("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
571 Proc_GetCurThread()->FaultHandler = Handler;
575 * \fn void Threads_Fault(int Num)
576 * \brief Calls a fault handler
578 void Threads_Fault(int Num)
580 tThread *thread = Proc_GetCurThread();
582 Log_Log("Threads", "Threads_Fault: thread = %p", thread);
586 Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
588 switch(thread->FaultHandler)
591 Threads_Kill(thread, -1);
594 case 1: // Dump Core?
595 Threads_Kill(thread, -1);
600 // Double Fault? Oh, F**k
601 if(thread->CurFaultNum != 0) {
602 Threads_Kill(thread, -1); // For now, just kill
606 thread->CurFaultNum = Num;
608 Proc_CallFaultHandler(thread);
611 // --- Process Structure Access Functions ---
612 tPID Threads_GetPID(void)
614 return Proc_GetCurThread()->TGID;
616 tTID Threads_GetTID(void)
618 return Proc_GetCurThread()->TID;
620 tUID Threads_GetUID(void)
622 return Proc_GetCurThread()->UID;
624 tGID Threads_GetGID(void)
626 return Proc_GetCurThread()->GID;
629 int Threads_SetUID(Uint *Errno, tUID ID)
631 tThread *t = Proc_GetCurThread();
636 Log("Threads_SetUID - Setting User ID to %i", ID);
641 int Threads_SetGID(Uint *Errno, tGID ID)
643 tThread *t = Proc_GetCurThread();
648 Log("Threads_SetGID - Setting Group ID to %i", ID);
654 * \fn void Threads_Dump(void)
655 * \brief Dums a list of currently running threads
657 void Threads_Dump(void)
660 tThread *cur = Proc_GetCurThread();
662 Log("Active Threads:");
663 for(thread=gActiveThreads;thread;thread=thread->Next)
665 Log("%c%i (%i) - %s",
666 (thread==cur?'*':' '),
667 thread->TID, thread->TGID, thread->ThreadName);
668 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
669 Log(" KStack 0x%x", thread->KernelStack);
671 Log("Sleeping Threads:");
672 for(thread=gSleepingThreads;thread;thread=thread->Next)
674 Log("%c%i (%i) - %s",
675 (thread==cur?'*':' '),
676 thread->TID, thread->TGID, thread->ThreadName);
677 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
678 Log(" KStack 0x%x", thread->KernelStack);
683 * \fn tThread *Threads_GetNextToRun(int CPU)
684 * \brief Gets the next thread to run
686 tThread *Threads_GetNextToRun(int CPU)
692 if(giNumActiveThreads == 0) {
696 // Special case: 1 thread
697 if(giNumActiveThreads == 1) {
698 return gActiveThreads;
701 // Get the ticket number
702 ticket = number = rand() % giTotalTickets;
704 // Find the next thread
705 for(thread=gActiveThreads;thread;thread=thread->Next)
707 if(thread->NumTickets > number) break;
708 number -= thread->NumTickets;
715 for(thread=gActiveThreads;thread;thread=thread->Next)
716 number += thread->NumTickets;
717 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
718 giTotalTickets, number);
725 * \fn void Threads_SegFault(tVAddr Addr)
726 * \brief Called when a Segment Fault occurs
728 void Threads_SegFault(tVAddr Addr)
730 Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
732 //Threads_Exit( 0, -1 );
736 EXPORT(Threads_GetUID);