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);
50 tThread gThreadZero = {
51 NULL, 0, // Next, Lock
52 THREAD_STAT_ACTIVE, // Status
56 0, // Parent Thread ID
63 0, {0}, {0}, // Signal State
65 NULL, NULL, // Messages, Last Message
66 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
68 {0} // Default config to zero
72 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
73 // --- Current State ---
74 volatile int giNumActiveThreads = 0;
75 volatile int giTotalTickets = 0;
76 volatile Uint giNextTID = 1;
77 // --- Thread Lists ---
78 tThread *gActiveThreads = NULL; // Currently Running Threads
79 tThread *gSleepingThreads = NULL; // Sleeping Threads
80 tThread *gDeleteThreads = NULL; // Threads to delete
85 * \fn void Threads_Init()
86 * \brief Initialse the thread list
92 // Create Initial Task
93 gActiveThreads = &gThreadZero;
94 giTotalTickets = gThreadZero.NumTickets;
95 giNumActiveThreads = 1;
99 if(Proc_Clone(0, 0) == 0)
101 tThread *cur = Proc_GetCurThread();
102 cur->ThreadName = "Idle Thread";
103 Threads_SetTickets(0); // Never called randomly
104 cur->Quantum = 1; // 1 slice quantum
107 HALT(); // Just yeilds
116 * \fn void Threads_SetName(char *NewName)
117 * \brief Sets the current thread's name
119 void 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);
129 * \fn char *Threads_GetName(int ID)
130 * \brief Gets a thread's name
132 char *Threads_GetName(int ID)
135 return Proc_GetCurThread()->ThreadName;
141 * \fn void Threads_SetTickets(int Num)
142 * \brief Sets the 'priority' of a task
144 void Threads_SetTickets(int Num)
146 tThread *cur = Proc_GetCurThread();
148 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
150 LOCK( &giThreadListLock );
151 giTotalTickets -= cur->NumTickets;
152 cur->NumTickets = Num;
153 giTotalTickets += Num;
154 //LOG("giTotalTickets = %i", giTotalTickets);
155 RELEASE( &giThreadListLock );
159 * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
161 tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
165 cur = Proc_GetCurThread();
167 new = malloc(sizeof(tThread));
175 new->Status = THREAD_STAT_ACTIVE;
179 new->TID = giNextTID++;
180 new->PTID = cur->TID;
183 new->ThreadName = malloc(strlen(cur->ThreadName)+1);
184 strcpy(new->ThreadName, cur->ThreadName);
186 // Set Thread Group ID (PID)
188 new->TGID = new->TID;
190 new->TGID = cur->TGID;
192 // Messages are not inherited
193 new->Messages = NULL;
194 new->LastMessage = NULL;
197 new->Remaining = new->Quantum = cur->Quantum;
198 new->NumTickets = cur->NumTickets;
200 // Set Signal Handlers
203 memset(new->SignalHandlers, 0, sizeof(new->SignalHandlers));
205 memcpy(new->SignalHandlers, cur->SignalHandlers, sizeof(new->SignalHandlers));
206 memset(&new->SignalState, 0, sizeof(tTaskState));
208 for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
210 switch(cCONFIG_TYPES[i])
213 new->Config[i] = cur->Config[i];
217 new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
228 * \fn Uint *Threads_GetCfgPtr(int Id)
230 Uint *Threads_GetCfgPtr(int Id)
232 if(Id < 0 || Id >= NUM_CFG_ENTRIES) {
233 Warning("Threads_GetCfgPtr: Index %i is out of bounds", Id);
237 return &Proc_GetCurThread()->Config[Id];
241 * \fn void Threads_WaitTID(int TID, int *status)
242 * \brief Wait for a task to change state
244 int Threads_WaitTID(int TID, int *status)
252 // Any peer/child thread
265 tThread *t = Threads_GetThread(TID);
266 int initStatus = t->Status;
269 if(initStatus != THREAD_STAT_ZOMBIE)
270 while(t->Status == initStatus) {
277 case THREAD_STAT_ZOMBIE:
278 t->Status = THREAD_STAT_DEAD;
279 if(status) *status = 0;
280 Threads_AddToDelete( t );
283 if(status) *status = -1;
293 * \fn tThread *Threads_GetThread(Uint TID)
294 * \brief Gets a thread given its TID
296 tThread *Threads_GetThread(Uint TID)
300 // Search Active List
301 for(thread = gActiveThreads;
303 thread = thread->Next)
305 if(thread->TID == TID)
309 // Search Sleeping List
310 for(thread = gSleepingThreads;
312 thread = thread->Next)
314 if(thread->TID == TID)
322 * \fn void Threads_AddToDelete(tThread *Thread)
323 * \brief Adds a thread to the delete queue
325 void Threads_AddToDelete(tThread *Thread)
327 // Add to delete queue
329 Thread->Next = gDeleteThreads;
330 gDeleteThreads = Thread;
333 gDeleteThreads = Thread;
338 * \fn tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
339 * \brief Gets the previous entry in a thead linked list
341 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
345 if(*List == Thread) {
346 return (tThread*)List;
349 ret->Next && ret->Next != Thread;
352 // Error if the thread is not on the list
353 if(!ret->Next || ret->Next != Thread) {
361 * \fn void Threads_Exit(int TID, int Status)
362 * \brief Exit the current process
364 void Threads_Exit(int TID, int Status)
367 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
369 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
370 for(;;) HALT(); // Just in case
374 * \fn void Threads_Kill(tThread *Thread, int Status)
375 * \brief Kill a thread
376 * \param Thread Thread to kill
377 * \param Status Status code to return to the parent
379 void Threads_Kill(tThread *Thread, int Status)
388 for(child = gActiveThreads;
392 if(child->PTID == Thread->TID)
393 Threads_Kill(child, -1);
398 ///\note Double lock is needed due to overlap of locks
400 // Lock thread (stop us recieving messages)
401 LOCK( &Thread->IsLocked );
404 LOCK( &giThreadListLock );
406 // Get previous thread on list
407 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
409 Warning("Proc_Exit - Current thread is not on the active queue");
413 // Clear Message Queue
414 while( Thread->Messages )
416 msg = Thread->Messages->Next;
417 free( Thread->Messages );
418 Thread->Messages = msg;
421 Thread->Remaining = 0; // Clear Remaining Quantum
422 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
423 prev->Next = Thread->Next; // Remove from active
425 giNumActiveThreads --;
426 giTotalTickets -= Thread->NumTickets;
428 // Mark thread as a zombie
429 Thread->RetStatus = Status;
431 // Don't Zombie if we are being killed as part of a tree
434 Thread->Status = THREAD_STAT_DEAD;
435 Threads_AddToDelete( Thread );
437 Thread->Status = THREAD_STAT_ZOMBIE;
441 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
442 RELEASE( &giThreadListLock );
444 //Log("Thread %i went *hurk*", Thread->TID);
446 if(Status != -1) HALT();
450 * \fn void Threads_Yield()
451 * \brief Yield remainder of timeslice
455 Proc_GetCurThread()->Remaining = 0;
460 * \fn void Threads_Sleep()
461 * \brief Take the current process off the run queue
465 tThread *cur = Proc_GetCurThread();
468 Log("Proc_Sleep: %i going to sleep", cur->TID);
471 LOCK( &giThreadListLock );
473 // Get thread before current thread
474 thread = Threads_int_GetPrev( &gActiveThreads, cur );
476 Warning("Threads_Sleep - Current thread is not on the active queue");
481 // Don't sleep if there is a message waiting
482 if( cur->Messages ) {
483 RELEASE( &giThreadListLock );
487 // Unset remaining timeslices (force a task switch on timer fire)
490 // Remove from active list
491 thread->Next = cur->Next;
493 // Add to Sleeping List (at the top)
494 cur->Next = gSleepingThreads;
495 gSleepingThreads = cur;
497 // Reduce the active count & ticket count
498 giNumActiveThreads --;
499 giTotalTickets -= cur->NumTickets;
501 // Mark thread as sleeping
502 cur->Status = THREAD_STAT_SLEEPING;
505 RELEASE( &giThreadListLock );
507 while(cur->Status != THREAD_STAT_ACTIVE) HALT();
512 * \fn void Threads_Wake( tThread *Thread )
513 * \brief Wakes a sleeping/waiting thread up
515 void Threads_Wake(tThread *Thread)
518 switch(Thread->Status)
520 case THREAD_STAT_ACTIVE: break;
521 case THREAD_STAT_SLEEPING:
522 LOCK( &giThreadListLock );
523 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
524 prev->Next = Thread->Next; // Remove from sleeping queue
525 Thread->Next = gActiveThreads; // Add to active queue
526 gActiveThreads = Thread;
527 Thread->Status = THREAD_STAT_ACTIVE;
528 RELEASE( &giThreadListLock );
530 case THREAD_STAT_WAITING:
531 Warning("Thread_Wake - Waiting threads are not currently supported");
533 case THREAD_STAT_DEAD:
534 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
537 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
543 * \fn void Threads_AddActive(tThread *Thread)
544 * \brief Adds a thread to the active queue
546 void Threads_AddActive(tThread *Thread)
548 LOCK( &giThreadListLock );
549 Thread->Next = gActiveThreads;
550 gActiveThreads = Thread;
551 giNumActiveThreads ++;
552 giTotalTickets += Thread->NumTickets;
553 //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
554 // giNumActiveThreads, giTotalTickets);
555 RELEASE( &giThreadListLock );
560 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
561 * \brief Sets the signal handler for a signal
563 void Threads_SetSignalHandler(int Num, void *Handler)
565 if(Num < 0 || Num >= NSIG) return;
567 gCurrentThread->SignalHandlers[Num] = Handler;
571 * \fn void Threads_SendSignal(int TID, int Num)
572 * \brief Send a signal to a thread
574 void Threads_SendSignal(int TID, int Num)
576 tThread *thread = Proc_GetThread(TID);
581 handler = thread->SignalHandlers[Num];
584 if(handler == SIG_ERR) {
594 if(handler == -2) return;
596 // Check the type and handle if the thread is already in a signal
597 if(thread->CurSignal != 0) {
598 if(Num < _SIGTYPE_FATAL)
601 while(thread->CurSignal != 0)
610 // --- Process Structure Access Functions ---
613 return Proc_GetCurThread()->TGID;
617 return Proc_GetCurThread()->TID;
621 return Proc_GetCurThread()->UID;
625 return Proc_GetCurThread()->GID;
629 * \fn void Threads_Dump()
630 * \brief Dums a list of currently running threads
635 tThread *cur = Proc_GetCurThread();
637 Log("Active Threads:");
638 for(thread=gActiveThreads;thread;thread=thread->Next)
640 Log("%c%i (%i) - %s",
641 (thread==cur?'*':' '),
642 thread->TID, thread->TGID, thread->ThreadName);
643 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
644 Log(" KStack 0x%x", thread->KernelStack);
646 Log("Sleeping Threads:");
647 for(thread=gSleepingThreads;thread;thread=thread->Next)
649 Log("%c%i (%i) - %s",
650 (thread==cur?'*':' '),
651 thread->TID, thread->TGID, thread->ThreadName);
652 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
653 Log(" KStack 0x%x", thread->KernelStack);
658 * \fn tThread *Threads_GetNextToRun(int CPU)
659 * \brief Gets the next thread to run
661 tThread *Threads_GetNextToRun(int CPU)
667 if(giNumActiveThreads == 0) return NULL;
669 // Special case: 1 thread
670 if(giNumActiveThreads == 1) {
671 return gActiveThreads;
674 //Log(" Threads_GetNextToRun: giNumActiveThreads=%i,giTotalTickets=%i",
675 // giNumActiveThreads, giTotalTickets);
676 // Get the ticket number
677 ticket = number = rand() % giTotalTickets;
679 //Log(" Threads_GetNextToRun: ticket = %i", ticket);
681 // Find the next thread
682 for(thread=gActiveThreads;thread;thread=thread->Next)
684 if(thread->NumTickets > number) break;
685 number -= thread->NumTickets;
692 for(thread=gActiveThreads;thread;thread=thread->Next)
693 number += thread->NumTickets;
694 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
695 giTotalTickets, number);
702 * \fn void Threads_SegFault(tVAddr Addr)
703 * \brief Called when a Segment Fault occurs
705 void Threads_SegFault(tVAddr Addr)
707 //Threads_SendSignal( Proc_GetCurThread()->TID, SIGSEGV );
708 Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
709 Threads_Exit( 0, -1 );
713 EXPORT(Threads_GetUID);