Removed debug
[tpg/acess2.git] / Kernel / threads.c
1 /*
2  * Acess2
3  * threads.c
4  * - Common Thread Control
5  */
6 #include <common.h>
7 #include <threads.h>
8
9 // === CONSTANTS ===
10 #define DEFAULT_QUANTUM 10
11 #define DEFAULT_TICKETS 5
12 #define MAX_TICKETS             10
13
14 // === IMPORTS ===
15 extern void     ArchThreads_Init();
16 extern void     Proc_Start();
17 extern tThread  *Proc_GetCurThread();
18 extern int      Proc_Clone(Uint *Err, Uint Flags);
19
20 // === PROTOTYPES ===
21 void    Threads_Init();
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);
30 void    Threads_Yield();
31 void    Threads_Sleep();
32 void    Threads_Wake(tThread *Thread);
33 void    Threads_AddActive(tThread *Thread);
34  int    Threads_GetPID();
35  int    Threads_GetTID();
36  int    Threads_GetUID();
37  int    Threads_GetGID();
38 void    Threads_Dump();
39
40 // === GLOBALS ===
41 // -- Core Thread --
42 tThread gThreadZero = {
43         NULL, 0,        // Next, Lock
44         THREAD_STAT_ACTIVE,     // Status
45         0,      // Exit Status
46         0, 0,   // TID, TGID
47         0, 0,   // UID, GID
48         0,      // Parent Thread ID
49         "ThreadZero",   // Name
50         
51         0,      // Kernel Stack
52         {0},    // Saved State
53         {0},    // VM State
54         
55         0, {0}, {0},    // Signal State
56         
57         NULL, NULL,     // Messages, Last Message
58         DEFAULT_QUANTUM, DEFAULT_QUANTUM,       // Quantum, Remaining
59         DEFAULT_TICKETS,
60         {0}     // Default config to zero
61         };
62 // -- Processes --
63 // --- Locks ---
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
73  int    giNumCPUs = 1;
74
75 // === CODE ===
76 /**
77  * \fn void Threads_Init()
78  * \brief Initialse the thread list
79  */
80 void Threads_Init()
81 {
82         ArchThreads_Init();
83         
84         // Create Initial Task
85         gActiveThreads = &gThreadZero;
86         giTotalTickets = gThreadZero.NumTickets;
87         giNumActiveThreads = 1;
88         
89         #if 1
90         // Create Idle Task
91         if(Proc_Clone(0, 0) == 0)
92         {
93                 tThread *cur = Proc_GetCurThread();
94                 cur->ThreadName = "Idle Thread";
95                 Threads_SetTickets(0);  // Never called randomly
96                 cur->Quantum = 1;       // 1 slice quantum
97                 HALT();
98                 for(;;) {
99                         HALT(); // Just yeilds
100                 }
101         }
102         #endif
103         
104         Proc_Start();
105 }
106
107 /**
108  * \fn void Threads_SetName(char *NewName)
109  * \brief Sets the current thread's name
110  */
111 void Threads_SetName(char *NewName)
112 {
113         tThread *cur = Proc_GetCurThread();
114         if( IsHeap(cur->ThreadName) )
115                 free( cur->ThreadName );
116         cur->ThreadName = malloc(strlen(NewName)+1);
117         strcpy(cur->ThreadName, NewName);
118 }
119
120 /**
121  * \fn void Threads_SetTickets(int Num)
122  * \brief Sets the 'priority' of a task
123  */
124 void Threads_SetTickets(int Num)
125 {
126         tThread *cur = Proc_GetCurThread();
127         if(Num < 0)     return;
128         if(Num > MAX_TICKETS)   Num = MAX_TICKETS;
129         
130         LOCK( &giThreadListLock );
131         giTotalTickets -= cur->NumTickets;
132         cur->NumTickets = Num;
133         giTotalTickets += Num;
134         //LOG("giTotalTickets = %i", giTotalTickets);
135         RELEASE( &giThreadListLock );
136 }
137
138 /**
139  * \fn void Threads_WaitTID(int TID, int *status)
140  * \brief Wait for a task to change state
141  */
142 int Threads_WaitTID(int TID, int *status)
143 {       
144         // Any Child
145         if(TID == -1) {
146                 
147                 return -1;
148         }
149         
150         // Any peer/child thread
151         if(TID == 0) {
152                 
153                 return -1;
154         }
155         
156         // TGID = abs(TID)
157         if(TID < -1) {
158                 return -1;
159         }
160         
161         // Specific Thread
162         if(TID > 0) {
163                 tThread *t = Threads_GetThread(TID);
164                  int    initStatus = t->Status;
165                  int    ret;
166                 while(t->Status == initStatus)  Threads_Yield();
167                 ret = t->RetStatus;
168                 switch(t->Status)
169                 {
170                 case THREAD_STAT_ZOMBIE:
171                         t->Status = THREAD_STAT_DEAD;
172                         if(status)      *status = 0;
173                         Threads_AddToDelete( t );
174                         break;
175                 default:
176                         if(status)      *status = -1;
177                         break;
178                 }
179                 return ret;
180         }
181         
182         return -1;
183 }
184
185 /**
186  * \fn tThread *Threads_GetThread(Uint TID)
187  * \brief Gets a thread given its TID
188  */
189 tThread *Threads_GetThread(Uint TID)
190 {
191         tThread *thread;
192         
193         // Search Active List
194         for(thread = gActiveThreads;
195                 thread;
196                 thread = thread->Next)
197         {
198                 if(thread->TID == TID)
199                         return thread;
200         }
201         
202         // Search Sleeping List
203         for(thread = gSleepingThreads;
204                 thread;
205                 thread = thread->Next)
206         {
207                 if(thread->TID == TID)
208                         return thread;
209         }
210         
211         return NULL;
212 }
213
214 /**
215  * \fn void Threads_AddToDelete(tThread *Thread)
216  * \brief Adds a thread to the delete queue
217  */
218 void Threads_AddToDelete(tThread *Thread)
219 {
220         // Add to delete queue
221         if(gDeleteThreads) {
222                 Thread->Next = gDeleteThreads;
223                 gDeleteThreads = Thread;
224         } else {
225                 Thread->Next = NULL;
226                 gDeleteThreads = Thread;
227         }
228 }
229
230 /**
231  * \fn tThread *Threads_int_GetPrev(tThread *List, tThread *Thread)
232  * \brief Gets the previous entry in a thead linked list
233  */
234 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
235 {
236         tThread *ret;
237         // First Entry
238         if(*List == Thread) {
239                 return (tThread*)List;
240         } else {
241                 for(ret = *List;
242                         ret->Next && ret->Next != Thread;
243                         ret = ret->Next
244                         );
245                 // Error if the thread is not on the list
246                 if(!ret->Next || ret->Next != Thread) {
247                         return NULL;
248                 }
249         }
250         return ret;
251 }
252
253 /**
254  * \fn void Threads_Exit(int TID, int Status)
255  * \brief Exit the current process
256  */
257 void Threads_Exit(int TID, int Status)
258 {
259         Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
260 }
261
262 /**
263  * \fn void Threads_Kill(tThread *Thread, int Status)
264  * \brief Kill a thread
265  * \param TID   Thread ID (0 for current)
266  */
267 void Threads_Kill(tThread *Thread, int Status)
268 {
269         tThread *prev;
270         tMsg    *msg;
271         
272         // Kill all children
273         #if 0
274         {
275                 tThread *child;
276                 for(child = gActiveThreads;
277                         child;
278                         child = child->Next)
279                 {
280                         if(child->PTID == gCurrentThread->TID)
281                                 Threads_Kill(child, -1);
282                 }
283         }
284         #endif
285         
286         ///\note Double lock is needed due to overlap of locks
287         
288         // Lock thread (stop us recieving messages)
289         LOCK( &Thread->IsLocked );
290         
291         // Lock thread list
292         LOCK( &giThreadListLock );
293         
294         // Get previous thread on list
295         prev = Threads_int_GetPrev( &gActiveThreads, Thread );
296         if(!prev) {
297                 Warning("Proc_Exit - Current thread is not on the active queue");
298                 return;
299         }
300         
301         // Clear Message Queue
302         while( Thread->Messages )
303         {
304                 msg = Thread->Messages->Next;
305                 free( Thread->Messages );
306                 Thread->Messages = msg;
307         }
308         
309         Thread->Remaining = 0;  // Clear Remaining Quantum
310         Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
311         prev->Next = Thread->Next;      // Remove from active
312         
313         giNumActiveThreads --;
314         giTotalTickets -= Thread->NumTickets;
315         
316         // Mark thread as a zombie
317         Thread->RetStatus = Status;
318         
319         // Don't Zombie if we are being killed as part of a tree
320         if(Status == -1)
321         {
322                 Thread->Status = THREAD_STAT_DEAD;
323                 Threads_AddToDelete( Thread );
324         } else {
325                 Thread->Status = THREAD_STAT_ZOMBIE;
326         }
327         
328         // Release spinlocks
329         RELEASE( &Thread->IsLocked );   // Released first so that it IS released
330         RELEASE( &giThreadListLock );
331         if(Status != -1)        HALT();
332 }
333
334 /**
335  * \fn void Threads_Yield()
336  * \brief Yield remainder of timeslice
337  */
338 void Threads_Yield()
339 {
340         Proc_GetCurThread()->Remaining = 0;
341         HALT();
342 }
343
344 /**
345  * \fn void Threads_Sleep()
346  * \brief Take the current process off the run queue
347  */
348 void Threads_Sleep()
349 {
350         tThread *cur = Proc_GetCurThread();
351         tThread *thread;
352         
353         Log("Proc_Sleep: %i going to sleep", cur->TID);
354         
355         // Acquire Spinlock
356         LOCK( &giThreadListLock );
357         
358         // Get thread before current thread
359         thread = Threads_int_GetPrev( &gActiveThreads, cur );
360         if(!thread) {
361                 Warning("Proc_Sleep - Current thread is not on the active queue");
362                 return;
363         }
364         
365         // Don't sleep if there is a message waiting
366         if( cur->Messages ) {
367                 RELEASE( &giThreadListLock );
368                 return;
369         }
370         
371         // Unset remaining timeslices (force a task switch on timer fire)
372         cur->Remaining = 0;
373         
374         // Remove from active list
375         thread->Next = cur->Next;
376         
377         // Add to Sleeping List (at the top)
378         cur->Next = gSleepingThreads;
379         gSleepingThreads = cur;
380         
381         // Reduce the active count & ticket count
382         giNumActiveThreads --;
383         giTotalTickets -= cur->NumTickets;
384         
385         // Mark thread as sleeping
386         cur->Status = THREAD_STAT_SLEEPING;
387         
388         // Release Spinlock
389         RELEASE( &giThreadListLock );
390         
391         HALT();
392 }
393
394
395 /**
396  * \fn void Threads_Wake( tThread *Thread )
397  * \brief Wakes a sleeping/waiting thread up
398  */
399 void Threads_Wake(tThread *Thread)
400 {
401         tThread *prev;
402         switch(Thread->Status)
403         {
404         case THREAD_STAT_ACTIVE:        break;
405         case THREAD_STAT_SLEEPING:
406                 LOCK( &giThreadListLock );
407                 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
408                 prev->Next = Thread->Next;      // Remove from sleeping queue
409                 Thread->Next = gActiveThreads;  // Add to active queue
410                 gActiveThreads = Thread;
411                 Thread->Status = THREAD_STAT_ACTIVE;
412                 RELEASE( &giThreadListLock );
413                 break;
414         case THREAD_STAT_WAITING:
415                 Warning("Thread_Wake - Waiting threads are not currently supported");
416                 break;
417         case THREAD_STAT_DEAD:
418                 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
419                 break;
420         default:
421                 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
422                 break;
423         }
424 }
425
426 /**
427  * \fn void Threads_AddActive(tThread *Thread)
428  * \brief Adds a thread to the active queue
429  */
430 void Threads_AddActive(tThread *Thread)
431 {
432         LOCK( &giThreadListLock );
433         Thread->Next = gActiveThreads;
434         gActiveThreads = Thread;
435         giNumActiveThreads ++;
436         giTotalTickets += Thread->NumTickets;
437         //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
438         //      giNumActiveThreads, giTotalTickets);
439         RELEASE( &giThreadListLock );
440 }
441
442 #if 0
443 /**
444  * \fn void Threads_SetSignalHandler(int Num, void *Handler)
445  * \brief Sets the signal handler for a signal
446  */
447 void Threads_SetSignalHandler(int Num, void *Handler)
448 {
449         if(Num < 0 || Num >= NSIG)      return;
450         
451         gCurrentThread->SignalHandlers[Num] = Handler;
452 }
453
454 /**
455  * \fn void Threads_SendSignal(int TID, int Num)
456  */
457 void Threads_SendSignal(int TID, int Num)
458 {
459         tThread *thread = Proc_GetThread(TID);
460         void    *handler;
461         
462         if(!thread)     return ;
463         
464         handler = thread->SignalHandlers[Num];
465         
466         // Panic?
467         if(handler == SIG_ERR) {
468                 Proc_Kill(TID);
469                 return ;
470         }
471         // Dump Core?
472         if(handler == -2) {
473                 Proc_Kill(TID);
474                 return ;
475         }
476         // Ignore?
477         if(handler == -2)       return;
478         
479         // Check the type and handle if the thread is already in a signal
480         if(thread->CurSignal != 0) {
481                 if(Num < _SIGTYPE_FATAL)
482                         Proc_Kill(TID);
483                 } else {
484                         while(thread->CurSignal != 0)
485                                 Proc_Yield();
486                 }
487         }
488         
489         //TODO: 
490 }
491 #endif
492
493 // --- Process Structure Access Functions ---
494 int Threads_GetPID()
495 {
496         return Proc_GetCurThread()->TGID;
497 }
498 int Threads_GetTID()
499 {
500         return Proc_GetCurThread()->TID;
501 }
502 int Threads_GetUID()
503 {
504         return Proc_GetCurThread()->UID;
505 }
506 int Threads_GetGID()
507 {
508         return Proc_GetCurThread()->GID;
509 }
510
511 /**
512  * \fn void Threads_Dump()
513  * \brief Dums a list of currently running threads
514  */
515 void Threads_Dump()
516 {
517         tThread *thread;
518         
519         Log("Active Threads:");
520         for(thread=gActiveThreads;thread;thread=thread->Next)
521         {
522                 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
523                 Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
524                 Log("  KStack 0x%x", thread->KernelStack);
525         }
526         Log("Sleeping Threads:");
527         for(thread=gSleepingThreads;thread;thread=thread->Next)
528         {
529                 Log(" %i (%i) - %s", thread->TID, thread->TGID, thread->ThreadName);
530                 Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
531                 Log("  KStack 0x%x", thread->KernelStack);
532         }
533 }
534
535 /**
536  * \fn tThread *Threads_GetNextToRun(int CPU)
537  * \brief Gets the next thread to run
538  */
539 tThread *Threads_GetNextToRun(int CPU)
540 {
541         tThread *thread;
542          int    ticket;
543          int    number;
544         
545         // Special case: 1 thread
546         if(giNumActiveThreads == 1)
547         {
548                 return gActiveThreads;
549         }
550         
551         //Log(" Threads_GetNextToRun: giNumActiveThreads=%i,giTotalTickets=%i",
552         //      giNumActiveThreads, giTotalTickets);
553         // Get the ticket number
554         ticket = number = rand() % giTotalTickets;
555         
556         //Log(" Threads_GetNextToRun: ticket = %i", ticket);
557         
558         // Find the next thread
559         for(thread=gActiveThreads;thread;thread=thread->Next)
560         {
561                 if(thread->NumTickets > number) break;
562                 number -= thread->NumTickets;
563         }
564         
565         // Error Check
566         if(thread == NULL)
567         {
568                 number = 0;
569                 for(thread=gActiveThreads;thread;thread=thread->Next)
570                         number += thread->NumTickets;
571                 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
572                         giTotalTickets, number);
573         }
574         
575         return thread;
576 }

UCC git Repository :: git.ucc.asn.au