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 void Threads_AddToDelete(tThread *Thread);
27 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
28 void Threads_Exit(int TID, int Status);
29 void Threads_Kill(tThread *Thread, int Status);
32 void Threads_Wake(tThread *Thread);
41 tThread gThreadZero = {
42 NULL, 0, // Next, Lock
43 THREAD_STAT_ACTIVE, // Status
47 0, // Parent Thread ID
54 0, {0}, {0}, // Signal State
56 NULL, NULL, // Messages, Last Message
57 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
59 {0} // Default config to zero
63 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
64 // --- Current State ---
65 volatile int giNumActiveThreads = 0;
66 volatile int giTotalTickets = 0;
67 volatile Uint giNextTID = 1;
68 // --- Thread Lists ---
69 tThread *gActiveThreads = NULL; // Currently Running Threads
70 tThread *gSleepingThreads = NULL; // Sleeping Threads
71 tThread *gDeleteThreads = NULL; // Threads to delete
76 * \fn void Threads_Init()
77 * \brief Initialse the thread list
83 // Create Initial Task
84 gActiveThreads = &gThreadZero;
85 giTotalTickets = gThreadZero.NumTickets;
86 giNumActiveThreads = 1;
90 if(Proc_Clone(0, 0) == 0)
92 tThread *cur = Proc_GetCurThread();
93 cur->ThreadName = "Idle Thread";
94 Threads_SetTickets(0); // Never called randomly
95 cur->Quantum = 1; // 1 slice quantum
96 for(;;) __asm__ __volatile__ ("hlt"); // Just yeilds
104 * \fn void Threads_SetName(char *NewName)
105 * \brief Sets the current thread's name
107 void Threads_SetName(char *NewName)
109 tThread *cur = Proc_GetCurThread();
110 if( IsHeap(cur->ThreadName) )
111 free( cur->ThreadName );
112 cur->ThreadName = malloc(strlen(NewName)+1);
113 strcpy(cur->ThreadName, NewName);
117 * \fn void Threads_SetTickets(int Num)
118 * \brief Sets the 'priority' of a task
120 void Threads_SetTickets(int Num)
122 tThread *cur = Proc_GetCurThread();
124 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
126 LOCK( &giThreadListLock );
127 giTotalTickets -= cur->NumTickets;
128 cur->NumTickets = Num;
129 giTotalTickets += Num;
130 //LOG("giTotalTickets = %i", giTotalTickets);
131 RELEASE( &giThreadListLock );
135 * \fn void Threads_WaitTID(int TID, int *status)
136 * \brief Wait for a task to change state
138 int Threads_WaitTID(int TID, int *status)
146 // Any peer/child thread
159 tThread *t = Threads_GetThread(TID);
160 int initStatus = t->Status;
162 while(t->Status == initStatus) Threads_Yield();
166 case THREAD_STAT_ZOMBIE:
167 t->Status = THREAD_STAT_DEAD;
168 if(status) *status = 0;
169 Threads_AddToDelete( t );
172 if(status) *status = -1;
182 * \fn tThread *Threads_GetThread(Uint TID)
183 * \brief Gets a thread given its TID
185 tThread *Threads_GetThread(Uint TID)
189 // Search Active List
190 for(thread = gActiveThreads;
192 thread = thread->Next)
194 if(thread->TID == TID)
198 // Search Sleeping List
199 for(thread = gSleepingThreads;
201 thread = thread->Next)
203 if(thread->TID == TID)
211 * \fn void Threads_AddToDelete(tThread *Thread)
212 * \brief Adds a thread to the delete queue
214 void Threads_AddToDelete(tThread *Thread)
216 // Add to delete queue
218 Thread->Next = gDeleteThreads;
219 gDeleteThreads = Thread;
222 gDeleteThreads = Thread;
227 * \fn tThread *Threads_int_GetPrev(tThread *List, tThread *Thread)
228 * \brief Gets the previous entry in a thead linked list
230 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
234 if(*List == Thread) {
235 return (tThread*)List;
238 ret->Next && ret->Next != Thread;
241 // Error if the thread is not on the list
242 if(!ret->Next || ret->Next != Thread) {
250 * \fn void Threads_Exit(int TID, int Status)
251 * \brief Exit the current process
253 void Threads_Exit(int TID, int Status)
255 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
259 * \fn void Threads_Kill(tThread *Thread, int Status)
260 * \brief Kill a thread
261 * \param TID Thread ID (0 for current)
263 void Threads_Kill(tThread *Thread, int Status)
272 for(child = gActiveThreads;
276 if(child->PTID == gCurrentThread->TID)
277 Threads_Kill(child, -1);
282 ///\note Double lock is needed due to overlap of locks
284 // Lock thread (stop us recieving messages)
285 LOCK( &Thread->IsLocked );
288 LOCK( &giThreadListLock );
290 // Get previous thread on list
291 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
293 Warning("Proc_Exit - Current thread is not on the active queue");
297 // Clear Message Queue
298 while( Thread->Messages )
300 msg = Thread->Messages->Next;
301 free( Thread->Messages );
302 Thread->Messages = msg;
305 Thread->Remaining = 0; // Clear Remaining Quantum
306 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
307 prev->Next = Thread->Next; // Remove from active
309 giNumActiveThreads --;
310 giTotalTickets -= Thread->NumTickets;
312 // Mark thread as a zombie
313 Thread->RetStatus = Status;
315 // Don't Zombie if we are being killed as part of a tree
318 Thread->Status = THREAD_STAT_DEAD;
319 Threads_AddToDelete( Thread );
321 Thread->Status = THREAD_STAT_ZOMBIE;
325 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
326 RELEASE( &giThreadListLock );
327 if(Status != -1) HALT();
331 * \fn void Threads_Yield()
332 * \brief Yield remainder of timeslice
336 Proc_GetCurThread()->Quantum = 0;
341 * \fn void Threads_Sleep()
342 * \brief Take the current process off the run queue
346 tThread *cur = Proc_GetCurThread();
349 //Log("Proc_Sleep: %i going to sleep", gCurrentThread->TID);
352 LOCK( &giThreadListLock );
354 // Get thread before current thread
355 thread = Threads_int_GetPrev( &gActiveThreads, cur );
357 Warning("Proc_Sleep - Current thread is not on the active queue");
361 // Don't sleep if there is a message waiting
362 if( cur->Messages ) {
363 RELEASE( &giThreadListLock );
367 // Unset remaining timeslices (force a task switch on timer fire)
370 // Remove from active list
371 thread->Next = cur->Next;
373 // Add to Sleeping List (at the top)
374 cur->Next = gSleepingThreads;
375 gSleepingThreads = cur;
377 // Reduce the active count & ticket count
378 giNumActiveThreads --;
379 giTotalTickets -= cur->NumTickets;
381 // Mark thread as sleeping
382 cur->Status = THREAD_STAT_SLEEPING;
385 RELEASE( &giThreadListLock );
392 * \fn void Threads_Wake( tThread *Thread )
393 * \brief Wakes a sleeping/waiting thread up
395 void Threads_Wake(tThread *Thread)
398 switch(Thread->Status)
400 case THREAD_STAT_ACTIVE: break;
401 case THREAD_STAT_SLEEPING:
402 LOCK( &giThreadListLock );
403 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
404 prev->Next = Thread->Next; // Remove from sleeping queue
405 Thread->Next = gActiveThreads; // Add to active queue
406 gActiveThreads = Thread;
407 Thread->Status = THREAD_STAT_ACTIVE;
408 RELEASE( &giThreadListLock );
410 case THREAD_STAT_WAITING:
411 Warning("Thread_Wake - Waiting threads are not currently supported");
413 case THREAD_STAT_DEAD:
414 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
417 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
424 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
425 * \brief Sets the signal handler for a signal
427 void Threads_SetSignalHandler(int Num, void *Handler)
429 if(Num < 0 || Num >= NSIG) return;
431 gCurrentThread->SignalHandlers[Num] = Handler;
435 * \fn void Threads_SendSignal(int TID, int Num)
437 void Threads_SendSignal(int TID, int Num)
439 tThread *thread = Proc_GetThread(TID);
444 handler = thread->SignalHandlers[Num];
447 if(handler == SIG_ERR) {
457 if(handler == -2) return;
459 // Check the type and handle if the thread is already in a signal
460 if(thread->CurSignal != 0) {
461 if(Num < _SIGTYPE_FATAL)
464 while(thread->CurSignal != 0)
473 // --- Process Structure Access Functions ---
476 return Proc_GetCurThread()->TGID;
480 return Proc_GetCurThread()->TID;
484 return Proc_GetCurThread()->UID;
488 return Proc_GetCurThread()->GID;
492 * \fn void Threads_Dump()
493 * \brief Dums a list of currently running threads
499 Log("Active Threads:");
500 for(thread=gActiveThreads;thread;thread=thread->Next)
502 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
503 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
504 Log(" KStack 0x%x", thread->KernelStack);
506 Log("Sleeping Threads:");
507 for(thread=gSleepingThreads;thread;thread=thread->Next)
509 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
510 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
511 Log(" KStack 0x%x", thread->KernelStack);
516 * \fn tThread *Threads_GetNextToRun(int CPU)
517 * \brief Gets the next thread to run
519 tThread *Threads_GetNextToRun(int CPU)
525 // Special case: 1 thread
526 if(giNumActiveThreads == 1)
528 return gActiveThreads;
531 // Get the ticket number
532 ticket = number = rand() % giTotalTickets;
534 // Find the next thread
535 for(thread=gActiveThreads;thread;thread=thread->Next)
537 if(thread->NumTickets > number) break;
538 number -= thread->NumTickets;
545 for(thread=gActiveThreads;thread;thread=thread->Next)
546 number += thread->NumTickets;
547 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
548 giTotalTickets, number);