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();
22 extern void Proc_Start();
23 extern tThread *Proc_GetCurThread();
24 extern int Proc_Clone(Uint *Err, Uint Flags);
28 void Threads_SetName(char *NewName);
29 char *Threads_GetName(int ID);
30 void Threads_SetTickets(int Num);
31 tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
32 int Threads_WaitTID(int TID, int *status);
33 tThread *Threads_GetThread(Uint TID);
34 void Threads_AddToDelete(tThread *Thread);
35 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
36 void Threads_Exit(int TID, int Status);
37 void Threads_Kill(tThread *Thread, int Status);
40 void Threads_Wake(tThread *Thread);
41 void Threads_AddActive(tThread *Thread);
44 tUID Threads_GetUID();
45 int Threads_SetUID(Uint *Errno, tUID ID);
46 tGID Threads_GetGID();
47 int Threads_SetGID(Uint *Errno, tUID ID);
52 tThread gThreadZero = {
53 NULL, 0, // Next, Lock
54 THREAD_STAT_ACTIVE, // Status
58 0, // Parent Thread ID
65 0, {0}, {0}, // Signal State
67 NULL, NULL, // Messages, Last Message
68 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
70 {0} // Default config to zero
74 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
75 // --- Current State ---
76 volatile int giNumActiveThreads = 0;
77 volatile int giTotalTickets = 0;
78 volatile Uint giNextTID = 1;
79 // --- Thread Lists ---
80 tThread *gActiveThreads = NULL; // Currently Running Threads
81 tThread *gSleepingThreads = NULL; // Sleeping Threads
82 tThread *gDeleteThreads = NULL; // Threads to delete
87 * \fn void Threads_Init()
88 * \brief Initialse the thread list
94 // Create Initial Task
95 gActiveThreads = &gThreadZero;
96 giTotalTickets = gThreadZero.NumTickets;
97 giNumActiveThreads = 1;
101 if(Proc_Clone(0, 0) == 0)
103 tThread *cur = Proc_GetCurThread();
104 cur->ThreadName = "Idle Thread";
105 Threads_SetTickets(0); // Never called randomly
106 cur->Quantum = 1; // 1 slice quantum
109 HALT(); // Just yeilds
118 * \fn void Threads_SetName(char *NewName)
119 * \brief Sets the current thread's name
121 void Threads_SetName(char *NewName)
123 tThread *cur = Proc_GetCurThread();
124 if( IsHeap(cur->ThreadName) )
125 free( cur->ThreadName );
126 cur->ThreadName = malloc(strlen(NewName)+1);
127 strcpy(cur->ThreadName, NewName);
131 * \fn char *Threads_GetName(int ID)
132 * \brief Gets a thread's name
134 char *Threads_GetName(int ID)
137 return Proc_GetCurThread()->ThreadName;
143 * \fn void Threads_SetTickets(int Num)
144 * \brief Sets the 'priority' of a task
146 void Threads_SetTickets(int Num)
148 tThread *cur = Proc_GetCurThread();
150 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
152 LOCK( &giThreadListLock );
153 giTotalTickets -= cur->NumTickets;
154 cur->NumTickets = Num;
155 giTotalTickets += Num;
156 //LOG("giTotalTickets = %i", giTotalTickets);
157 RELEASE( &giThreadListLock );
161 * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
163 tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
167 cur = Proc_GetCurThread();
169 new = malloc(sizeof(tThread));
177 new->Status = THREAD_STAT_ACTIVE;
181 new->TID = giNextTID++;
182 new->PTID = cur->TID;
185 new->ThreadName = malloc(strlen(cur->ThreadName)+1);
186 strcpy(new->ThreadName, cur->ThreadName);
188 // Set Thread Group ID (PID)
190 new->TGID = new->TID;
192 new->TGID = cur->TGID;
194 // Messages are not inherited
195 new->Messages = NULL;
196 new->LastMessage = NULL;
199 new->Remaining = new->Quantum = cur->Quantum;
200 new->NumTickets = cur->NumTickets;
202 // Set Signal Handlers
205 memset(new->SignalHandlers, 0, sizeof(new->SignalHandlers));
207 memcpy(new->SignalHandlers, cur->SignalHandlers, sizeof(new->SignalHandlers));
208 memset(&new->SignalState, 0, sizeof(tTaskState));
210 for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
212 switch(cCONFIG_TYPES[i])
215 new->Config[i] = cur->Config[i];
219 new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
230 * \fn Uint *Threads_GetCfgPtr(int Id)
232 Uint *Threads_GetCfgPtr(int Id)
234 if(Id < 0 || Id >= NUM_CFG_ENTRIES) {
235 Warning("Threads_GetCfgPtr: Index %i is out of bounds", Id);
239 return &Proc_GetCurThread()->Config[Id];
243 * \fn void Threads_WaitTID(int TID, int *status)
244 * \brief Wait for a task to change state
246 int Threads_WaitTID(int TID, int *status)
254 // Any peer/child thread
267 tThread *t = Threads_GetThread(TID);
268 int initStatus = t->Status;
271 if(initStatus != THREAD_STAT_ZOMBIE)
272 while(t->Status == initStatus) {
279 case THREAD_STAT_ZOMBIE:
280 t->Status = THREAD_STAT_DEAD;
281 if(status) *status = 0;
282 Threads_AddToDelete( t );
285 if(status) *status = -1;
295 * \fn tThread *Threads_GetThread(Uint TID)
296 * \brief Gets a thread given its TID
298 tThread *Threads_GetThread(Uint TID)
302 // Search Active List
303 for(thread = gActiveThreads;
305 thread = thread->Next)
307 if(thread->TID == TID)
311 // Search Sleeping List
312 for(thread = gSleepingThreads;
314 thread = thread->Next)
316 if(thread->TID == TID)
324 * \fn void Threads_AddToDelete(tThread *Thread)
325 * \brief Adds a thread to the delete queue
327 void Threads_AddToDelete(tThread *Thread)
329 // Add to delete queue
331 Thread->Next = gDeleteThreads;
332 gDeleteThreads = Thread;
335 gDeleteThreads = Thread;
340 * \fn tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
341 * \brief Gets the previous entry in a thead linked list
343 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
347 if(*List == Thread) {
348 return (tThread*)List;
351 ret->Next && ret->Next != Thread;
354 // Error if the thread is not on the list
355 if(!ret->Next || ret->Next != Thread) {
363 * \fn void Threads_Exit(int TID, int Status)
364 * \brief Exit the current process
366 void Threads_Exit(int TID, int Status)
369 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
371 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
372 for(;;) HALT(); // Just in case
376 * \fn void Threads_Kill(tThread *Thread, int Status)
377 * \brief Kill a thread
378 * \param Thread Thread to kill
379 * \param Status Status code to return to the parent
381 void Threads_Kill(tThread *Thread, int Status)
390 for(child = gActiveThreads;
394 if(child->PTID == Thread->TID)
395 Threads_Kill(child, -1);
400 ///\note Double lock is needed due to overlap of locks
402 // Lock thread (stop us recieving messages)
403 LOCK( &Thread->IsLocked );
406 LOCK( &giThreadListLock );
408 // Get previous thread on list
409 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
411 Warning("Proc_Exit - Current thread is not on the active queue");
415 // Clear Message Queue
416 while( Thread->Messages )
418 msg = Thread->Messages->Next;
419 free( Thread->Messages );
420 Thread->Messages = msg;
423 Thread->Remaining = 0; // Clear Remaining Quantum
424 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
425 prev->Next = Thread->Next; // Remove from active
427 giNumActiveThreads --;
428 giTotalTickets -= Thread->NumTickets;
430 // Mark thread as a zombie
431 Thread->RetStatus = Status;
433 // Don't Zombie if we are being killed as part of a tree
436 Thread->Status = THREAD_STAT_DEAD;
437 Threads_AddToDelete( Thread );
439 Thread->Status = THREAD_STAT_ZOMBIE;
443 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
444 RELEASE( &giThreadListLock );
446 //Log("Thread %i went *hurk*", Thread->TID);
448 if(Status != -1) HALT();
452 * \fn void Threads_Yield()
453 * \brief Yield remainder of timeslice
457 Proc_GetCurThread()->Remaining = 0;
462 * \fn void Threads_Sleep()
463 * \brief Take the current process off the run queue
467 tThread *cur = Proc_GetCurThread();
470 Log("Proc_Sleep: %i going to sleep", cur->TID);
473 LOCK( &giThreadListLock );
475 // Get thread before current thread
476 thread = Threads_int_GetPrev( &gActiveThreads, cur );
478 Warning("Threads_Sleep - Current thread is not on the active queue");
483 // Don't sleep if there is a message waiting
484 if( cur->Messages ) {
485 RELEASE( &giThreadListLock );
489 // Unset remaining timeslices (force a task switch on timer fire)
492 // Remove from active list
493 thread->Next = cur->Next;
495 // Add to Sleeping List (at the top)
496 cur->Next = gSleepingThreads;
497 gSleepingThreads = cur;
499 // Reduce the active count & ticket count
500 giNumActiveThreads --;
501 giTotalTickets -= cur->NumTickets;
503 // Mark thread as sleeping
504 cur->Status = THREAD_STAT_SLEEPING;
507 RELEASE( &giThreadListLock );
509 while(cur->Status != THREAD_STAT_ACTIVE) HALT();
514 * \fn void Threads_Wake( tThread *Thread )
515 * \brief Wakes a sleeping/waiting thread up
517 void Threads_Wake(tThread *Thread)
520 switch(Thread->Status)
522 case THREAD_STAT_ACTIVE: break;
523 case THREAD_STAT_SLEEPING:
524 LOCK( &giThreadListLock );
525 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
526 prev->Next = Thread->Next; // Remove from sleeping queue
527 Thread->Next = gActiveThreads; // Add to active queue
528 gActiveThreads = Thread;
529 Thread->Status = THREAD_STAT_ACTIVE;
530 RELEASE( &giThreadListLock );
532 case THREAD_STAT_WAITING:
533 Warning("Thread_Wake - Waiting threads are not currently supported");
535 case THREAD_STAT_DEAD:
536 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
539 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
545 * \fn void Threads_AddActive(tThread *Thread)
546 * \brief Adds a thread to the active queue
548 void Threads_AddActive(tThread *Thread)
550 LOCK( &giThreadListLock );
551 Thread->Next = gActiveThreads;
552 gActiveThreads = Thread;
553 giNumActiveThreads ++;
554 giTotalTickets += Thread->NumTickets;
555 //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
556 // giNumActiveThreads, giTotalTickets);
557 RELEASE( &giThreadListLock );
562 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
563 * \brief Sets the signal handler for a signal
565 void Threads_SetSignalHandler(int Num, void *Handler)
567 if(Num < 0 || Num >= NSIG) return;
569 gCurrentThread->SignalHandlers[Num] = Handler;
573 * \fn void Threads_SendSignal(int TID, int Num)
574 * \brief Send a signal to a thread
576 void Threads_SendSignal(int TID, int Num)
578 tThread *thread = Proc_GetThread(TID);
583 handler = thread->SignalHandlers[Num];
586 if(handler == SIG_ERR) {
596 if(handler == -2) return;
598 // Check the type and handle if the thread is already in a signal
599 if(thread->CurSignal != 0) {
600 if(Num < _SIGTYPE_FATAL)
603 while(thread->CurSignal != 0)
612 // --- Process Structure Access Functions ---
615 return Proc_GetCurThread()->TGID;
619 return Proc_GetCurThread()->TID;
621 tUID Threads_GetUID()
623 return Proc_GetCurThread()->UID;
625 tGID Threads_GetGID()
627 return Proc_GetCurThread()->GID;
630 int Threads_SetUID(Uint *Errno, tUID ID)
632 tThread *t = Proc_GetCurThread();
637 Log("Threads_SetUID - Setting User ID to %i", ID);
642 int Threads_SetGID(Uint *Errno, tGID ID)
644 tThread *t = Proc_GetCurThread();
649 Log("Threads_SetGID - Setting Group ID to %i", ID);
655 * \fn void Threads_Dump()
656 * \brief Dums a list of currently running threads
661 tThread *cur = Proc_GetCurThread();
663 Log("Active Threads:");
664 for(thread=gActiveThreads;thread;thread=thread->Next)
666 Log("%c%i (%i) - %s",
667 (thread==cur?'*':' '),
668 thread->TID, thread->TGID, thread->ThreadName);
669 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
670 Log(" KStack 0x%x", thread->KernelStack);
672 Log("Sleeping Threads:");
673 for(thread=gSleepingThreads;thread;thread=thread->Next)
675 Log("%c%i (%i) - %s",
676 (thread==cur?'*':' '),
677 thread->TID, thread->TGID, thread->ThreadName);
678 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
679 Log(" KStack 0x%x", thread->KernelStack);
684 * \fn tThread *Threads_GetNextToRun(int CPU)
685 * \brief Gets the next thread to run
687 tThread *Threads_GetNextToRun(int CPU)
693 if(giNumActiveThreads == 0) return NULL;
695 // Special case: 1 thread
696 if(giNumActiveThreads == 1) {
697 return gActiveThreads;
700 //Log(" Threads_GetNextToRun: giNumActiveThreads=%i,giTotalTickets=%i",
701 // giNumActiveThreads, giTotalTickets);
702 // Get the ticket number
703 ticket = number = rand() % giTotalTickets;
705 //Log(" Threads_GetNextToRun: ticket = %i", ticket);
707 // Find the next thread
708 for(thread=gActiveThreads;thread;thread=thread->Next)
710 if(thread->NumTickets > number) break;
711 number -= thread->NumTickets;
718 for(thread=gActiveThreads;thread;thread=thread->Next)
719 number += thread->NumTickets;
720 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
721 giTotalTickets, number);
728 * \fn void Threads_SegFault(tVAddr Addr)
729 * \brief Called when a Segment Fault occurs
731 void Threads_SegFault(tVAddr Addr)
733 //Threads_SendSignal( Proc_GetCurThread()->TID, SIGSEGV );
734 Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
735 Threads_Exit( 0, -1 );
739 EXPORT(Threads_GetUID);