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 tThread *Proc_GetCurThread();
17 extern int Proc_Clone(Uint *Err, Uint Flags);
21 void Threads_SetName(char *NewName);
22 void Threads_SetTickets(int Num);
23 int Threads_WaitTID(int TID, int *status);
24 tThread *Threads_GetThread(Uint TID);
25 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
26 void Threads_Exit(int TID, int Status);
27 void Threads_Kill(tThread *Thread, int Status);
30 void Threads_Wake(tThread *Thread);
39 tThread gThreadZero = {
40 NULL, 0, // Next, Lock
41 THREAD_STAT_ACTIVE, // Status
45 0, // Parent Thread ID
52 0, {0}, {0}, // Signal State
54 NULL, NULL, // Messages, Last Message
55 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
57 {0} // Default config to zero
61 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
62 // --- Current State ---
63 volatile int giNumActiveThreads = 0;
64 volatile int giTotalTickets = 0;
65 volatile Uint giNextTID = 1;
66 // --- Thread Lists ---
67 tThread *gActiveThreads = NULL; // Currently Running Threads
68 tThread *gSleepingThreads = NULL; // Sleeping Threads
69 tThread *gDeleteThreads = NULL; // Threads to delete
74 * \fn void Threads_Init()
75 * \brief Initialse the thread list
81 // Create Initial Task
82 gActiveThreads = &gThreadZero;
83 giTotalTickets = gThreadZero.NumTickets;
84 giNumActiveThreads = 1;
88 if(Proc_Clone(0, 0) == 0)
90 tThread *cur = Proc_GetCurThread();
91 cur->ThreadName = "Idle Thread";
92 Threads_SetTickets(0); // Never called randomly
93 cur->Quantum = 1; // 1 slice quantum
94 for(;;) __asm__ __volatile__ ("hlt"); // Just yeilds
100 * \fn void Threads_SetName(char *NewName)
101 * \brief Sets the current thread's name
103 void Threads_SetName(char *NewName)
105 tThread *cur = Proc_GetCurThread();
106 if( IsHeap(cur->ThreadName) )
107 free( cur->ThreadName );
108 cur->ThreadName = malloc(strlen(NewName)+1);
109 strcpy(cur->ThreadName, NewName);
113 * \fn void Threads_SetTickets(int Num)
114 * \brief Sets the 'priority' of a task
116 void Threads_SetTickets(int Num)
118 tThread *cur = Proc_GetCurThread();
120 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
122 LOCK( &giThreadListLock );
123 giTotalTickets -= cur->NumTickets;
124 cur->NumTickets = Num;
125 giTotalTickets += Num;
126 //LOG("giTotalTickets = %i", giTotalTickets);
127 RELEASE( &giThreadListLock );
131 * \fn void Threads_WaitTID(int TID, int *status)
132 * \brief Wait for a task to change state
134 int Threads_WaitTID(int TID, int *status)
142 // Any peer/child thread
155 tThread *t = Threads_GetThread(TID);
156 int initStatus = t->Status;
158 while(t->Status == initStatus) Threads_Yield();
162 case THREAD_STAT_ZOMBIE:
163 t->Status = THREAD_STAT_DEAD;
177 * \fn tThread *Threads_GetThread(Uint TID)
178 * \brief Gets a thread given its TID
180 tThread *Threads_GetThread(Uint TID)
184 // Search Active List
185 for(thread = gActiveThreads;
187 thread = thread->Next)
189 if(thread->TID == TID)
193 // Search Sleeping List
194 for(thread = gSleepingThreads;
196 thread = thread->Next)
198 if(thread->TID == TID)
206 * \fn tThread *Threads_int_GetPrev(tThread *List, tThread *Thread)
207 * \brief Gets the previous entry in a thead linked list
209 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
213 if(*List == Thread) {
214 return (tThread*)List;
217 ret->Next && ret->Next != Thread;
220 // Error if the thread is not on the list
221 if(!ret->Next || ret->Next != Thread) {
229 * \fn void Threads_Exit(int TID, int Status)
230 * \brief Exit the current process
232 void Threads_Exit(int TID, int Status)
234 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
238 * \fn void Threads_Kill(tThread *Thread, int Status)
239 * \brief Kill a thread
240 * \param TID Thread ID (0 for current)
242 void Threads_Kill(tThread *Thread, int Status)
251 for(child = gActiveThreads;
255 if(child->PTID == gCurrentThread->TID)
256 Threads_Kill(child, -1);
261 ///\note Double lock is needed due to overlap of locks
263 // Lock thread (stop us recieving messages)
264 LOCK( &Thread->IsLocked );
267 LOCK( &giThreadListLock );
269 // Get previous thread on list
270 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
272 Warning("Proc_Exit - Current thread is not on the active queue");
276 // Clear Message Queue
277 while( Thread->Messages )
279 msg = Thread->Messages->Next;
280 free( Thread->Messages );
281 Thread->Messages = msg;
284 Thread->Remaining = 0; // Clear Remaining Quantum
285 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
286 prev->Next = Thread->Next; // Remove from active
288 giNumActiveThreads --;
289 giTotalTickets -= Thread->NumTickets;
291 // Mark thread as a zombie
292 Thread->RetStatus = Status;
294 // Don't Zombie if we are being killed as part of a tree
297 Thread->Status = THREAD_STAT_DEAD;
298 // Add to delete queue
300 Thread->Next = gDeleteThreads;
301 gDeleteThreads = Thread;
304 gDeleteThreads = Thread;
307 Thread->Status = THREAD_STAT_ZOMBIE;
311 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
312 RELEASE( &giThreadListLock );
313 if(Status != -1) HALT();
317 * \fn void Threads_Yield()
318 * \brief Yield remainder of timeslice
322 Proc_GetCurThread()->Quantum = 0;
327 * \fn void Threads_Sleep()
328 * \brief Take the current process off the run queue
332 tThread *cur = Proc_GetCurThread();
335 //Log("Proc_Sleep: %i going to sleep", gCurrentThread->TID);
338 LOCK( &giThreadListLock );
340 // Get thread before current thread
341 thread = Threads_int_GetPrev( &gActiveThreads, cur );
343 Warning("Proc_Sleep - Current thread is not on the active queue");
347 // Don't sleep if there is a message waiting
348 if( cur->Messages ) {
349 RELEASE( &giThreadListLock );
353 // Unset remaining timeslices (force a task switch on timer fire)
356 // Remove from active list
357 thread->Next = cur->Next;
359 // Add to Sleeping List (at the top)
360 cur->Next = gSleepingThreads;
361 gSleepingThreads = cur;
363 // Reduce the active count & ticket count
364 giNumActiveThreads --;
365 giTotalTickets -= cur->NumTickets;
367 // Mark thread as sleeping
368 cur->Status = THREAD_STAT_SLEEPING;
371 RELEASE( &giThreadListLock );
378 * \fn void Threads_Wake( tThread *Thread )
379 * \brief Wakes a sleeping/waiting thread up
381 void Threads_Wake(tThread *Thread)
384 switch(Thread->Status)
386 case THREAD_STAT_ACTIVE: break;
387 case THREAD_STAT_SLEEPING:
388 LOCK( &giThreadListLock );
389 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
390 prev->Next = Thread->Next; // Remove from sleeping queue
391 Thread->Next = gActiveThreads; // Add to active queue
392 gActiveThreads = Thread;
393 Thread->Status = THREAD_STAT_ACTIVE;
394 RELEASE( &giThreadListLock );
396 case THREAD_STAT_WAITING:
397 Warning("Thread_Wake - Waiting threads are not currently supported");
399 case THREAD_STAT_DEAD:
400 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
403 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
410 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
411 * \brief Sets the signal handler for a signal
413 void Threads_SetSignalHandler(int Num, void *Handler)
415 if(Num < 0 || Num >= NSIG) return;
417 gCurrentThread->SignalHandlers[Num] = Handler;
421 * \fn void Threads_SendSignal(int TID, int Num)
423 void Threads_SendSignal(int TID, int Num)
425 tThread *thread = Proc_GetThread(TID);
430 handler = thread->SignalHandlers[Num];
433 if(handler == SIG_ERR) {
443 if(handler == -2) return;
445 // Check the type and handle if the thread is already in a signal
446 if(thread->CurSignal != 0) {
447 if(Num < _SIGTYPE_FATAL)
450 while(thread->CurSignal != 0)
459 // --- Process Structure Access Functions ---
462 return Proc_GetCurThread()->TGID;
466 return Proc_GetCurThread()->TID;
470 return Proc_GetCurThread()->UID;
474 return Proc_GetCurThread()->GID;
478 * \fn void Threads_Dump()
479 * \brief Dums a list of currently running threads
485 Log("Active Threads:");
486 for(thread=gActiveThreads;thread;thread=thread->Next)
488 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
489 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
490 Log(" KStack 0x%x", thread->KernelStack);
492 Log("Sleeping Threads:");
493 for(thread=gSleepingThreads;thread;thread=thread->Next)
495 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
496 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
497 Log(" KStack 0x%x", thread->KernelStack);
502 * \fn tThread *Threads_GetNextToRun(int CPU)
503 * \brief Gets the next thread to run
505 tThread *Threads_GetNextToRun(int CPU)
511 // Special case: 1 thread
512 if(giNumActiveThreads == 1)
514 return gActiveThreads;
517 // Get the ticket number
518 ticket = number = rand() % giTotalTickets;
520 // Find the next thread
521 for(thread=gActiveThreads;thread;thread=thread->Next)
523 if(thread->NumTickets > number) break;
524 number -= thread->NumTickets;
531 for(thread=gActiveThreads;thread;thread=thread->Next)
532 number += thread->NumTickets;
533 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
534 giTotalTickets, number);