#define DEFAULT_TICKETS 5
#define MAX_TICKETS 10
const enum eConfigTypes cCONFIG_TYPES[] = {
- CFGT_HEAPSTR, // CFG_VFS_CWD
- CFGT_INT, // CFG_VFS_MAXFILES
+ CFGT_HEAPSTR, // e.g. CFG_VFS_CWD
+ CFGT_INT, // e.g. CFG_VFS_MAXFILES
CFGT_NULL
};
// === GLOBALS ===
// -- Core Thread --
+// Only used for the core kernel
tThread gThreadZero = {
NULL, 0, // Next, Lock
THREAD_STAT_ACTIVE, // Status
tSpinlock glThreadListLock = 0; ///\note NEVER use a heap function while locked
// --- Current State ---
volatile int giNumActiveThreads = 0;
-volatile int giTotalTickets = 0;
+//volatile int giTotalTickets = 0;
+volatile int giFreeTickets = 0;
volatile Uint giNextTID = 1;
// --- Thread Lists ---
tThread *gActiveThreads = NULL; // Currently Running Threads
// Create Initial Task
gActiveThreads = &gThreadZero;
- giTotalTickets = gThreadZero.NumTickets;
+ //giFreeTickets = gThreadZero.NumTickets;
giNumActiveThreads = 1;
#if 1
tThread *cur = Proc_GetCurThread();
if( IsHeap(cur->ThreadName) )
free( cur->ThreadName );
+ // TODO: Possible concurrency issue
cur->ThreadName = malloc(strlen(NewName)+1);
strcpy(cur->ThreadName, NewName);
return 0;
if(ID == -1) {
return Proc_GetCurThread()->ThreadName;
}
+ // TODO: Find a thread and get its name
return NULL;
}
if(Num < 0) return;
if(Num > MAX_TICKETS) Num = MAX_TICKETS;
- LOCK( &glThreadListLock );
- giTotalTickets -= cur->NumTickets;
cur->NumTickets = Num;
- giTotalTickets += Num;
- //LOG("giTotalTickets = %i", giTotalTickets);
- RELEASE( &glThreadListLock );
}
/**
}
memcpy(new, cur, sizeof(tThread));
+ new->CurCPU = -1;
new->Next = NULL;
new->IsLocked = 0;
new->Status = THREAD_STAT_ACTIVE;
/**
* \fn tThread *Threads_GetThread(Uint TID)
* \brief Gets a thread given its TID
+ * \param TID Thread ID
*/
tThread *Threads_GetThread(Uint TID)
{
Threads_Kill( Proc_GetCurThread(), (Uint)Status & 0xFF );
else
Threads_Kill( Threads_GetThread(TID), (Uint)Status & 0xFF );
- for(;;) HALT(); // Just in case
+ // Halt forever, just in case
+ for(;;)
+ HALT();
}
/**
}
#endif
- ///\note Double lock is needed due to overlap of locks
+ ///\note Double lock is needed due to overlap of lock areas
// Lock thread (stop us recieving messages)
LOCK( &Thread->IsLocked );
prev->Next = Thread->Next; // Remove from active
giNumActiveThreads --;
- giTotalTickets -= Thread->NumTickets;
+ if( Thread != Proc_GetCurThread() )
+ giFreeTickets -= Thread->NumTickets;
// Mark thread as a zombie
Thread->RetStatus = Status;
if(!thread) {
Warning("Threads_Sleep - Current thread is not on the active queue");
Threads_Dump();
+ RELEASE( &glThreadListLock );
return;
}
// Reduce the active count & ticket count
giNumActiveThreads --;
- giTotalTickets -= cur->NumTickets;
+ //giTotalTickets -= cur->NumTickets;
// Mark thread as sleeping
cur->Status = THREAD_STAT_SLEEPING;
Thread->Next = gActiveThreads; // Add to active queue
gActiveThreads = Thread;
giNumActiveThreads ++;
- giTotalTickets += Thread->NumTickets;
+ // Thread can't be the current, so no need to check
+ giFreeTickets += Thread->NumTickets;
Thread->Status = THREAD_STAT_ACTIVE;
RELEASE( &glThreadListLock );
break;
}
}
+/**
+ * \brief Wake a thread given the TID
+ */
void Threads_WakeTID(tTID Thread)
{
Threads_Wake( Threads_GetThread(Thread) );
Thread->Next = gActiveThreads;
gActiveThreads = Thread;
giNumActiveThreads ++;
- giTotalTickets += Thread->NumTickets;
+ // Thread can't be the current, so no need to check
+ giFreeTickets += Thread->NumTickets;
//Log("Threads_AddActive: giNumActiveThreads = %i, giTotalTickets = %i",
// giNumActiveThreads, giTotalTickets);
RELEASE( &glThreadListLock );
Log("Active Threads:");
for(thread=gActiveThreads;thread;thread=thread->Next)
{
- Log("%c%i (%i) - %s",
- (thread==cur?'*':' '),
- thread->TID, thread->TGID, thread->ThreadName);
+ Log(" %i (%i) - %s (CPU %i)",
+ thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
Log(" %i Tickets, Quantum %i", thread->NumTickets, thread->Quantum);
Log(" KStack 0x%x", thread->KernelStack);
}
}
/**
- * \fn tThread *Threads_GetNextToRun(int CPU)
+ * \fn tThread *Threads_GetNextToRun(int CPU, tThread *Last)
* \brief Gets the next thread to run
+ * \param CPU Current CPU
+ * \param Last The thread the CPU was running
*/
-tThread *Threads_GetNextToRun(int CPU)
+tThread *Threads_GetNextToRun(int CPU, tThread *Last)
{
tThread *thread;
int ticket;
int number;
+ // Note: Enable the code to tell if the switch code has the lock, or
+ // if it's the other code.
+
+ // Check if the thread list is locked by other code
+ // - If so, don't switch (give it a chance to complete)
+ if( IS_LOCKED(&glThreadListLock) )
+ return Last;
+
+ // No active threads, just take a nap
if(giNumActiveThreads == 0) {
return NULL;
}
+ // Lock thread list
+ // - HLT lock (Used because only another CPU can obtain the lock,
+ // but it has a potentially long lock period)
+ // - Well, this CPU can obtain the lock, but that is aliveviated by
+ // the above.
+ TIGHTLOCK( &glThreadListLock );
+
// Special case: 1 thread
if(giNumActiveThreads == 1) {
- return gActiveThreads;
+ if( gActiveThreads->CurCPU == -1 )
+ gActiveThreads->CurCPU = CPU;
+ RELEASE( &glThreadListLock );
+ if( gActiveThreads->CurCPU == CPU )
+ return gActiveThreads;
+ return NULL; // CPU has nothing to do
}
+ // Allow the old thread to be scheduled again
+ if( Last ) {
+ if( Last->Status == THREAD_STAT_ACTIVE )
+ giFreeTickets += Last->NumTickets;
+ Last->CurCPU = -1;
+ }
+
// Get the ticket number
- ticket = number = rand() % giTotalTickets;
+ ticket = number = rand() % giFreeTickets;
// Find the next thread
for(thread=gActiveThreads;thread;thread=thread->Next)
{
+ if(thread->CurCPU >= 0) continue;
if(thread->NumTickets > number) break;
number -= thread->NumTickets;
}
-
// Error Check
if(thread == NULL)
{
number = 0;
- for(thread=gActiveThreads;thread;thread=thread->Next)
+ for(thread=gActiveThreads;thread;thread=thread->Next) {
+ if(thread->CurCPU >= 0) continue;
number += thread->NumTickets;
- Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)",
- giTotalTickets, number);
+ }
+ Panic("Bookeeping Failed - giFreeTickets(%i) > true count (%i)",
+ giFreeTickets, number);
}
+ // Make the new thread non-schedulable
+ giFreeTickets -= thread->NumTickets;
+ thread->CurCPU = CPU;
+
+ RELEASE( &glThreadListLock );
+
return thread;
}