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);
33 void Threads_AddActive(tThread *Thread);
42 tThread gThreadZero = {
43 NULL, 0, // Next, Lock
44 THREAD_STAT_ACTIVE, // Status
48 0, // Parent Thread ID
55 0, {0}, {0}, // Signal State
57 NULL, NULL, // Messages, Last Message
58 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
60 {0} // Default config to zero
64 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
65 // --- Current State ---
66 volatile int giNumActiveThreads = 0;
67 volatile int giTotalTickets = 0;
68 volatile Uint giNextTID = 1;
69 // --- Thread Lists ---
70 tThread *gActiveThreads = NULL; // Currently Running Threads
71 tThread *gSleepingThreads = NULL; // Sleeping Threads
72 tThread *gDeleteThreads = NULL; // Threads to delete
77 * \fn void Threads_Init()
78 * \brief Initialse the thread list
84 // Create Initial Task
85 gActiveThreads = &gThreadZero;
86 giTotalTickets = gThreadZero.NumTickets;
87 giNumActiveThreads = 1;
91 if(Proc_Clone(0, 0) == 0)
93 tThread *cur = Proc_GetCurThread();
94 cur->ThreadName = "Idle Thread";
95 Threads_SetTickets(0); // Never called randomly
96 cur->Quantum = 1; // 1 slice quantum
101 HALT(); // Just yeilds
110 * \fn void Threads_SetName(char *NewName)
111 * \brief Sets the current thread's name
113 void Threads_SetName(char *NewName)
115 tThread *cur = Proc_GetCurThread();
116 if( IsHeap(cur->ThreadName) )
117 free( cur->ThreadName );
118 cur->ThreadName = malloc(strlen(NewName)+1);
119 strcpy(cur->ThreadName, NewName);
123 * \fn void Threads_SetTickets(int Num)
124 * \brief Sets the 'priority' of a task
126 void Threads_SetTickets(int Num)
128 tThread *cur = Proc_GetCurThread();
130 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
132 LOCK( &giThreadListLock );
133 giTotalTickets -= cur->NumTickets;
134 cur->NumTickets = Num;
135 giTotalTickets += Num;
136 //LOG("giTotalTickets = %i", giTotalTickets);
137 RELEASE( &giThreadListLock );
141 * \fn void Threads_WaitTID(int TID, int *status)
142 * \brief Wait for a task to change state
144 int Threads_WaitTID(int TID, int *status)
154 // Any peer/child thread
167 tThread *t = Threads_GetThread(TID);
168 int initStatus = t->Status;
170 while(t->Status == initStatus) Threads_Yield();
174 case THREAD_STAT_ZOMBIE:
175 t->Status = THREAD_STAT_DEAD;
176 if(status) *status = 0;
177 Threads_AddToDelete( t );
180 if(status) *status = -1;
190 * \fn tThread *Threads_GetThread(Uint TID)
191 * \brief Gets a thread given its TID
193 tThread *Threads_GetThread(Uint TID)
197 // Search Active List
198 for(thread = gActiveThreads;
200 thread = thread->Next)
202 if(thread->TID == TID)
206 // Search Sleeping List
207 for(thread = gSleepingThreads;
209 thread = thread->Next)
211 if(thread->TID == TID)
219 * \fn void Threads_AddToDelete(tThread *Thread)
220 * \brief Adds a thread to the delete queue
222 void Threads_AddToDelete(tThread *Thread)
224 // Add to delete queue
226 Thread->Next = gDeleteThreads;
227 gDeleteThreads = Thread;
230 gDeleteThreads = Thread;
235 * \fn tThread *Threads_int_GetPrev(tThread *List, tThread *Thread)
236 * \brief Gets the previous entry in a thead linked list
238 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
242 if(*List == Thread) {
243 return (tThread*)List;
246 ret->Next && ret->Next != Thread;
249 // Error if the thread is not on the list
250 if(!ret->Next || ret->Next != Thread) {
258 * \fn void Threads_Exit(int TID, int Status)
259 * \brief Exit the current process
261 void Threads_Exit(int TID, int Status)
263 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
267 * \fn void Threads_Kill(tThread *Thread, int Status)
268 * \brief Kill a thread
269 * \param TID Thread ID (0 for current)
271 void Threads_Kill(tThread *Thread, int Status)
280 for(child = gActiveThreads;
284 if(child->PTID == gCurrentThread->TID)
285 Threads_Kill(child, -1);
290 ///\note Double lock is needed due to overlap of locks
292 // Lock thread (stop us recieving messages)
293 LOCK( &Thread->IsLocked );
296 LOCK( &giThreadListLock );
298 // Get previous thread on list
299 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
301 Warning("Proc_Exit - Current thread is not on the active queue");
305 // Clear Message Queue
306 while( Thread->Messages )
308 msg = Thread->Messages->Next;
309 free( Thread->Messages );
310 Thread->Messages = msg;
313 Thread->Remaining = 0; // Clear Remaining Quantum
314 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
315 prev->Next = Thread->Next; // Remove from active
317 giNumActiveThreads --;
318 giTotalTickets -= Thread->NumTickets;
320 // Mark thread as a zombie
321 Thread->RetStatus = Status;
323 // Don't Zombie if we are being killed as part of a tree
326 Thread->Status = THREAD_STAT_DEAD;
327 Threads_AddToDelete( Thread );
329 Thread->Status = THREAD_STAT_ZOMBIE;
333 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
334 RELEASE( &giThreadListLock );
335 if(Status != -1) HALT();
339 * \fn void Threads_Yield()
340 * \brief Yield remainder of timeslice
344 Proc_GetCurThread()->Remaining = 0;
349 * \fn void Threads_Sleep()
350 * \brief Take the current process off the run queue
354 tThread *cur = Proc_GetCurThread();
357 Log("Proc_Sleep: %i going to sleep", cur->TID);
360 LOCK( &giThreadListLock );
362 // Get thread before current thread
363 thread = Threads_int_GetPrev( &gActiveThreads, cur );
365 Warning("Proc_Sleep - Current thread is not on the active queue");
369 // Don't sleep if there is a message waiting
370 if( cur->Messages ) {
371 RELEASE( &giThreadListLock );
375 // Unset remaining timeslices (force a task switch on timer fire)
378 // Remove from active list
379 thread->Next = cur->Next;
381 // Add to Sleeping List (at the top)
382 cur->Next = gSleepingThreads;
383 gSleepingThreads = cur;
385 // Reduce the active count & ticket count
386 giNumActiveThreads --;
387 giTotalTickets -= cur->NumTickets;
389 // Mark thread as sleeping
390 cur->Status = THREAD_STAT_SLEEPING;
393 RELEASE( &giThreadListLock );
400 * \fn void Threads_Wake( tThread *Thread )
401 * \brief Wakes a sleeping/waiting thread up
403 void Threads_Wake(tThread *Thread)
406 switch(Thread->Status)
408 case THREAD_STAT_ACTIVE: break;
409 case THREAD_STAT_SLEEPING:
410 LOCK( &giThreadListLock );
411 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
412 prev->Next = Thread->Next; // Remove from sleeping queue
413 Thread->Next = gActiveThreads; // Add to active queue
414 gActiveThreads = Thread;
415 Thread->Status = THREAD_STAT_ACTIVE;
416 RELEASE( &giThreadListLock );
418 case THREAD_STAT_WAITING:
419 Warning("Thread_Wake - Waiting threads are not currently supported");
421 case THREAD_STAT_DEAD:
422 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
425 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
431 * \fn void Threads_AddActive(tThread *Thread)
432 * \brief Adds a thread to the active queue
434 void Threads_AddActive(tThread *Thread)
436 LOCK( &giThreadListLock );
437 Thread->Next = gActiveThreads;
438 gActiveThreads = Thread;
439 giNumActiveThreads ++;
440 giTotalTickets += Thread->NumTickets;
441 //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
442 // giNumActiveThreads, giTotalTickets);
443 RELEASE( &giThreadListLock );
448 * \fn void Threads_SetSignalHandler(int Num, void *Handler)
449 * \brief Sets the signal handler for a signal
451 void Threads_SetSignalHandler(int Num, void *Handler)
453 if(Num < 0 || Num >= NSIG) return;
455 gCurrentThread->SignalHandlers[Num] = Handler;
459 * \fn void Threads_SendSignal(int TID, int Num)
461 void Threads_SendSignal(int TID, int Num)
463 tThread *thread = Proc_GetThread(TID);
468 handler = thread->SignalHandlers[Num];
471 if(handler == SIG_ERR) {
481 if(handler == -2) return;
483 // Check the type and handle if the thread is already in a signal
484 if(thread->CurSignal != 0) {
485 if(Num < _SIGTYPE_FATAL)
488 while(thread->CurSignal != 0)
497 // --- Process Structure Access Functions ---
500 return Proc_GetCurThread()->TGID;
504 return Proc_GetCurThread()->TID;
508 return Proc_GetCurThread()->UID;
512 return Proc_GetCurThread()->GID;
516 * \fn void Threads_Dump()
517 * \brief Dums a list of currently running threads
523 Log("Active Threads:");
524 for(thread=gActiveThreads;thread;thread=thread->Next)
526 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
527 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
528 Log(" KStack 0x%x", thread->KernelStack);
530 Log("Sleeping Threads:");
531 for(thread=gSleepingThreads;thread;thread=thread->Next)
533 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
534 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
535 Log(" KStack 0x%x", thread->KernelStack);
540 * \fn tThread *Threads_GetNextToRun(int CPU)
541 * \brief Gets the next thread to run
543 tThread *Threads_GetNextToRun(int CPU)
549 // Special case: 1 thread
550 if(giNumActiveThreads == 1)
552 return gActiveThreads;
555 //Log(" Threads_GetNextToRun: giNumActiveThreads=%i,giTotalTickets=%i",
556 // giNumActiveThreads, giTotalTickets);
557 // Get the ticket number
558 ticket = number = rand() % giTotalTickets;
560 //Log(" Threads_GetNextToRun: ticket = %i", ticket);
562 // Find the next thread
563 for(thread=gActiveThreads;thread;thread=thread->Next)
565 if(thread->NumTickets > number) break;
566 number -= thread->NumTickets;
573 for(thread=gActiveThreads;thread;thread=thread->Next)
574 number += thread->NumTickets;
575 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
576 giTotalTickets, number);