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

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