+ #endif
+ #endif
+
+ // Allow the old thread to be scheduled again
+ if( Last ) {
+ if( Last->Status == THREAD_STAT_ACTIVE ) {
+ tThreadList *list;
+ #if SCHEDULER_TYPE == SCHED_LOTTERY
+ giFreeTickets += caiTICKET_COUNTS[ Last->Priority ];
+ # if DEBUG_TRACE_TICKETS
+ LogF("Log: CPU%i released %p (%i %s) into the pool (%i [+%i] tickets in pool)\n",
+ CPU, Last, Last->TID, Last->ThreadName, giFreeTickets,
+ caiTICKET_COUNTS[ Last->Priority ]);
+ # endif
+ #endif
+
+ #if SCHEDULER_TYPE == SCHED_RR_PRI
+ list = &gaActiveThreads[ Last->Priority ];
+ #else
+ list = &gActiveThreads;
+ #endif
+ // Add to end of list
+ Threads_int_AddToList( list, Last );
+ }
+ #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS
+ else
+ LogF("Log: CPU%i released %p (%i %s)->Status = %i (Released,not in pool)\n",
+ CPU, Last, Last->TID, Last->ThreadName, Last->Status);
+ #endif
+ Last->CurCPU = -1;
+ }
+
+ // ---
+ // Lottery Scheduler
+ // ---
+ #if SCHEDULER_TYPE == SCHED_LOTTERY
+ {
+ int ticket, number;
+ # if 1
+ number = 0;
+ for(thread = gActiveThreads.Head; thread; thread = thread->Next)
+ {
+ if(thread->Status != THREAD_STAT_ACTIVE)
+ Panic("Bookkeeping fail - %p %i(%s) is on the active queue with a status of %i",
+ thread, thread->TID, thread->ThreadName, thread->Status);
+ if(thread->Next == thread) {
+ Panic("Bookkeeping fail - %p %i(%s) loops back on itself",
+ thread, thread->TID, thread->ThreadName, thread->Status);
+ }
+ number += caiTICKET_COUNTS[ thread->Priority ];
+ }
+ if(number != giFreeTickets) {
+ Panic("Bookkeeping fail (giFreeTickets(%i) != number(%i)) - CPU%i",
+ giFreeTickets, number, CPU);
+ }
+ # endif
+
+ // No free tickets (all tasks delegated to cores)
+ if( giFreeTickets == 0 ) {
+ SHORTREL(&glThreadListLock);
+ return NULL;
+ }
+
+ // Get the ticket number
+ ticket = number = rand() % giFreeTickets;
+
+ // Find the next thread
+ for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
+ {
+ if( caiTICKET_COUNTS[ thread->Priority ] > number) break;
+ number -= caiTICKET_COUNTS[ thread->Priority ];
+ }
+
+ // If we didn't find a thread, something went wrong
+ if(thread == NULL)
+ {
+ number = 0;
+ for(thread=gActiveThreads;thread;thread=thread->Next) {
+ if(thread->CurCPU >= 0) continue;
+ number += caiTICKET_COUNTS[ thread->Priority ];
+ }
+ Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
+ giFreeTickets, number);
+ }
+
+ // Remove
+ if(prev)
+ prev->Next = thread->Next;
+ else
+ gActiveThreads.Head = thread->Next;
+ if(!thread->Next)
+ gActiveThreads.Tail = prev;
+
+ giFreeTickets -= caiTICKET_COUNTS[ thread->Priority ];
+ # if DEBUG_TRACE_TICKETS
+ LogF("Log: CPU%i allocated %p (%i %s), (%i [-%i] tickets in pool), \n",
+ CPU, thread, thread->TID, thread->ThreadName,
+ giFreeTickets, caiTICKET_COUNTS[ thread->Priority ]);
+ # endif
+ }
+
+ // ---
+ // Priority based round robin scheduler
+ // ---
+ #elif SCHEDULER_TYPE == SCHED_RR_PRI
+ {
+ int i;
+ thread = NULL;
+ for( i = 0; i < MIN_PRIORITY + 1; i ++ )
+ {
+ if( !gaActiveThreads[i].Head )
+ continue ;
+
+ thread = gaActiveThreads[i].Head;
+
+ // Remove from head
+ gaActiveThreads[i].Head = thread->Next;
+ if(!thread->Next)
+ gaActiveThreads[i].Tail = NULL;
+ thread->Next = NULL;
+ break;
+ }
+
+ // Anything to do?
+ if( !thread ) {
+ SHORTREL(&glThreadListLock);
+ return NULL;
+ }
+ if( thread->Status != THREAD_STAT_ACTIVE ) {
+ LogF("Oops, Thread %i (%s) is not active\n", thread->TID, thread->ThreadName);
+ }
+ }
+ #elif SCHEDULER_TYPE == SCHED_RR_SIM
+ {
+ // Get the next thread off the list
+ thread = gActiveThreads.Head;
+ gActiveThreads.Head = thread->Next;
+ if(!thread->Next)
+ gaActiveThreads.Tail = NULL;
+ thread->Next = NULL;
+
+ // Anything to do?
+ if( !thread ) {
+ SHORTREL(&glThreadListLock);
+ return NULL;
+ }
+ }
+ #else
+ # error "Unimplemented scheduling algorithm"
+ #endif
+
+ // Make the new thread non-schedulable
+ thread->CurCPU = CPU;
+ thread->Remaining = thread->Quantum;
+
+ SHORTREL( &glThreadListLock );
+
+ return thread;