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

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