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 void Threads_SetTickets(int Num);
24 int Threads_WaitTID(int TID, int *status);
25 tThread *Threads_GetThread(Uint TID);
26 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
27 void Threads_Exit(int TID, int Status);
28 void Threads_Kill(tThread *Thread, int Status);
31 void Threads_Wake(tThread *Thread);
40 tThread gThreadZero = {
41 NULL, 0, // Next, Lock
42 THREAD_STAT_ACTIVE, // Status
46 0, // Parent Thread ID
53 0, {0}, {0}, // Signal State
55 NULL, NULL, // Messages, Last Message
56 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
58 {0} // Default config to zero
62 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
63 // --- Current State ---
64 volatile int giNumActiveThreads = 0;
65 volatile int giTotalTickets = 0;
66 volatile Uint giNextTID = 1;
67 // --- Thread Lists ---
68 tThread *gActiveThreads = NULL; // Currently Running Threads
69 tThread *gSleepingThreads = NULL; // Sleeping Threads
70 tThread *gDeleteThreads = NULL; // Threads to delete
75 * \fn void Threads_Init()
76 * \brief Initialse the thread list
82 // Create Initial Task
83 gActiveThreads = &gThreadZero;
84 giTotalTickets = gThreadZero.NumTickets;
85 giNumActiveThreads = 1;
89 if(Proc_Clone(0, 0) == 0)
91 tThread *cur = Proc_GetCurThread();
92 cur->ThreadName = "Idle Thread";
93 Threads_SetTickets(0); // Never called randomly
94 cur->Quantum = 1; // 1 slice quantum
95 for(;;) __asm__ __volatile__ ("hlt"); // Just yeilds
103 * \fn void Threads_SetName(char *NewName)
104 * \brief Sets the current thread's name
106 void Threads_SetName(char *NewName)
108 tThread *cur = Proc_GetCurThread();
109 if( IsHeap(cur->ThreadName) )
110 free( cur->ThreadName );
111 cur->ThreadName = malloc(strlen(NewName)+1);
112 strcpy(cur->ThreadName, NewName);
116 * \fn void Threads_SetTickets(int Num)
117 * \brief Sets the 'priority' of a task
119 void Threads_SetTickets(int Num)
121 tThread *cur = Proc_GetCurThread();
123 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
125 LOCK( &giThreadListLock );
126 giTotalTickets -= cur->NumTickets;
127 cur->NumTickets = Num;
128 giTotalTickets += Num;
129 //LOG("giTotalTickets = %i", giTotalTickets);
130 RELEASE( &giThreadListLock );
134 * \fn void Threads_WaitTID(int TID, int *status)
135 * \brief Wait for a task to change state
137 int Threads_WaitTID(int TID, int *status)
145 // Any peer/child thread
158 tThread *t = Threads_GetThread(TID);
159 int initStatus = t->Status;
161 while(t->Status == initStatus) Threads_Yield();
165 case THREAD_STAT_ZOMBIE:
166 t->Status = THREAD_STAT_DEAD;
180 * \fn tThread *Threads_GetThread(Uint TID)
181 * \brief Gets a thread given its TID
183 tThread *Threads_GetThread(Uint TID)
187 // Search Active List
188 for(thread = gActiveThreads;
190 thread = thread->Next)
192 if(thread->TID == TID)
196 // Search Sleeping List
197 for(thread = gSleepingThreads;
199 thread = thread->Next)
201 if(thread->TID == TID)
209 * \fn tThread *Threads_int_GetPrev(tThread *List, tThread *Thread)
210 * \brief Gets the previous entry in a thead linked list
212 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
216 if(*List == Thread) {
217 return (tThread*)List;
220 ret->Next && ret->Next != Thread;
223 // Error if the thread is not on the list
224 if(!ret->Next || ret->Next != Thread) {
232 * \fn void Threads_Exit(int TID, int Status)
233 * \brief Exit the current process
235 void Threads_Exit(int TID, int Status)
237 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
241 * \fn void Threads_Kill(tThread *Thread, int Status)
242 * \brief Kill a thread
243 * \param TID Thread ID (0 for current)
245 void Threads_Kill(tThread *Thread, int Status)
254 for(child = gActiveThreads;
258 if(child->PTID == gCurrentThread->TID)
259 Threads_Kill(child, -1);
264 ///\note Double lock is needed due to overlap of locks
266 // Lock thread (stop us recieving messages)
267 LOCK( &Thread->IsLocked );
270 LOCK( &giThreadListLock );
272 // Get previous thread on list
273 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
275 Warning("Proc_Exit - Current thread is not on the active queue");
279 // Clear Message Queue
280 while( Thread->Messages )
282 msg = Thread->Messages->Next;
283 free( Thread->Messages );
284 Thread->Messages = msg;
287 Thread->Remaining = 0; // Clear Remaining Quantum
288 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
289 prev->Next = Thread->Next; // Remove from active
291 giNumActiveThreads --;
292 giTotalTickets -= Thread->NumTickets;
294 // Mark thread as a zombie
295 Thread->RetStatus = Status;
297 // Don't Zombie if we are being killed as part of a tree
300 Thread->Status = THREAD_STAT_DEAD;
301 // Add to delete queue
303 Thread->Next = gDeleteThreads;
304 gDeleteThreads = Thread;
307 gDeleteThreads = Thread;
310 Thread->Status = THREAD_STAT_ZOMBIE;
314 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
315 RELEASE( &giThreadListLock );
316 if(Status != -1) HALT();
320 * \fn void Threads_Yield()
321 * \brief Yield remainder of timeslice
325 Proc_GetCurThread()->Quantum = 0;
330 * \fn void Threads_Sleep()
331 * \brief Take the current process off the run queue
335 tThread *cur = Proc_GetCurThread();
338 //Log("Proc_Sleep: %i going to sleep", gCurrentThread->TID);
341 LOCK( &giThreadListLock );
343 // Get thread before current thread
344 thread = Threads_int_GetPrev( &gActiveThreads, cur );
346 Warning("Proc_Sleep - Current thread is not on the active queue");
350 // Don't sleep if there is a message waiting
351 if( cur->Messages ) {
352 RELEASE( &giThreadListLock );
356 // Unset remaining timeslices (force a task switch on timer fire)
359 // Remove from active list
360 thread->Next = cur->Next;
362 // Add to Sleeping List (at the top)
363 cur->Next = gSleepingThreads;
364 gSleepingThreads = cur;
366 // Reduce the active count & ticket count
367 giNumActiveThreads --;
368 giTotalTickets -= cur->NumTickets;
370 // Mark thread as sleeping
371 cur->Status = THREAD_STAT_SLEEPING;
374 RELEASE( &giThreadListLock );
381 * \fn void Threads_Wake( tThread *Thread )
382 * \brief Wakes a sleeping/waiting thread up
384 void Threads_Wake(tThread *Thread)
387 switch(Thread->Status)
389 case THREAD_STAT_ACTIVE: break;
390 case THREAD_STAT_SLEEPING:
391 LOCK( &giThreadListLock );
392 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
393 prev->Next = Thread->Next; // Remove from sleeping queue
394 Thread->Next = gActiveThreads; // Add to active queue
395 gActiveThreads = Thread;
396 Thread->Status = THREAD_STAT_ACTIVE;
397 RELEASE( &giThreadListLock );
399 case THREAD_STAT_WAITING:
400 Warning("Thread_Wake - Waiting threads are not currently supported");
402 case THREAD_STAT_DEAD:
403 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
406 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
413 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
414 * \brief Sets the signal handler for a signal
416 void Threads_SetSignalHandler(int Num, void *Handler)
418 if(Num < 0 || Num >= NSIG) return;
420 gCurrentThread->SignalHandlers[Num] = Handler;
424 * \fn void Threads_SendSignal(int TID, int Num)
426 void Threads_SendSignal(int TID, int Num)
428 tThread *thread = Proc_GetThread(TID);
433 handler = thread->SignalHandlers[Num];
436 if(handler == SIG_ERR) {
446 if(handler == -2) return;
448 // Check the type and handle if the thread is already in a signal
449 if(thread->CurSignal != 0) {
450 if(Num < _SIGTYPE_FATAL)
453 while(thread->CurSignal != 0)
462 // --- Process Structure Access Functions ---
465 return Proc_GetCurThread()->TGID;
469 return Proc_GetCurThread()->TID;
473 return Proc_GetCurThread()->UID;
477 return Proc_GetCurThread()->GID;
481 * \fn void Threads_Dump()
482 * \brief Dums a list of currently running threads
488 Log("Active Threads:");
489 for(thread=gActiveThreads;thread;thread=thread->Next)
491 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
492 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
493 Log(" KStack 0x%x", thread->KernelStack);
495 Log("Sleeping Threads:");
496 for(thread=gSleepingThreads;thread;thread=thread->Next)
498 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
499 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
500 Log(" KStack 0x%x", thread->KernelStack);
505 * \fn tThread *Threads_GetNextToRun(int CPU)
506 * \brief Gets the next thread to run
508 tThread *Threads_GetNextToRun(int CPU)
514 // Special case: 1 thread
515 if(giNumActiveThreads == 1)
517 return gActiveThreads;
520 // Get the ticket number
521 ticket = number = rand() % giTotalTickets;
523 // Find the next thread
524 for(thread=gActiveThreads;thread;thread=thread->Next)
526 if(thread->NumTickets > number) break;
527 number -= thread->NumTickets;
534 for(thread=gActiveThreads;thread;thread=thread->Next)
535 number += thread->NumTickets;
536 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
537 giTotalTickets, number);