4 * - Common Thread Control
10 #define DEFAULT_QUANTUM 10
11 #define DEFAULT_TICKETS 5
12 #define MAX_TICKETS 10
15 extern void ArchThreads_Init();
16 extern void Proc_Start();
17 extern tThread *Proc_GetCurThread();
18 extern int Proc_Clone(Uint *Err, Uint Flags);
22 void Threads_SetName(char *NewName);
23 char *Threads_GetName(int ID);
24 void Threads_SetTickets(int Num);
25 int Threads_WaitTID(int TID, int *status);
26 tThread *Threads_GetThread(Uint TID);
27 void Threads_AddToDelete(tThread *Thread);
28 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
29 void Threads_Exit(int TID, int Status);
30 void Threads_Kill(tThread *Thread, int Status);
33 void Threads_Wake(tThread *Thread);
34 void Threads_AddActive(tThread *Thread);
43 tThread gThreadZero = {
44 NULL, 0, // Next, Lock
45 THREAD_STAT_ACTIVE, // Status
49 0, // Parent Thread ID
56 0, {0}, {0}, // Signal State
58 NULL, NULL, // Messages, Last Message
59 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
61 {0} // Default config to zero
65 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
66 // --- Current State ---
67 volatile int giNumActiveThreads = 0;
68 volatile int giTotalTickets = 0;
69 volatile Uint giNextTID = 1;
70 // --- Thread Lists ---
71 tThread *gActiveThreads = NULL; // Currently Running Threads
72 tThread *gSleepingThreads = NULL; // Sleeping Threads
73 tThread *gDeleteThreads = NULL; // Threads to delete
78 * \fn void Threads_Init()
79 * \brief Initialse the thread list
85 // Create Initial Task
86 gActiveThreads = &gThreadZero;
87 giTotalTickets = gThreadZero.NumTickets;
88 giNumActiveThreads = 1;
92 if(Proc_Clone(0, 0) == 0)
94 tThread *cur = Proc_GetCurThread();
95 cur->ThreadName = "Idle Thread";
96 Threads_SetTickets(0); // Never called randomly
97 cur->Quantum = 1; // 1 slice quantum
100 HALT(); // Just yeilds
109 * \fn void Threads_SetName(char *NewName)
110 * \brief Sets the current thread's name
112 void Threads_SetName(char *NewName)
114 tThread *cur = Proc_GetCurThread();
115 if( IsHeap(cur->ThreadName) )
116 free( cur->ThreadName );
117 cur->ThreadName = malloc(strlen(NewName)+1);
118 strcpy(cur->ThreadName, NewName);
122 * \fn char *Threads_GetName(int ID)
123 * \brief Gets a thread's name
125 char *Threads_GetName(int ID)
128 return Proc_GetCurThread()->ThreadName;
134 * \fn void Threads_SetTickets(int Num)
135 * \brief Sets the 'priority' of a task
137 void Threads_SetTickets(int Num)
139 tThread *cur = Proc_GetCurThread();
141 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
143 LOCK( &giThreadListLock );
144 giTotalTickets -= cur->NumTickets;
145 cur->NumTickets = Num;
146 giTotalTickets += Num;
147 //LOG("giTotalTickets = %i", giTotalTickets);
148 RELEASE( &giThreadListLock );
152 * \fn void Threads_WaitTID(int TID, int *status)
153 * \brief Wait for a task to change state
155 int Threads_WaitTID(int TID, int *status)
163 // Any peer/child thread
176 tThread *t = Threads_GetThread(TID);
177 int initStatus = t->Status;
179 while(t->Status == initStatus) Threads_Yield();
183 case THREAD_STAT_ZOMBIE:
184 t->Status = THREAD_STAT_DEAD;
185 if(status) *status = 0;
186 Threads_AddToDelete( t );
189 if(status) *status = -1;
199 * \fn tThread *Threads_GetThread(Uint TID)
200 * \brief Gets a thread given its TID
202 tThread *Threads_GetThread(Uint TID)
206 // Search Active List
207 for(thread = gActiveThreads;
209 thread = thread->Next)
211 if(thread->TID == TID)
215 // Search Sleeping List
216 for(thread = gSleepingThreads;
218 thread = thread->Next)
220 if(thread->TID == TID)
228 * \fn void Threads_AddToDelete(tThread *Thread)
229 * \brief Adds a thread to the delete queue
231 void Threads_AddToDelete(tThread *Thread)
233 // Add to delete queue
235 Thread->Next = gDeleteThreads;
236 gDeleteThreads = Thread;
239 gDeleteThreads = Thread;
244 * \fn tThread *Threads_int_GetPrev(tThread *List, tThread *Thread)
245 * \brief Gets the previous entry in a thead linked list
247 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
251 if(*List == Thread) {
252 return (tThread*)List;
255 ret->Next && ret->Next != Thread;
258 // Error if the thread is not on the list
259 if(!ret->Next || ret->Next != Thread) {
267 * \fn void Threads_Exit(int TID, int Status)
268 * \brief Exit the current process
270 void Threads_Exit(int TID, int Status)
273 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
275 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
279 * \fn void Threads_Kill(tThread *Thread, int Status)
280 * \brief Kill a thread
281 * \param TID Thread ID (0 for current)
283 void Threads_Kill(tThread *Thread, int Status)
292 for(child = gActiveThreads;
296 if(child->PTID == Thread->TID)
297 Threads_Kill(child, -1);
302 ///\note Double lock is needed due to overlap of locks
304 // Lock thread (stop us recieving messages)
305 LOCK( &Thread->IsLocked );
308 LOCK( &giThreadListLock );
310 // Get previous thread on list
311 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
313 Warning("Proc_Exit - Current thread is not on the active queue");
317 // Clear Message Queue
318 while( Thread->Messages )
320 msg = Thread->Messages->Next;
321 free( Thread->Messages );
322 Thread->Messages = msg;
325 Thread->Remaining = 0; // Clear Remaining Quantum
326 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
327 prev->Next = Thread->Next; // Remove from active
329 giNumActiveThreads --;
330 giTotalTickets -= Thread->NumTickets;
332 // Mark thread as a zombie
333 Thread->RetStatus = Status;
335 // Don't Zombie if we are being killed as part of a tree
338 Thread->Status = THREAD_STAT_DEAD;
339 Threads_AddToDelete( Thread );
341 Thread->Status = THREAD_STAT_ZOMBIE;
345 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
346 RELEASE( &giThreadListLock );
347 if(Status != -1) HALT();
351 * \fn void Threads_Yield()
352 * \brief Yield remainder of timeslice
356 Proc_GetCurThread()->Remaining = 0;
361 * \fn void Threads_Sleep()
362 * \brief Take the current process off the run queue
366 tThread *cur = Proc_GetCurThread();
369 Log("Proc_Sleep: %i going to sleep", cur->TID);
372 LOCK( &giThreadListLock );
374 // Get thread before current thread
375 thread = Threads_int_GetPrev( &gActiveThreads, cur );
377 Warning("Proc_Sleep - Current thread is not on the active queue");
381 // Don't sleep if there is a message waiting
382 if( cur->Messages ) {
383 RELEASE( &giThreadListLock );
387 // Unset remaining timeslices (force a task switch on timer fire)
390 // Remove from active list
391 thread->Next = cur->Next;
393 // Add to Sleeping List (at the top)
394 cur->Next = gSleepingThreads;
395 gSleepingThreads = cur;
397 // Reduce the active count & ticket count
398 giNumActiveThreads --;
399 giTotalTickets -= cur->NumTickets;
401 // Mark thread as sleeping
402 cur->Status = THREAD_STAT_SLEEPING;
405 RELEASE( &giThreadListLock );
412 * \fn void Threads_Wake( tThread *Thread )
413 * \brief Wakes a sleeping/waiting thread up
415 void Threads_Wake(tThread *Thread)
418 switch(Thread->Status)
420 case THREAD_STAT_ACTIVE: break;
421 case THREAD_STAT_SLEEPING:
422 LOCK( &giThreadListLock );
423 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
424 prev->Next = Thread->Next; // Remove from sleeping queue
425 Thread->Next = gActiveThreads; // Add to active queue
426 gActiveThreads = Thread;
427 Thread->Status = THREAD_STAT_ACTIVE;
428 RELEASE( &giThreadListLock );
430 case THREAD_STAT_WAITING:
431 Warning("Thread_Wake - Waiting threads are not currently supported");
433 case THREAD_STAT_DEAD:
434 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
437 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
443 * \fn void Threads_AddActive(tThread *Thread)
444 * \brief Adds a thread to the active queue
446 void Threads_AddActive(tThread *Thread)
448 LOCK( &giThreadListLock );
449 Thread->Next = gActiveThreads;
450 gActiveThreads = Thread;
451 giNumActiveThreads ++;
452 giTotalTickets += Thread->NumTickets;
453 //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
454 // giNumActiveThreads, giTotalTickets);
455 RELEASE( &giThreadListLock );
460 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
461 * \brief Sets the signal handler for a signal
463 void Threads_SetSignalHandler(int Num, void *Handler)
465 if(Num < 0 || Num >= NSIG) return;
467 gCurrentThread->SignalHandlers[Num] = Handler;
471 * \fn void Threads_SendSignal(int TID, int Num)
472 * \brief Send a signal to a thread
474 void Threads_SendSignal(int TID, int Num)
476 tThread *thread = Proc_GetThread(TID);
481 handler = thread->SignalHandlers[Num];
484 if(handler == SIG_ERR) {
494 if(handler == -2) return;
496 // Check the type and handle if the thread is already in a signal
497 if(thread->CurSignal != 0) {
498 if(Num < _SIGTYPE_FATAL)
501 while(thread->CurSignal != 0)
510 // --- Process Structure Access Functions ---
513 return Proc_GetCurThread()->TGID;
517 return Proc_GetCurThread()->TID;
521 return Proc_GetCurThread()->UID;
525 return Proc_GetCurThread()->GID;
529 * \fn void Threads_Dump()
530 * \brief Dums a list of currently running threads
536 Log("Active Threads:");
537 for(thread=gActiveThreads;thread;thread=thread->Next)
539 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
540 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
541 Log(" KStack 0x%x", thread->KernelStack);
543 Log("Sleeping Threads:");
544 for(thread=gSleepingThreads;thread;thread=thread->Next)
546 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
547 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
548 Log(" KStack 0x%x", thread->KernelStack);
553 * \fn tThread *Threads_GetNextToRun(int CPU)
554 * \brief Gets the next thread to run
556 tThread *Threads_GetNextToRun(int CPU)
562 // Special case: 1 thread
563 if(giNumActiveThreads == 1)
565 return gActiveThreads;
568 //Log(" Threads_GetNextToRun: giNumActiveThreads=%i,giTotalTickets=%i",
569 // giNumActiveThreads, giTotalTickets);
570 // Get the ticket number
571 ticket = number = rand() % giTotalTickets;
573 //Log(" Threads_GetNextToRun: ticket = %i", ticket);
575 // Find the next thread
576 for(thread=gActiveThreads;thread;thread=thread->Next)
578 if(thread->NumTickets > number) break;
579 number -= thread->NumTickets;
586 for(thread=gActiveThreads;thread;thread=thread->Next)
587 number += thread->NumTickets;
588 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
589 giTotalTickets, number);
596 * \fn void Threads_SegFault(tVAddr Addr)
597 * \brief Called when a Segment Fault occurs
599 void Threads_SegFault(tVAddr Addr)
601 //Threads_SendSignal( Proc_GetCurThread()->TID, SIGSEGV );
602 Log("Thread #%i committed a segfault at address %p\n", Proc_GetCurThread()->TID, Addr);
603 Threads_Exit( 0, 0 );