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

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