Fixing bugs and removing debug statements
[tpg/acess2.git] / Kernel / threads.c
1 /*
2  * Acess2
3  * threads.c
4  * - Common Thread Control
5  */
6 #include <acess.h>
7 #include <threads.h>
8 #include <errno.h>
9
10 // === CONSTANTS ===
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
17         CFGT_NULL
18 };
19
20 // === IMPORTS ===
21 extern void     ArchThreads_Init(void);
22 extern void     Proc_Start(void);
23 extern tThread  *Proc_GetCurThread(void);
24 extern int      Proc_Clone(Uint *Err, Uint Flags);
25 extern void     Proc_CallFaultHandler(tThread *Thread);
26
27 // === PROTOTYPES ===
28 void    Threads_Init(void);
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);
39 void    Threads_Yield(void);
40 void    Threads_Sleep(void);
41 void    Threads_Wake(tThread *Thread);
42 void    Threads_AddActive(tThread *Thread);
43  int    Threads_GetPID(void);
44  int    Threads_GetTID(void);
45 tUID    Threads_GetUID(void);
46  int    Threads_SetUID(Uint *Errno, tUID ID);
47 tGID    Threads_GetGID(void);
48  int    Threads_SetGID(Uint *Errno, tUID ID);
49 void    Threads_Dump(void);
50
51 // === GLOBALS ===
52 // -- Core Thread --
53 tThread gThreadZero = {
54         NULL, 0,        // Next, Lock
55         THREAD_STAT_ACTIVE,     // Status
56         0,      // Exit Status
57         0, 0,   // TID, TGID
58         0, 0,   // UID, GID
59         0,      // Parent Thread ID
60         "ThreadZero",   // Name
61         
62         0,      // Kernel Stack
63         {0},    // Saved State
64         {0},    // VM State
65         
66         0, 0,   // Current Fault, Fault Handler
67         
68         NULL, NULL,     // Messages, Last Message
69         DEFAULT_QUANTUM, DEFAULT_QUANTUM,       // Quantum, Remaining
70         DEFAULT_TICKETS,
71         {0}     // Default config to zero
72         };
73 // -- Processes --
74 // --- Locks ---
75 tSpinlock       glThreadListLock = 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
84  int    giNumCPUs = 1;
85
86 // === CODE ===
87 /**
88  * \fn void Threads_Init(void)
89  * \brief Initialse the thread list
90  */
91 void Threads_Init(void)
92 {
93         ArchThreads_Init();
94         
95         // Create Initial Task
96         gActiveThreads = &gThreadZero;
97         giTotalTickets = gThreadZero.NumTickets;
98         giNumActiveThreads = 1;
99         
100         #if 1
101         // Create Idle Task
102         if(Proc_Clone(0, 0) == 0)
103         {
104                 tThread *cur = Proc_GetCurThread();
105                 cur->ThreadName = "Idle Thread";
106                 Threads_SetTickets(0);  // Never called randomly
107                 cur->Quantum = 1;       // 1 slice quantum
108                 for(;;) HALT(); // Just yeilds
109         }
110         #endif
111         
112         Proc_Start();
113 }
114
115 /**
116  * \fn void Threads_SetName(char *NewName)
117  * \brief Sets the current thread's name
118  */
119 int Threads_SetName(char *NewName)
120 {
121         tThread *cur = Proc_GetCurThread();
122         if( IsHeap(cur->ThreadName) )
123                 free( cur->ThreadName );
124         cur->ThreadName = malloc(strlen(NewName)+1);
125         strcpy(cur->ThreadName, NewName);
126         return 0;
127 }
128
129 /**
130  * \fn char *Threads_GetName(int ID)
131  * \brief Gets a thread's name
132  */
133 char *Threads_GetName(int ID)
134 {
135         if(ID == -1) {
136                 return Proc_GetCurThread()->ThreadName;
137         }
138         return NULL;
139 }
140
141 /**
142  * \fn void Threads_SetTickets(int Num)
143  * \brief Sets the 'priority' of a task
144  */
145 void Threads_SetTickets(int Num)
146 {
147         tThread *cur = Proc_GetCurThread();
148         if(Num < 0)     return;
149         if(Num > MAX_TICKETS)   Num = MAX_TICKETS;
150         
151         LOCK( &glThreadListLock );
152         giTotalTickets -= cur->NumTickets;
153         cur->NumTickets = Num;
154         giTotalTickets += Num;
155         //LOG("giTotalTickets = %i", giTotalTickets);
156         RELEASE( &glThreadListLock );
157 }
158
159 /**
160  * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
161  */
162 tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
163 {
164         tThread *cur, *new;
165          int    i;
166         cur = Proc_GetCurThread();
167         
168         new = malloc(sizeof(tThread));
169         if(new == NULL) {
170                 *Err = -ENOMEM;
171                 return NULL;
172         }
173         memcpy(new, cur, sizeof(tThread));
174         
175         new->Next = NULL;
176         new->IsLocked = 0;
177         new->Status = THREAD_STAT_ACTIVE;
178         new->RetStatus = 0;
179         
180         // Get Thread ID
181         new->TID = giNextTID++;
182         new->PTID = cur->TID;
183         
184         // Clone Name
185         new->ThreadName = strdup(cur->ThreadName);
186         
187         // Set Thread Group ID (PID)
188         if(Flags & CLONE_VM)
189                 new->TGID = new->TID;
190         else
191                 new->TGID = cur->TGID;
192         
193         // Messages are not inherited
194         new->Messages = NULL;
195         new->LastMessage = NULL;
196         
197         // Set State
198         new->Remaining = new->Quantum = cur->Quantum;
199         new->NumTickets = cur->NumTickets;
200         
201         // Set Signal Handlers
202         new->CurFaultNum = 0;
203         new->FaultHandler = cur->FaultHandler;
204         
205         for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
206         {
207                 switch(cCONFIG_TYPES[i])
208                 {
209                 default:
210                         new->Config[i] = cur->Config[i];
211                         break;
212                 case CFGT_HEAPSTR:
213                         if(cur->Config[i])
214                                 new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
215                         else
216                                 new->Config[i] = 0;
217                         break;
218                 }
219         }
220         
221         return new;
222 }
223
224 /**
225  * \fn Uint *Threads_GetCfgPtr(int Id)
226  */
227 Uint *Threads_GetCfgPtr(int Id)
228 {
229         if(Id < 0 || Id >= NUM_CFG_ENTRIES) {
230                 Warning("Threads_GetCfgPtr: Index %i is out of bounds", Id);
231                 return NULL;
232         }
233         
234         return &Proc_GetCurThread()->Config[Id];
235 }
236
237 /**
238  * \fn void Threads_WaitTID(int TID, int *status)
239  * \brief Wait for a task to change state
240  */
241 int Threads_WaitTID(int TID, int *status)
242 {       
243         // Any Child
244         if(TID == -1) {
245                 
246                 return -1;
247         }
248         
249         // Any peer/child thread
250         if(TID == 0) {
251                 
252                 return -1;
253         }
254         
255         // TGID = abs(TID)
256         if(TID < -1) {
257                 return -1;
258         }
259         
260         // Specific Thread
261         if(TID > 0) {
262                 tThread *t = Threads_GetThread(TID);
263                  int    initStatus = t->Status;
264                  int    ret;
265                 
266                 if(initStatus != THREAD_STAT_ZOMBIE) {
267                         while(t->Status == initStatus) {
268                                 Threads_Yield();
269                         }
270                 }
271                 
272                 ret = t->RetStatus;
273                 switch(t->Status)
274                 {
275                 case THREAD_STAT_ZOMBIE:
276                         t->Status = THREAD_STAT_DEAD;
277                         if(status)      *status = 0;
278                         Threads_AddToDelete( t );
279                         break;
280                 default:
281                         if(status)      *status = -1;
282                         break;
283                 }
284                 return ret;
285         }
286         
287         return -1;
288 }
289
290 /**
291  * \fn tThread *Threads_GetThread(Uint TID)
292  * \brief Gets a thread given its TID
293  */
294 tThread *Threads_GetThread(Uint TID)
295 {
296         tThread *thread;
297         
298         // Search Active List
299         for(thread = gActiveThreads;
300                 thread;
301                 thread = thread->Next)
302         {
303                 if(thread->TID == TID)
304                         return thread;
305         }
306         
307         // Search Sleeping List
308         for(thread = gSleepingThreads;
309                 thread;
310                 thread = thread->Next)
311         {
312                 if(thread->TID == TID)
313                         return thread;
314         }
315         
316         return NULL;
317 }
318
319 /**
320  * \fn void Threads_AddToDelete(tThread *Thread)
321  * \brief Adds a thread to the delete queue
322  */
323 void Threads_AddToDelete(tThread *Thread)
324 {
325         // Add to delete queue
326         if(gDeleteThreads) {
327                 Thread->Next = gDeleteThreads;
328                 gDeleteThreads = Thread;
329         } else {
330                 Thread->Next = NULL;
331                 gDeleteThreads = Thread;
332         }
333 }
334
335 /**
336  * \fn tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
337  * \brief Gets the previous entry in a thead linked list
338  */
339 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
340 {
341         tThread *ret;
342         // First Entry
343         if(*List == Thread) {
344                 return (tThread*)List;
345         } else {
346                 for(ret = *List;
347                         ret->Next && ret->Next != Thread;
348                         ret = ret->Next
349                         );
350                 // Error if the thread is not on the list
351                 if(!ret->Next || ret->Next != Thread) {
352                         return NULL;
353                 }
354         }
355         return ret;
356 }
357
358 /**
359  * \fn void Threads_Exit(int TID, int Status)
360  * \brief Exit the current process
361  */
362 void Threads_Exit(int TID, int Status)
363 {
364         if( TID == 0 )
365                 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
366         else
367                 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
368         for(;;) HALT(); // Just in case
369 }
370
371 /**
372  * \fn void Threads_Kill(tThread *Thread, int Status)
373  * \brief Kill a thread
374  * \param Thread        Thread to kill
375  * \param Status        Status code to return to the parent
376  */
377 void Threads_Kill(tThread *Thread, int Status)
378 {
379         tThread *prev;
380         tMsg    *msg;
381         
382         // Kill all children
383         #if 0
384         {
385                 tThread *child;
386                 for(child = gActiveThreads;
387                         child;
388                         child = child->Next)
389                 {
390                         if(child->PTID == Thread->TID)
391                                 Threads_Kill(child, -1);
392                 }
393         }
394         #endif
395         
396         ///\note Double lock is needed due to overlap of locks
397         
398         // Lock thread (stop us recieving messages)
399         LOCK( &Thread->IsLocked );
400         
401         // Lock thread list
402         LOCK( &glThreadListLock );
403         
404         // Get previous thread on list
405         prev = Threads_int_GetPrev( &gActiveThreads, Thread );
406         if(!prev) {
407                 Warning("Proc_Exit - Current thread is not on the active queue");
408                 return;
409         }
410         
411         // Clear Message Queue
412         while( Thread->Messages )
413         {
414                 msg = Thread->Messages->Next;
415                 free( Thread->Messages );
416                 Thread->Messages = msg;
417         }
418         
419         Thread->Remaining = 0;  // Clear Remaining Quantum
420         Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
421         prev->Next = Thread->Next;      // Remove from active
422         
423         giNumActiveThreads --;
424         giTotalTickets -= Thread->NumTickets;
425         
426         // Mark thread as a zombie
427         Thread->RetStatus = Status;
428         
429         // Don't Zombie if we are being killed as part of a tree
430         if(Status == -1)
431         {
432                 Thread->Status = THREAD_STAT_DEAD;
433                 Threads_AddToDelete( Thread );
434         } else {
435                 Thread->Status = THREAD_STAT_ZOMBIE;
436         }
437         
438         // Release spinlocks
439         RELEASE( &Thread->IsLocked );   // Released first so that it IS released
440         RELEASE( &glThreadListLock );
441         
442         //Log("Thread %i went *hurk*", Thread->TID);
443         
444         if(Status != -1)        HALT();
445 }
446
447 /**
448  * \fn void Threads_Yield(void)
449  * \brief Yield remainder of timeslice
450  */
451 void Threads_Yield(void)
452 {
453         Proc_GetCurThread()->Remaining = 0;
454         HALT();
455 }
456
457 /**
458  * \fn void Threads_Sleep(void)
459  * \brief Take the current process off the run queue
460  */
461 void Threads_Sleep(void)
462 {
463         tThread *cur = Proc_GetCurThread();
464         tThread *thread;
465         
466         //Log_Log("Threads", "%i going to sleep", cur->TID);
467         
468         // Acquire Spinlock
469         LOCK( &glThreadListLock );
470         
471         // Get thread before current thread
472         thread = Threads_int_GetPrev( &gActiveThreads, cur );
473         if(!thread) {
474                 Warning("Threads_Sleep - Current thread is not on the active queue");
475                 Threads_Dump();
476                 return;
477         }
478         
479         // Don't sleep if there is a message waiting
480         if( cur->Messages ) {
481                 RELEASE( &glThreadListLock );
482                 return;
483         }
484         
485         // Unset remaining timeslices (force a task switch on timer fire)
486         cur->Remaining = 0;
487         
488         // Remove from active list
489         thread->Next = cur->Next;
490         
491         // Add to Sleeping List (at the top)
492         cur->Next = gSleepingThreads;
493         gSleepingThreads = cur;
494         
495         // Reduce the active count & ticket count
496         giNumActiveThreads --;
497         giTotalTickets -= cur->NumTickets;
498         
499         // Mark thread as sleeping
500         cur->Status = THREAD_STAT_SLEEPING;
501         
502         // Release Spinlock
503         RELEASE( &glThreadListLock );
504         
505         while(cur->Status != THREAD_STAT_ACTIVE)        HALT();
506 }
507
508
509 /**
510  * \fn void Threads_Wake( tThread *Thread )
511  * \brief Wakes a sleeping/waiting thread up
512  */
513 void Threads_Wake(tThread *Thread)
514 {
515         tThread *prev;
516         switch(Thread->Status)
517         {
518         case THREAD_STAT_ACTIVE:        break;
519         case THREAD_STAT_SLEEPING:
520                 //Log_Log("Threads", "Waking %i (%p) from sleeping", Thread->TID, Thread);
521                 LOCK( &glThreadListLock );
522                 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
523                 prev->Next = Thread->Next;      // Remove from sleeping queue
524                 Thread->Next = gActiveThreads;  // Add to active queue
525                 gActiveThreads = Thread;
526                 giNumActiveThreads ++;
527                 giTotalTickets += Thread->NumTickets;
528                 Thread->Status = THREAD_STAT_ACTIVE;
529                 RELEASE( &glThreadListLock );
530                 break;
531         case THREAD_STAT_WAITING:
532                 Warning("Thread_Wake - Waiting threads are not currently supported");
533                 break;
534         case THREAD_STAT_DEAD:
535                 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
536                 break;
537         default:
538                 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
539                 break;
540         }
541 }
542
543 void Threads_WakeTID(tTID Thread)
544 {
545         Threads_Wake( Threads_GetThread(Thread) );
546 }
547
548 /**
549  * \fn void Threads_AddActive(tThread *Thread)
550  * \brief Adds a thread to the active queue
551  */
552 void Threads_AddActive(tThread *Thread)
553 {
554         LOCK( &glThreadListLock );
555         Thread->Next = gActiveThreads;
556         gActiveThreads = Thread;
557         giNumActiveThreads ++;
558         giTotalTickets += Thread->NumTickets;
559         //Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
560         //      giNumActiveThreads, giTotalTickets);
561         RELEASE( &glThreadListLock );
562 }
563
564 /**
565  * \fn void Threads_SetFaultHandler(Uint Handler)
566  * \brief Sets the signal handler for a signal
567  */
568 void Threads_SetFaultHandler(Uint Handler)
569 {       
570         Log_Log("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
571         Proc_GetCurThread()->FaultHandler = Handler;
572 }
573
574 /**
575  * \fn void Threads_Fault(int Num)
576  * \brief Calls a fault handler
577  */
578 void Threads_Fault(int Num)
579 {
580         tThread *thread = Proc_GetCurThread();
581         
582         Log_Log("Threads", "Threads_Fault: thread = %p", thread);
583         
584         if(!thread)     return ;
585         
586         Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
587         
588         switch(thread->FaultHandler)
589         {
590         case 0: // Panic?
591                 Threads_Kill(thread, -1);
592                 HALT();
593                 return ;
594         case 1: // Dump Core?
595                 Threads_Kill(thread, -1);
596                 HALT();
597                 return ;
598         }
599         
600         // Double Fault? Oh, F**k
601         if(thread->CurFaultNum != 0) {
602                 Threads_Kill(thread, -1);       // For now, just kill
603                 HALT();
604         }
605         
606         thread->CurFaultNum = Num;
607         
608         Proc_CallFaultHandler(thread);
609 }
610
611 // --- Process Structure Access Functions ---
612 tPID Threads_GetPID(void)
613 {
614         return Proc_GetCurThread()->TGID;
615 }
616 tTID Threads_GetTID(void)
617 {
618         return Proc_GetCurThread()->TID;
619 }
620 tUID Threads_GetUID(void)
621 {
622         return Proc_GetCurThread()->UID;
623 }
624 tGID Threads_GetGID(void)
625 {
626         return Proc_GetCurThread()->GID;
627 }
628
629 int Threads_SetUID(Uint *Errno, tUID ID)
630 {
631         tThread *t = Proc_GetCurThread();
632         if( t->UID != 0 ) {
633                 *Errno = -EACCES;
634                 return -1;
635         }
636         Log("Threads_SetUID - Setting User ID to %i", ID);
637         t->UID = ID;
638         return 0;
639 }
640
641 int Threads_SetGID(Uint *Errno, tGID ID)
642 {
643         tThread *t = Proc_GetCurThread();
644         if( t->UID != 0 ) {
645                 *Errno = -EACCES;
646                 return -1;
647         }
648         Log("Threads_SetGID - Setting Group ID to %i", ID);
649         t->GID = ID;
650         return 0;
651 }
652
653 /**
654  * \fn void Threads_Dump(void)
655  * \brief Dums a list of currently running threads
656  */
657 void Threads_Dump(void)
658 {
659         tThread *thread;
660         tThread *cur = Proc_GetCurThread();
661         
662         Log("Active Threads:");
663         for(thread=gActiveThreads;thread;thread=thread->Next)
664         {
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);
670         }
671         Log("Sleeping Threads:");
672         for(thread=gSleepingThreads;thread;thread=thread->Next)
673         {
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);
679         }
680 }
681
682 /**
683  * \fn tThread *Threads_GetNextToRun(int CPU)
684  * \brief Gets the next thread to run
685  */
686 tThread *Threads_GetNextToRun(int CPU)
687 {
688         tThread *thread;
689          int    ticket;
690          int    number;
691         
692         if(giNumActiveThreads == 0) {
693                 return NULL;
694         }
695         
696         // Special case: 1 thread
697         if(giNumActiveThreads == 1) {
698                 return gActiveThreads;
699         }
700         
701         // Get the ticket number
702         ticket = number = rand() % giTotalTickets;
703         
704         // Find the next thread
705         for(thread=gActiveThreads;thread;thread=thread->Next)
706         {
707                 if(thread->NumTickets > number) break;
708                 number -= thread->NumTickets;
709         }
710         
711         // Error Check
712         if(thread == NULL)
713         {
714                 number = 0;
715                 for(thread=gActiveThreads;thread;thread=thread->Next)
716                         number += thread->NumTickets;
717                 Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
718                         giTotalTickets, number);
719         }
720         
721         return thread;
722 }
723
724 /**
725  * \fn void Threads_SegFault(tVAddr Addr)
726  * \brief Called when a Segment Fault occurs
727  */
728 void Threads_SegFault(tVAddr Addr)
729 {
730         Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
731         Threads_Fault( 1 );
732         //Threads_Exit( 0, -1 );
733 }
734
735 // === EXPORTS ===
736 EXPORT(Threads_GetUID);

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