4 * - Common Thread Control
11 #define DEFAULT_QUANTUM 10
12 #define DEFAULT_TICKETS 5
13 #define MAX_TICKETS 10
14 const enum eConfigTypes cCONFIG_TYPES[] = {
15 CFGT_HEAPSTR, // CFG_VFS_CWD
16 CFGT_INT, // CFG_VFS_MAXFILES
21 extern void ArchThreads_Init();
22 extern void Proc_Start();
23 extern tThread *Proc_GetCurThread();
24 extern int Proc_Clone(Uint *Err, Uint Flags);
25 extern void Proc_CallFaultHandler(tThread *Thread);
29 int Threads_SetName(char *NewName);
30 char *Threads_GetName(int ID);
31 void Threads_SetTickets(int Num);
32 tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
33 int Threads_WaitTID(int TID, int *status);
34 tThread *Threads_GetThread(Uint TID);
35 void Threads_AddToDelete(tThread *Thread);
36 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
37 void Threads_Exit(int TID, int Status);
38 void Threads_Kill(tThread *Thread, int Status);
41 void Threads_Wake(tThread *Thread);
42 void Threads_AddActive(tThread *Thread);
45 tUID Threads_GetUID();
46 int Threads_SetUID(Uint *Errno, tUID ID);
47 tGID Threads_GetGID();
48 int Threads_SetGID(Uint *Errno, tUID ID);
53 tThread gThreadZero = {
54 NULL, 0, // Next, Lock
55 THREAD_STAT_ACTIVE, // Status
59 0, // Parent Thread ID
66 0, 0, // Current Fault, Fault Handler
68 NULL, NULL, // Messages, Last Message
69 DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
71 {0} // Default config to zero
75 volatile int giThreadListLock = 0; ///\note NEVER use a heap function while locked
76 // --- Current State ---
77 volatile int giNumActiveThreads = 0;
78 volatile int giTotalTickets = 0;
79 volatile Uint giNextTID = 1;
80 // --- Thread Lists ---
81 tThread *gActiveThreads = NULL; // Currently Running Threads
82 tThread *gSleepingThreads = NULL; // Sleeping Threads
83 tThread *gDeleteThreads = NULL; // Threads to delete
88 * \fn void Threads_Init()
89 * \brief Initialse the thread list
95 // Create Initial Task
96 gActiveThreads = &gThreadZero;
97 giTotalTickets = gThreadZero.NumTickets;
98 giNumActiveThreads = 1;
102 if(Proc_Clone(0, 0) == 0)
104 tThread *cur = Proc_GetCurThread();
105 cur->ThreadName = "Idle Thread";
106 Threads_SetTickets(0); // Never called randomly
107 cur->Quantum = 1; // 1 slice quantum
110 HALT(); // Just yeilds
119 * \fn void Threads_SetName(char *NewName)
120 * \brief Sets the current thread's name
122 int Threads_SetName(char *NewName)
124 tThread *cur = Proc_GetCurThread();
125 if( IsHeap(cur->ThreadName) )
126 free( cur->ThreadName );
127 cur->ThreadName = malloc(strlen(NewName)+1);
128 strcpy(cur->ThreadName, NewName);
133 * \fn char *Threads_GetName(int ID)
134 * \brief Gets a thread's name
136 char *Threads_GetName(int ID)
139 return Proc_GetCurThread()->ThreadName;
145 * \fn void Threads_SetTickets(int Num)
146 * \brief Sets the 'priority' of a task
148 void Threads_SetTickets(int Num)
150 tThread *cur = Proc_GetCurThread();
152 if(Num > MAX_TICKETS) Num = MAX_TICKETS;
154 LOCK( &giThreadListLock );
155 giTotalTickets -= cur->NumTickets;
156 cur->NumTickets = Num;
157 giTotalTickets += Num;
158 //LOG("giTotalTickets = %i", giTotalTickets);
159 RELEASE( &giThreadListLock );
163 * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
165 tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
169 cur = Proc_GetCurThread();
171 new = malloc(sizeof(tThread));
179 new->Status = THREAD_STAT_ACTIVE;
183 new->TID = giNextTID++;
184 new->PTID = cur->TID;
187 new->ThreadName = malloc(strlen(cur->ThreadName)+1);
188 strcpy(new->ThreadName, cur->ThreadName);
190 // Set Thread Group ID (PID)
192 new->TGID = new->TID;
194 new->TGID = cur->TGID;
196 // Messages are not inherited
197 new->Messages = NULL;
198 new->LastMessage = NULL;
201 new->Remaining = new->Quantum = cur->Quantum;
202 new->NumTickets = cur->NumTickets;
204 // Set Signal Handlers
205 new->CurFaultNum = 0;
206 new->FaultHandler = cur->FaultHandler;
208 for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
210 switch(cCONFIG_TYPES[i])
213 new->Config[i] = cur->Config[i];
217 new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
228 * \fn Uint *Threads_GetCfgPtr(int Id)
230 Uint *Threads_GetCfgPtr(int Id)
232 if(Id < 0 || Id >= NUM_CFG_ENTRIES) {
233 Warning("Threads_GetCfgPtr: Index %i is out of bounds", Id);
237 return &Proc_GetCurThread()->Config[Id];
241 * \fn void Threads_WaitTID(int TID, int *status)
242 * \brief Wait for a task to change state
244 int Threads_WaitTID(int TID, int *status)
252 // Any peer/child thread
265 tThread *t = Threads_GetThread(TID);
266 int initStatus = t->Status;
269 if(initStatus != THREAD_STAT_ZOMBIE)
270 while(t->Status == initStatus) {
277 case THREAD_STAT_ZOMBIE:
278 t->Status = THREAD_STAT_DEAD;
279 if(status) *status = 0;
280 Threads_AddToDelete( t );
283 if(status) *status = -1;
293 * \fn tThread *Threads_GetThread(Uint TID)
294 * \brief Gets a thread given its TID
296 tThread *Threads_GetThread(Uint TID)
300 // Search Active List
301 for(thread = gActiveThreads;
303 thread = thread->Next)
305 if(thread->TID == TID)
309 // Search Sleeping List
310 for(thread = gSleepingThreads;
312 thread = thread->Next)
314 if(thread->TID == TID)
322 * \fn void Threads_AddToDelete(tThread *Thread)
323 * \brief Adds a thread to the delete queue
325 void Threads_AddToDelete(tThread *Thread)
327 // Add to delete queue
329 Thread->Next = gDeleteThreads;
330 gDeleteThreads = Thread;
333 gDeleteThreads = Thread;
338 * \fn tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
339 * \brief Gets the previous entry in a thead linked list
341 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
345 if(*List == Thread) {
346 return (tThread*)List;
349 ret->Next && ret->Next != Thread;
352 // Error if the thread is not on the list
353 if(!ret->Next || ret->Next != Thread) {
361 * \fn void Threads_Exit(int TID, int Status)
362 * \brief Exit the current process
364 void Threads_Exit(int TID, int Status)
367 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
369 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
370 for(;;) HALT(); // Just in case
374 * \fn void Threads_Kill(tThread *Thread, int Status)
375 * \brief Kill a thread
376 * \param Thread Thread to kill
377 * \param Status Status code to return to the parent
379 void Threads_Kill(tThread *Thread, int Status)
388 for(child = gActiveThreads;
392 if(child->PTID == Thread->TID)
393 Threads_Kill(child, -1);
398 ///\note Double lock is needed due to overlap of locks
400 // Lock thread (stop us recieving messages)
401 LOCK( &Thread->IsLocked );
404 LOCK( &giThreadListLock );
406 // Get previous thread on list
407 prev = Threads_int_GetPrev( &gActiveThreads, Thread );
409 Warning("Proc_Exit - Current thread is not on the active queue");
413 // Clear Message Queue
414 while( Thread->Messages )
416 msg = Thread->Messages->Next;
417 free( Thread->Messages );
418 Thread->Messages = msg;
421 Thread->Remaining = 0; // Clear Remaining Quantum
422 Thread->Quantum = 0; // Clear Quantum to indicate dead thread
423 prev->Next = Thread->Next; // Remove from active
425 giNumActiveThreads --;
426 giTotalTickets -= Thread->NumTickets;
428 // Mark thread as a zombie
429 Thread->RetStatus = Status;
431 // Don't Zombie if we are being killed as part of a tree
434 Thread->Status = THREAD_STAT_DEAD;
435 Threads_AddToDelete( Thread );
437 Thread->Status = THREAD_STAT_ZOMBIE;
441 RELEASE( &Thread->IsLocked ); // Released first so that it IS released
442 RELEASE( &giThreadListLock );
444 //Log("Thread %i went *hurk*", Thread->TID);
446 if(Status != -1) HALT();
450 * \fn void Threads_Yield()
451 * \brief Yield remainder of timeslice
455 Proc_GetCurThread()->Remaining = 0;
460 * \fn void Threads_Sleep()
461 * \brief Take the current process off the run queue
465 tThread *cur = Proc_GetCurThread();
468 //Log_Log("Threads", "%i going to sleep", cur->TID);
471 LOCK( &giThreadListLock );
473 // Get thread before current thread
474 thread = Threads_int_GetPrev( &gActiveThreads, cur );
476 Warning("Threads_Sleep - Current thread is not on the active queue");
481 // Don't sleep if there is a message waiting
482 if( cur->Messages ) {
483 RELEASE( &giThreadListLock );
487 // Unset remaining timeslices (force a task switch on timer fire)
490 // Remove from active list
491 thread->Next = cur->Next;
493 // Add to Sleeping List (at the top)
494 cur->Next = gSleepingThreads;
495 gSleepingThreads = cur;
497 // Reduce the active count & ticket count
498 giNumActiveThreads --;
499 giTotalTickets -= cur->NumTickets;
501 // Mark thread as sleeping
502 cur->Status = THREAD_STAT_SLEEPING;
505 RELEASE( &giThreadListLock );
507 while(cur->Status != THREAD_STAT_ACTIVE) HALT();
512 * \fn void Threads_Wake( tThread *Thread )
513 * \brief Wakes a sleeping/waiting thread up
515 void Threads_Wake(tThread *Thread)
518 switch(Thread->Status)
520 case THREAD_STAT_ACTIVE: break;
521 case THREAD_STAT_SLEEPING:
522 //Log_Log("Threads", "Waking %i (%p) from sleeping", Thread->TID, Thread);
523 LOCK( &giThreadListLock );
524 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
525 prev->Next = Thread->Next; // Remove from sleeping queue
526 Thread->Next = gActiveThreads; // Add to active queue
527 gActiveThreads = Thread;
528 giNumActiveThreads ++;
529 giTotalTickets += Thread->NumTickets;
530 Thread->Status = THREAD_STAT_ACTIVE;
531 RELEASE( &giThreadListLock );
533 case THREAD_STAT_WAITING:
534 Warning("Thread_Wake - Waiting threads are not currently supported");
536 case THREAD_STAT_DEAD:
537 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
540 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
545 void Threads_WakeTID(tTID Thread)
547 Threads_Wake( Threads_GetThread(Thread) );
551 * \fn void Threads_AddActive(tThread *Thread)
552 * \brief Adds a thread to the active queue
554 void Threads_AddActive(tThread *Thread)
556 LOCK( &giThreadListLock );
557 Thread->Next = gActiveThreads;
558 gActiveThreads = Thread;
559 giNumActiveThreads ++;
560 giTotalTickets += Thread->NumTickets;
561 //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
562 // giNumActiveThreads, giTotalTickets);
563 RELEASE( &giThreadListLock );
567 * \fn void Threads_SetSignalHandler(Uint Handler)
568 * \brief Sets the signal handler for a signal
570 void Threads_SetFaultHandler(Uint Handler)
572 Log_Log("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
573 Proc_GetCurThread()->FaultHandler = Handler;
577 * \fn void Threads_Fault(int Num)
578 * \brief Calls a fault handler
580 void Threads_Fault(int Num)
582 tThread *thread = Proc_GetCurThread();
584 Log_Log("Threads", "Threads_Fault: thread = %p", thread);
588 Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
590 switch(thread->FaultHandler)
593 Threads_Kill(thread, -1);
596 case 1: // Dump Core?
597 Threads_Kill(thread, -1);
602 // Double Fault? Oh, F**k
603 if(thread->CurFaultNum != 0) {
604 Threads_Kill(thread, -1); // For now, just kill
608 Proc_CallFaultHandler(thread);
611 // --- Process Structure Access Functions ---
612 tPID Threads_GetPID()
614 return Proc_GetCurThread()->TGID;
616 tTID Threads_GetTID()
618 return Proc_GetCurThread()->TID;
620 tUID Threads_GetUID()
622 return Proc_GetCurThread()->UID;
624 tGID Threads_GetGID()
626 return Proc_GetCurThread()->GID;
629 int Threads_SetUID(Uint *Errno, tUID ID)
631 tThread *t = Proc_GetCurThread();
636 Log("Threads_SetUID - Setting User ID to %i", ID);
641 int Threads_SetGID(Uint *Errno, tGID ID)
643 tThread *t = Proc_GetCurThread();
648 Log("Threads_SetGID - Setting Group ID to %i", ID);
654 * \fn void Threads_Dump()
655 * \brief Dums a list of currently running threads
660 tThread *cur = Proc_GetCurThread();
662 Log("Active Threads:");
663 for(thread=gActiveThreads;thread;thread=thread->Next)
665 Log("%c%i (%i) - %s",
666 (thread==cur?'*':' '),
667 thread->TID, thread->TGID, thread->ThreadName);
668 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
669 Log(" KStack 0x%x", thread->KernelStack);
671 Log("Sleeping Threads:");
672 for(thread=gSleepingThreads;thread;thread=thread->Next)
674 Log("%c%i (%i) - %s",
675 (thread==cur?'*':' '),
676 thread->TID, thread->TGID, thread->ThreadName);
677 Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
678 Log(" KStack 0x%x", thread->KernelStack);
683 * \fn tThread *Threads_GetNextToRun(int CPU)
684 * \brief Gets the next thread to run
686 tThread *Threads_GetNextToRun(int CPU)
692 if(giNumActiveThreads == 0) {
693 //Log_Debug("Threads", "CPU%i has no threads to run", CPU);
697 // Special case: 1 thread
698 if(giNumActiveThreads == 1) {
699 //Log_Debug("Threads", "CPU%i has only one thread %i %s",
700 // CPU, gActiveThreads->TID, gActiveThreads->ThreadName);
701 return gActiveThreads;
704 //Log(" Threads_GetNextToRun: giNumActiveThreads=%i,giTotalTickets=%i",
705 // giNumActiveThreads, giTotalTickets);
706 // Get the ticket number
707 ticket = number = rand() % giTotalTickets;
709 //Log(" Threads_GetNextToRun: ticket = %i", ticket);
711 // Find the next thread
712 for(thread=gActiveThreads;thread;thread=thread->Next)
714 if(thread->NumTickets > number) break;
715 number -= thread->NumTickets;
722 for(thread=gActiveThreads;thread;thread=thread->Next)
723 number += thread->NumTickets;
724 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
725 giTotalTickets, number);
728 //Log_Debug("Threads", "Switching CPU%i to %p (%s)",
729 // CPU, thread, thread->ThreadName);
735 * \fn void Threads_SegFault(tVAddr Addr)
736 * \brief Called when a Segment Fault occurs
738 void Threads_SegFault(tVAddr Addr)
740 Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
742 //Threads_Exit( 0, -1 );
746 EXPORT(Threads_GetUID);