Fixed TID0 not being on the All Threads list
[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 #define DEBUG_TRACE_TICKETS     0       // Trace ticket counts
11 #define DEBUG_TRACE_STATE       0       // Trace state changes (sleep/wake)
12
13 // === CONSTANTS ===
14 #define DEFAULT_QUANTUM 10
15 #define DEFAULT_TICKETS 5
16 #define MAX_TICKETS             10
17 const enum eConfigTypes cCONFIG_TYPES[] = {
18         CFGT_HEAPSTR,   // e.g. CFG_VFS_CWD
19         CFGT_INT,       // e.g. CFG_VFS_MAXFILES
20         CFGT_NULL
21 };
22
23 // === IMPORTS ===
24 extern void     ArchThreads_Init(void);
25 extern void     Proc_Start(void);
26 extern tThread  *Proc_GetCurThread(void);
27 extern int      Proc_Clone(Uint *Err, Uint Flags);
28 extern void     Proc_CallFaultHandler(tThread *Thread);
29
30 // === PROTOTYPES ===
31 void    Threads_Init(void);
32  int    Threads_SetName(char *NewName);
33 char    *Threads_GetName(int ID);
34 void    Threads_SetTickets(tThread *Thread, int Num);
35 tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
36  int    Threads_WaitTID(int TID, int *status);
37 tThread *Threads_GetThread(Uint TID);
38 void    Threads_AddToDelete(tThread *Thread);
39 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread);
40 void    Threads_Exit(int TID, int Status);
41 void    Threads_Kill(tThread *Thread, int Status);
42 void    Threads_Yield(void);
43 void    Threads_Sleep(void);
44  int    Threads_Wake(tThread *Thread);
45 void    Threads_AddActive(tThread *Thread);
46 tThread *Threads_RemActive(void);
47  int    Threads_GetPID(void);
48  int    Threads_GetTID(void);
49 tUID    Threads_GetUID(void);
50  int    Threads_SetUID(Uint *Errno, tUID ID);
51 tGID    Threads_GetGID(void);
52  int    Threads_SetGID(Uint *Errno, tUID ID);
53 void    Threads_Dump(void);
54 void    Mutex_Acquire(tMutex *Mutex);
55 void    Mutex_Release(tMutex *Mutex);
56  int    Mutex_IsLocked(tMutex *Mutex);
57
58 // === GLOBALS ===
59 // -- Core Thread --
60 // Only used for the core kernel
61 tThread gThreadZero = {
62         Status: THREAD_STAT_ACTIVE,     // Status
63         ThreadName:     "ThreadZero",   // Name
64         Quantum: DEFAULT_QUANTUM,       // Default Quantum
65         Remaining:      DEFAULT_QUANTUM,        // Current Quantum
66         NumTickets:     DEFAULT_TICKETS // Number of tickets
67         };
68 // -- Processes --
69 // --- Locks ---
70 tShortSpinlock  glThreadListLock;       ///\note NEVER use a heap function while locked
71 // --- Current State ---
72 volatile int    giNumActiveThreads = 0;
73 volatile int    giFreeTickets = 0;
74 volatile Uint   giNextTID = 1;
75 // --- Thread Lists ---
76 tThread *gAllThreads = NULL;            // All allocated threads
77 tThread *gActiveThreads = NULL;         // Currently Running Threads
78 tThread *gSleepingThreads = NULL;       // Sleeping Threads
79 tThread *gDeleteThreads = NULL;         // Threads to delete
80  int    giNumCPUs = 1;
81
82 // === CODE ===
83 /**
84  * \fn void Threads_Init(void)
85  * \brief Initialse the thread list
86  */
87 void Threads_Init(void)
88 {
89         ArchThreads_Init();
90         
91         // Create Initial Task
92         gActiveThreads = &gThreadZero;
93         gAllThreads = &gThreadZero;
94         //giFreeTickets = gThreadZero.NumTickets;
95         giNumActiveThreads = 1;
96                 
97         Proc_Start();
98 }
99
100 /**
101  * \fn void Threads_SetName(char *NewName)
102  * \brief Sets the current thread's name
103  */
104 int Threads_SetName(char *NewName)
105 {
106         tThread *cur = Proc_GetCurThread();
107         char    *oldname = cur->ThreadName;
108         
109         cur->ThreadName = NULL;
110         
111         if( IsHeap(oldname) )   free( oldname );
112         
113         cur->ThreadName = strdup(NewName);
114         return 0;
115 }
116
117 /**
118  * \fn char *Threads_GetName(int ID)
119  * \brief Gets a thread's name
120  */
121 char *Threads_GetName(int ID)
122 {
123         if(ID == -1) {
124                 return Proc_GetCurThread()->ThreadName;
125         }
126         // TODO: Find a thread and get its name
127         return NULL;
128 }
129
130 /**
131  * \fn void Threads_SetTickets(tThread *Thread, int Num)
132  * \brief Sets the 'priority' of a task
133  */
134 void Threads_SetTickets(tThread *Thread, int Num)
135 {
136         if(Thread == NULL)
137                 Thread = Proc_GetCurThread();
138         if(Num < 0)     return;
139         if(Num > MAX_TICKETS)   Num = MAX_TICKETS;
140         
141         if( Thread != Proc_GetCurThread() ) {
142                 SHORTLOCK( &glThreadListLock );
143                 giFreeTickets -= Thread->NumTickets - Num;
144                 Thread->NumTickets = Num;
145                 SHORTREL( &glThreadListLock );
146         }
147         else
148                 Thread->NumTickets = Num;
149 }
150
151 /**
152  * \fn tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
153  */
154 tThread *Threads_CloneTCB(Uint *Err, Uint Flags)
155 {
156         tThread *cur, *new;
157          int    i;
158         cur = Proc_GetCurThread();
159         
160         new = malloc(sizeof(tThread));
161         if(new == NULL) {
162                 *Err = -ENOMEM;
163                 return NULL;
164         }
165         memcpy(new, cur, sizeof(tThread));
166         
167         new->CurCPU = -1;
168         new->Next = NULL;
169         memset( &new->IsLocked, 0, sizeof(new->IsLocked));
170         new->Status = THREAD_STAT_ACTIVE;
171         new->RetStatus = 0;
172         
173         // Get Thread ID
174         new->TID = giNextTID++;
175         new->Parent = cur;
176         
177         // Clone Name
178         new->ThreadName = strdup(cur->ThreadName);
179         
180         // Set Thread Group ID (PID)
181         if(Flags & CLONE_VM)
182                 new->TGID = new->TID;
183         else
184                 new->TGID = cur->TGID;
185         
186         // Messages are not inherited
187         new->Messages = NULL;
188         new->LastMessage = NULL;
189         
190         // Set State
191         new->Remaining = new->Quantum = cur->Quantum;
192         new->NumTickets = cur->NumTickets;
193         
194         // Set Signal Handlers
195         new->CurFaultNum = 0;
196         new->FaultHandler = cur->FaultHandler;
197         
198         for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
199         {
200                 switch(cCONFIG_TYPES[i])
201                 {
202                 default:
203                         new->Config[i] = cur->Config[i];
204                         break;
205                 case CFGT_HEAPSTR:
206                         if(cur->Config[i])
207                                 new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
208                         else
209                                 new->Config[i] = 0;
210                         break;
211                 }
212         }
213         
214         // Maintain a global list of threads
215         SHORTLOCK( &glThreadListLock );
216         new->GlobalPrev = NULL; // Protect against bugs
217         new->GlobalNext = gAllThreads;
218         gAllThreads = new;
219         SHORTREL( &glThreadListLock );
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 tTID Threads_WaitTID(int TID, int *status)
239  * \brief Wait for a task to change state
240  * \return TID of child that changed state
241  */
242 int Threads_WaitTID(int TID, int *status)
243 {       
244         // Any Child
245         if(TID == -1) {
246                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
247                 return -1;
248         }
249         
250         // Any peer/child thread
251         if(TID == 0) {
252                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
253                 return -1;
254         }
255         
256         // TGID = abs(TID)
257         if(TID < -1) {
258                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
259                 return -1;
260         }
261         
262         // Specific Thread
263         if(TID > 0) {
264                 tThread *t = Threads_GetThread(TID);
265                  int    initStatus = t->Status;
266                  int    ret;
267                 
268                 if(initStatus != THREAD_STAT_ZOMBIE) {
269                         // TODO: Handle child also being suspended if wanted
270                         while(t->Status != THREAD_STAT_ZOMBIE) {
271                                 Threads_Sleep();
272                                 Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
273                                         Threads_GetTID(), t->TID, t->Status);
274                         }
275                 }
276                 
277                 Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
278                         Threads_GetTID(), t->TID, t->Status);
279                 ret = t->RetStatus;
280                 switch(t->Status)
281                 {
282                 case THREAD_STAT_ZOMBIE:
283                         // Kill the thread
284                         t->Status = THREAD_STAT_DEAD;
285                         // TODO: Child return value?
286                         if(status)      *status = 0;
287                         // add to delete queue
288                         Threads_AddToDelete( t );
289                         break;
290                 default:
291                         if(status)      *status = -1;
292                         break;
293                 }
294                 return ret;
295         }
296         
297         return -1;
298 }
299
300 /**
301  * \fn tThread *Threads_GetThread(Uint TID)
302  * \brief Gets a thread given its TID
303  * \param TID   Thread ID
304  */
305 tThread *Threads_GetThread(Uint TID)
306 {
307         tThread *thread;
308         
309         // Search global list
310         for(thread = gAllThreads;
311                 thread;
312                 thread = thread->GlobalNext)
313         {
314                 if(thread->TID == TID)
315                         return thread;
316         }
317
318         Log("Unable to find TID %i on main list\n", TID);
319         
320         return NULL;
321 }
322
323 /**
324  * \fn void Threads_AddToDelete(tThread *Thread)
325  * \brief Adds a thread to the delete queue
326  */
327 void Threads_AddToDelete(tThread *Thread)
328 {
329         // Add to delete queue
330         if(gDeleteThreads) {
331                 Thread->Next = gDeleteThreads;
332                 gDeleteThreads = Thread;
333         } else {
334                 Thread->Next = NULL;
335                 gDeleteThreads = Thread;
336         }
337 }
338
339 /**
340  * \fn tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
341  * \brief Gets the previous entry in a thead linked list
342  */
343 tThread *Threads_int_GetPrev(tThread **List, tThread *Thread)
344 {
345         tThread *ret;
346         // First Entry
347         if(*List == Thread) {
348                 return (tThread*)List;
349         } else {
350                 for(ret = *List;
351                         ret->Next && ret->Next != Thread;
352                         ret = ret->Next
353                         );
354                 // Error if the thread is not on the list
355                 if(!ret->Next || ret->Next != Thread) {
356                         return NULL;
357                 }
358         }
359         return ret;
360 }
361
362 /**
363  * \fn void Threads_Exit(int TID, int Status)
364  * \brief Exit the current process
365  */
366 void Threads_Exit(int TID, int Status)
367 {
368         if( TID == 0 )
369                 Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
370         else
371                 Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
372         // Halt forever, just in case
373         for(;;)
374                 HALT();
375 }
376
377 /**
378  * \fn void Threads_Kill(tThread *Thread, int Status)
379  * \brief Kill a thread
380  * \param Thread        Thread to kill
381  * \param Status        Status code to return to the parent
382  */
383 void Threads_Kill(tThread *Thread, int Status)
384 {
385         tThread *prev;
386         tMsg    *msg;
387         
388         // Kill all children
389         #if 0
390         {
391                 tThread *child;
392                 for(child = gActiveThreads;
393                         child;
394                         child = child->Next)
395                 {
396                         if(child->PTID == Thread->TID)
397                                 Threads_Kill(child, -1);
398                 }
399         }
400         #endif
401         
402         ///\note Double lock is needed due to overlap of lock areas
403         
404         // Lock thread (stop us recieving messages)
405         SHORTLOCK( &Thread->IsLocked );
406         
407         // Lock thread list
408         SHORTLOCK( &glThreadListLock );
409         
410         // Get previous thread on list
411         prev = Threads_int_GetPrev( &gActiveThreads, Thread );
412         if(!prev) {
413                 Warning("Proc_Exit - Current thread is not on the active queue");
414                 SHORTREL( &Thread->IsLocked );
415                 SHORTREL( &glThreadListLock );
416                 return;
417         }
418         
419         // Clear Message Queue
420         while( Thread->Messages )
421         {
422                 msg = Thread->Messages->Next;
423                 free( Thread->Messages );
424                 Thread->Messages = msg;
425         }
426         
427         Thread->Remaining = 0;  // Clear Remaining Quantum
428         Thread->Quantum = 0;    // Clear Quantum to indicate dead thread
429         prev->Next = Thread->Next;      // Remove from active
430         
431         giNumActiveThreads --;
432         if( Thread != Proc_GetCurThread() )
433                 giFreeTickets -= Thread->NumTickets;
434         
435         // Save exit status
436         Thread->RetStatus = Status;
437         
438         // Don't Zombie if we are being killed as part of a tree
439         if(Status == -1)
440         {
441                 Thread->Status = THREAD_STAT_DEAD;
442                 Threads_AddToDelete( Thread );
443         } else {
444                 Thread->Status = THREAD_STAT_ZOMBIE;
445                 // Wake parent
446                 Threads_Wake( Thread->Parent );
447         }
448         
449         Log("Thread %i went *hurk* (%i)", Thread->TID, Thread->Status);
450         
451         // Release spinlocks
452         SHORTREL( &Thread->IsLocked );
453         SHORTREL( &glThreadListLock );
454         
455         if(Status != -1)        HALT();
456 }
457
458 /**
459  * \fn void Threads_Yield(void)
460  * \brief Yield remainder of timeslice
461  */
462 void Threads_Yield(void)
463 {
464         Proc_GetCurThread()->Remaining = 0;
465         HALT();
466 }
467
468 /**
469  * \fn void Threads_Sleep(void)
470  * \brief Take the current process off the run queue
471  */
472 void Threads_Sleep(void)
473 {
474         tThread *cur = Proc_GetCurThread();
475         
476         //Log_Log("Threads", "%i going to sleep", cur->TID);
477         
478         // Acquire Spinlock
479         SHORTLOCK( &glThreadListLock );
480         
481         // Don't sleep if there is a message waiting
482         if( cur->Messages ) {
483                 SHORTREL( &glThreadListLock );
484                 return;
485         }
486         
487         // Remove us from running queue
488         Threads_RemActive();
489         
490         // Add to Sleeping List (at the top)
491         cur->Next = gSleepingThreads;
492         gSleepingThreads = cur;
493         
494         // Mark thread as sleeping
495         cur->Status = THREAD_STAT_SLEEPING;
496         
497         #if DEBUG_TRACE_STATE
498         Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
499         #endif
500         
501         // Release Spinlock
502         SHORTREL( &glThreadListLock );
503         
504         while(cur->Status != THREAD_STAT_ACTIVE)        HALT();
505 }
506
507
508 /**
509  * \fn int Threads_Wake( tThread *Thread )
510  * \brief Wakes a sleeping/waiting thread up
511  * \param Thread        Thread to wake
512  * \return Boolean Failure (Returns ERRNO)
513  * \note Should be called with the scheduler lock held
514  */
515 int Threads_Wake(tThread *Thread)
516 {
517         tThread *prev;
518         
519         if(!Thread)
520                 return -EINVAL;
521         
522         switch(Thread->Status)
523         {
524         case THREAD_STAT_ACTIVE:
525                 Log("Thread_Wake: Waking awake thread (%i)", Thread->TID);
526                 return -EALREADY;
527         
528         case THREAD_STAT_SLEEPING:      // TODO: Comment better
529                 // Remove from sleeping queue
530                 prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
531                 prev->Next = Thread->Next;
532                 // Add to active queue
533                 Thread->Next = gActiveThreads;
534                 gActiveThreads = Thread;
535                 // Update bookkeeping
536                 giNumActiveThreads ++;
537                 giFreeTickets += Thread->NumTickets;
538                 #if DEBUG_TRACE_TICKETS
539                 Log("Threads_Wake: new giFreeTickets = %i", giFreeTickets);
540                 #endif
541                 Thread->CurCPU = -1;
542                 Thread->Status = THREAD_STAT_ACTIVE;
543                 #if DEBUG_TRACE_STATE
544                 Log("Threads_Sleep: %p (%i %s) woken", Thread, Thread->TID, Thread->ThreadName);
545                 #endif
546                 return -EOK;
547         
548         case THREAD_STAT_WAITING:
549                 Warning("Thread_Wake - Waiting threads are not currently supported");
550                 return -ENOTIMPL;
551         
552         case THREAD_STAT_DEAD:
553                 Warning("Thread_Wake - Attempt to wake dead thread (%i)", Thread->TID);
554                 return -ENOTIMPL;
555         
556         default:
557                 Warning("Thread_Wake - Unknown process status (%i)\n", Thread->Status);
558                 return -EINTERNAL;
559         }
560 }
561
562 /**
563  * \brief Wake a thread given the TID
564  * \param TID   Thread ID to wake
565  * \return Boolean Faulure (errno)
566  */
567 int Threads_WakeTID(tTID TID)
568 {
569         tThread *thread = Threads_GetThread(TID);
570          int    ret;
571         if(!thread)
572                 return -ENOENT;
573         SHORTLOCK( &glThreadListLock );
574         ret = Threads_Wake( thread );
575         SHORTREL( &glThreadListLock );
576         return ret;
577 }
578
579 /**
580  * \fn void Threads_AddActive(tThread *Thread)
581  * \brief Adds a thread to the active queue
582  */
583 void Threads_AddActive(tThread *Thread)
584 {
585         SHORTLOCK( &glThreadListLock );
586         // Add to active list
587         Thread->Next = gActiveThreads;
588         gActiveThreads = Thread;
589         // Update bookkeeping
590         giNumActiveThreads ++;
591         giFreeTickets += Thread->NumTickets;
592         #if DEBUG_TRACE_TICKETS
593         Log("Threads_AddActive: new giFreeTickets = %i", giFreeTickets);
594         #endif
595         SHORTREL( &glThreadListLock );
596 }
597
598 /**
599  * \brief Removes the current thread from the active queue
600  * \warning This should ONLY be called with task switches disabled
601  * \return Current thread pointer
602  */
603 tThread *Threads_RemActive(void)
604 {
605         tThread *ret = Proc_GetCurThread();
606         tThread *prev = Threads_int_GetPrev(&gActiveThreads, ret);
607         if(!prev)       return NULL;
608         ret->Remaining = 0;
609         ret->CurCPU = -1;
610         prev->Next = ret->Next;
611         giNumActiveThreads --;
612         return ret;
613 }
614
615 /**
616  * \fn void Threads_SetFaultHandler(Uint Handler)
617  * \brief Sets the signal handler for a signal
618  */
619 void Threads_SetFaultHandler(Uint Handler)
620 {       
621         //Log_Debug("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
622         Proc_GetCurThread()->FaultHandler = Handler;
623 }
624
625 /**
626  * \fn void Threads_Fault(int Num)
627  * \brief Calls a fault handler
628  */
629 void Threads_Fault(int Num)
630 {
631         tThread *thread = Proc_GetCurThread();
632         
633         Log_Log("Threads", "Threads_Fault: thread = %p", thread);
634         
635         if(!thread)     return ;
636         
637         Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
638         
639         switch(thread->FaultHandler)
640         {
641         case 0: // Panic?
642                 Threads_Kill(thread, -1);
643                 HALT();
644                 return ;
645         case 1: // Dump Core?
646                 Threads_Kill(thread, -1);
647                 HALT();
648                 return ;
649         }
650         
651         // Double Fault? Oh, F**k
652         if(thread->CurFaultNum != 0) {
653                 Threads_Kill(thread, -1);       // For now, just kill
654                 HALT();
655         }
656         
657         thread->CurFaultNum = Num;
658         
659         Proc_CallFaultHandler(thread);
660 }
661
662 // --- Process Structure Access Functions ---
663 tPID Threads_GetPID(void)
664 {
665         return Proc_GetCurThread()->TGID;
666 }
667 tTID Threads_GetTID(void)
668 {
669         return Proc_GetCurThread()->TID;
670 }
671 tUID Threads_GetUID(void)
672 {
673         return Proc_GetCurThread()->UID;
674 }
675 tGID Threads_GetGID(void)
676 {
677         return Proc_GetCurThread()->GID;
678 }
679
680 int Threads_SetUID(Uint *Errno, tUID ID)
681 {
682         tThread *t = Proc_GetCurThread();
683         if( t->UID != 0 ) {
684                 *Errno = -EACCES;
685                 return -1;
686         }
687         Log_Debug("Threads", "TID %i's UID set to %i", t->TID, ID);
688         t->UID = ID;
689         return 0;
690 }
691
692 int Threads_SetGID(Uint *Errno, tGID ID)
693 {
694         tThread *t = Proc_GetCurThread();
695         if( t->UID != 0 ) {
696                 *Errno = -EACCES;
697                 return -1;
698         }
699         Log_Debug("Threads", "TID %i's GID set to %i", t->TID, ID);
700         t->GID = ID;
701         return 0;
702 }
703
704 /**
705  * \fn void Threads_Dump(void)
706  * \brief Dums a list of currently running threads
707  */
708 void Threads_Dump(void)
709 {
710         tThread *thread;
711         
712         Log("Active Threads:");
713         for(thread=gActiveThreads;thread;thread=thread->Next)
714         {
715                 Log(" %i (%i) - %s (CPU %i)",
716                         thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
717                 Log("  State: %i", thread->Status);
718                 Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
719                 Log("  KStack 0x%x", thread->KernelStack);
720         }
721         
722         Log("All Threads:");
723         for(thread=gAllThreads;thread;thread=thread->GlobalNext)
724         {
725                 Log(" %i (%i) - %s (CPU %i)",
726                         thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
727                 Log("  State: %i", thread->Status);
728                 Log("  %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
729                 Log("  KStack 0x%x", thread->KernelStack);
730         }
731 }
732
733 /**
734  * \fn tThread *Threads_GetNextToRun(int CPU, tThread *Last)
735  * \brief Gets the next thread to run
736  * \param CPU   Current CPU
737  * \param Last  The thread the CPU was running
738  */
739 tThread *Threads_GetNextToRun(int CPU, tThread *Last)
740 {
741         tThread *thread;
742          int    ticket;
743          int    number; 
744         
745         // Lock thread list
746         SHORTLOCK( &glThreadListLock );
747         
748         // Clear Delete Queue
749         while(gDeleteThreads)
750         {
751                 thread = gDeleteThreads->Next;
752                 if( IS_LOCKED(&gDeleteThreads->IsLocked) ) {    // Only free if structure is unused
753                         // Set to dead
754                         gDeleteThreads->Status = THREAD_STAT_DEAD;
755                         // Free name
756                         if( IsHeap(gDeleteThreads->ThreadName) )
757                                 free(gDeleteThreads->ThreadName);
758                         // Remove from global list
759                         if( gDeleteThreads == gAllThreads )
760                                 gAllThreads = gDeleteThreads->GlobalNext;
761                         else
762                                 gDeleteThreads->GlobalPrev->GlobalNext = gDeleteThreads->GlobalNext;
763                         free( gDeleteThreads );
764                 }
765                 gDeleteThreads = thread;
766         }
767         
768         // No active threads, just take a nap
769         if(giNumActiveThreads == 0) {
770                 SHORTREL( &glThreadListLock );
771                 #if DEBUG_TRACE_TICKETS
772                 Log("No active threads");
773                 #endif
774                 return NULL;
775         }
776         
777         // Special case: 1 thread
778         if(giNumActiveThreads == 1) {
779                 if( gActiveThreads->CurCPU == -1 )
780                         gActiveThreads->CurCPU = CPU;
781                 SHORTREL( &glThreadListLock );
782                 if( gActiveThreads->CurCPU == CPU )
783                         return gActiveThreads;
784                 return NULL;    // CPU has nothing to do
785         }
786         
787         // Allow the old thread to be scheduled again
788         if( Last ) {
789                 if( Last->Status == THREAD_STAT_ACTIVE ) {
790                         giFreeTickets += Last->NumTickets;
791                         #if DEBUG_TRACE_TICKETS
792                         LogF(" CPU %i released %p (%i %s) into the pool (%i tickets in pool)\n",
793                                 CPU, Last, Last->TID, Last->ThreadName, giFreeTickets);
794                         #endif
795                 }
796                 #if DEBUG_TRACE_TICKETS
797                 else
798                         LogF(" %p (%s)->Status = %i\n", Last, Last->ThreadName, Last->Status);
799                 #endif
800                 Last->CurCPU = -1;
801         }
802         
803         #if 1
804         number = 0;
805         for(thread=gActiveThreads;thread;thread=thread->Next) {
806                 if(thread->CurCPU >= 0) continue;
807                 number += thread->NumTickets;
808         }
809         if(number != giFreeTickets) {
810                 Panic("Bookkeeping fail (giFreeTickets(%i) != number(%i)) - CPU%i",
811                         giFreeTickets, number, CPU);
812         }
813         #endif
814         
815         // No free tickets (all tasks delegated to cores)
816         if( giFreeTickets == 0 ) {
817                 SHORTREL(&glThreadListLock);
818                 return NULL;
819         }
820         
821         // Get the ticket number
822         ticket = number = rand() % giFreeTickets;
823         
824         // Find the next thread
825         for(thread=gActiveThreads;thread;thread=thread->Next)
826         {
827                 if(thread->CurCPU >= 0) continue;
828                 if(thread->NumTickets > number) break;
829                 number -= thread->NumTickets;
830         }
831         // Error Check
832         if(thread == NULL)
833         {
834                 number = 0;
835                 for(thread=gActiveThreads;thread;thread=thread->Next) {
836                         if(thread->CurCPU >= 0) continue;
837                         number += thread->NumTickets;
838                 }
839                 Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
840                         giFreeTickets, number);
841         }
842         #if DEBUG_TRACE_TICKETS
843         LogF(" CPU%i giFreeTickets = %i\n", CPU, giFreeTickets);
844         #endif
845         
846         // Make the new thread non-schedulable
847         giFreeTickets -= thread->NumTickets;    
848         thread->CurCPU = CPU;
849         
850         //Threads_Dump();
851         #if DEBUG_TRACE_TICKETS
852         LogF(" CPU%i giFreeTickets = %i, giving %p (%i %s CPU=%i)\n",
853                 CPU, giFreeTickets, thread, thread->TID, thread->ThreadName, thread->CurCPU);
854         #endif
855         
856         SHORTREL( &glThreadListLock );
857         
858         return thread;
859 }
860
861 /**
862  * \fn void Threads_SegFault(tVAddr Addr)
863  * \brief Called when a Segment Fault occurs
864  */
865 void Threads_SegFault(tVAddr Addr)
866 {
867         Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
868         Threads_Fault( 1 );
869         //Threads_Exit( 0, -1 );
870 }
871
872 /**
873  * \brief Acquire a heavy mutex
874  * \param Mutex Mutex to acquire
875  * 
876  * This type of mutex checks if the mutex is avaliable, and acquires it
877  * if it is. Otherwise, the current thread is added to the mutex's wait
878  * queue and the thread suspends. When the holder of the mutex completes,
879  * the oldest thread (top thread) on the queue is given the lock and
880  * restarted.
881  */
882 void Mutex_Acquire(tMutex *Mutex)
883 {
884         tThread *us = Proc_GetCurThread();
885         
886         // Get protector
887         SHORTLOCK( &Mutex->Protector );
888         
889         //Log("Mutex_Acquire: (%p)", Mutex);
890         
891         // Check if the lock is already held
892         if( Mutex->Owner ) {
893                 SHORTLOCK( &glThreadListLock );
894                 // - Remove from active list
895                 Threads_RemActive();
896                 // - Mark as sleeping
897                 us->Status = THREAD_STAT_OFFSLEEP;
898                 
899                 // - Add to waiting
900                 if(Mutex->LastWaiting) {
901                         Mutex->LastWaiting->Next = us;
902                         Mutex->LastWaiting = us;
903                 }
904                 else {
905                         Mutex->Waiting = us;
906                         Mutex->LastWaiting = us;
907                 }
908                 SHORTREL( &glThreadListLock );
909                 SHORTREL( &Mutex->Protector );
910                 while(us->Status == THREAD_STAT_OFFSLEEP)       HALT();
911                 // We're only woken when we get the lock
912         }
913         // Ooh, let's take it!
914         else {
915                 Mutex->Owner = us;
916                 SHORTREL( &Mutex->Protector );
917         }
918 }
919
920 /**
921  * \brief Release a held mutex
922  * \param Mutex Mutex to release
923  */
924 void Mutex_Release(tMutex *Mutex)
925 {
926         SHORTLOCK( &Mutex->Protector );
927         //Log("Mutex_Release: (%p)", Mutex);
928         if( Mutex->Waiting ) {
929                 Mutex->Owner = Mutex->Waiting;  // Set owner
930                 Mutex->Waiting = Mutex->Waiting->Next;  // Next!
931                 // Wake new owner
932                 Mutex->Owner->Status = THREAD_STAT_ACTIVE;
933                 Threads_AddActive(Mutex->Owner);
934                 //Log("Mutex %p Woke %p", Mutex, Mutex->Owner);
935         }
936         else {
937                 Mutex->Owner = NULL;
938         }
939         SHORTREL( &Mutex->Protector );
940 }
941
942 /**
943  * \brief Is this mutex locked?
944  * \param Mutex Mutex pointer
945  */
946 int Mutex_IsLocked(tMutex *Mutex)
947 {
948         return Mutex->Owner != NULL;
949 }
950
951 // === EXPORTS ===
952 EXPORT(Threads_GetUID);
953 EXPORT(Mutex_Acquire);
954 EXPORT(Mutex_Release);
955 EXPORT(Mutex_IsLocked);

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