#include <errno.h>
#include <hal_proc.h>
#include <semaphore.h>
+#include <vfs_threads.h> // VFS Handle maintainence
// Configuration
#define DEBUG_TRACE_TICKETS 0 // Trace ticket counts
#define DEFAULT_QUANTUM 5
#define DEFAULT_PRIORITY 5
#define MIN_PRIORITY 10
-const enum eConfigTypes cCONFIG_TYPES[] = {
- CFGT_HEAPSTR, // e.g. CFG_VFS_CWD
- CFGT_INT, // e.g. CFG_VFS_MAXFILES
- CFGT_NULL
-};
// === IMPORTS ===
+// === TYPE ===
+typedef struct
+{
+ tThread *Head;
+ tThread *Tail;
+} tThreadList;
+
// === PROTOTYPES ===
void Threads_Init(void);
#if 0
void Threads_Delete(tThread *Thread);
int Threads_SetName(const char *NewName);
#endif
-char *Threads_GetName(int ID);
+char *Threads_GetName(tTID ID);
#if 0
void Threads_SetPriority(tThread *Thread, int Pri);
tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
int Threads_WaitTID(int TID, int *status);
tThread *Threads_GetThread(Uint TID);
#endif
-tThread *Threads_int_DelFromQueue(tThread **List, tThread *Thread);
+tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread);
+void Threads_int_AddToList(tThreadList *List, tThread *Thread);
#if 0
void Threads_Exit(int TID, int Status);
void Threads_Kill(tThread *Thread, int Status);
// === GLOBALS ===
// -- Core Thread --
+struct sProcess gProcessZero = {
+ };
// Only used for the core kernel
tThread gThreadZero = {
.Status = THREAD_STAT_ACTIVE, // Status
volatile Uint giNextTID = 1; // Next TID to allocate
// --- Thread Lists ---
tThread *gAllThreads = NULL; // All allocated threads
-tThread *gSleepingThreads = NULL; // Sleeping Threads
+tThreadList gSleepingThreads; // Sleeping Threads
int giNumCPUs = 1; // Number of CPUs
BOOL gaThreads_NoTaskSwitch[MAX_CPUS]; // Disables task switches for each core (Pseudo-IF)
// --- Scheduler Types ---
#if SCHEDULER_TYPE == SCHED_LOTTERY
const int caiTICKET_COUNTS[MIN_PRIORITY+1] = {100,81,64,49,36,25,16,9,4,1,0};
volatile int giFreeTickets = 0; // Number of tickets held by non-scheduled threads
-tThread *gActiveThreads = NULL; // Currently Running Threads
+tThreadList gActiveThreads; // Currently Running Threads
#elif SCHEDULER_TYPE == SCHED_RR_SIM
-tThread *gActiveThreads = NULL; // Currently Running Threads
+tThreadList gActiveThreads; // Currently Running Threads
#elif SCHEDULER_TYPE == SCHED_RR_PRI
-tThread *gaActiveThreads[MIN_PRIORITY+1]; // Active threads for each priority level
+tThreadList gaActiveThreads[MIN_PRIORITY+1]; // Active threads for each priority level
#else
# error "Unkown scheduler type"
#endif
Log_Debug("Threads", ".KernelStack = %i", offsetof(tThread, KernelStack));
// Create Initial Task
- #if SCHEDULER_TYPE == SCHED_RR_PRI
- gaActiveThreads[gThreadZero.Priority] = &gThreadZero;
- #else
- gActiveThreads = &gThreadZero;
- #endif
+// #if SCHEDULER_TYPE == SCHED_RR_PRI
+// gaActiveThreads[gThreadZero.Priority].Head = &gThreadZero;
+// gaActiveThreads[gThreadZero.Priority].Tail = &gThreadZero;
+// #else
+// gActiveThreads.Head = &gThreadZero;
+// gActiveThreads.Tail = &gThreadZero;
+// #endif
gAllThreads = &gThreadZero;
giNumActiveThreads = 1;
+ gThreadZero.Process = &gProcessZero;
Proc_Start();
}
{
// Set to dead
Thread->Status = THREAD_STAT_BURIED;
+
+ // Clear out process state
+ Proc_ClearThread(Thread);
+
+ Thread->Process->nThreads --;
+ if( Thread->Process->nThreads == 0 )
+ {
+ tProcess *proc = Thread->Process;
+ // VFS Cleanup
+ VFS_CloseAllUserHandles();
+ // Architecture cleanup
+ Proc_ClearProcess( proc );
+ // VFS Configuration strings
+ if( proc->CurrentWorkingDir)
+ free( proc->CurrentWorkingDir );
+ if( proc->RootDir )
+ free( proc->RootDir );
+ // Process descriptor
+ free( proc );
+ }
// Free name
if( IsHeap(Thread->ThreadName) )
cur->ThreadName = NULL;
- if( IsHeap(oldname) ) free( oldname );
-
+ if( IsHeap(oldname) ) free( oldname );
cur->ThreadName = strdup(NewName);
+
+ Log_Debug("Threads", "Thread renamed to '%s'", NewName);
+
return 0;
}
if( Pri == Thread->Priority ) return;
#if SCHEDULER_TYPE == SCHED_RR_PRI
- SHORTLOCK( &glThreadListLock );
- // Remove from old priority
- Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
- // And add to new
- Thread->Next = gaActiveThreads[Pri];
- gaActiveThreads[Pri] = Thread;
- Thread->Priority = Pri;
- SHORTREL( &glThreadListLock );
+ if( Thread != Proc_GetCurThread() )
+ {
+ SHORTLOCK( &glThreadListLock );
+ // Remove from old priority
+ Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread );
+ // And add to new
+ Threads_int_AddToList( &gaActiveThreads[Pri], Thread );
+ Thread->Priority = Pri;
+ SHORTREL( &glThreadListLock );
+ }
+ else
+ Thread->Priority = Pri;
#else
// If this isn't the current thread, we need to lock
if( Thread != Proc_GetCurThread() )
tThread *Threads_CloneTCB(Uint Flags)
{
tThread *cur, *new;
- int i;
cur = Proc_GetCurThread();
// Allocate and duplicate
new->ThreadName = strdup(cur->ThreadName);
// Set Thread Group ID (PID)
- if(Flags & CLONE_VM)
- new->TGID = new->TID;
- else
- new->TGID = cur->TGID;
+ if(Flags & CLONE_VM) {
+ tProcess *newproc, *oldproc;
+ oldproc = cur->Process;
+ new->Process = malloc( sizeof(struct sProcess) );
+ newproc = new->Process;
+ newproc->PID = new->TID;
+ newproc->UID = oldproc->UID;
+ newproc->GID = oldproc->GID;
+ newproc->MaxFD = oldproc->MaxFD;
+ if( oldproc->CurrentWorkingDir )
+ newproc->CurrentWorkingDir = strdup( oldproc->CurrentWorkingDir );
+ else
+ newproc->CurrentWorkingDir = NULL;
+ if( oldproc->RootDir )
+ newproc->RootDir = strdup( oldproc->RootDir );
+ else
+ newproc->RootDir = NULL;
+ newproc->nThreads = 1;
+ // Reference all handles in the VFS
+ VFS_ReferenceUserHandles();
+ }
+ else {
+ new->Process->nThreads ++;
+ }
// Messages are not inherited
new->Messages = NULL;
// Set State
new->Remaining = new->Quantum = cur->Quantum;
new->Priority = cur->Priority;
+ new->_errno = 0;
// Set Signal Handlers
new->CurFaultNum = 0;
new->FaultHandler = cur->FaultHandler;
- for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
- {
- switch(cCONFIG_TYPES[i])
- {
- default:
- new->Config[i] = cur->Config[i];
- break;
- case CFGT_HEAPSTR:
- if(cur->Config[i])
- new->Config[i] = (Uint) strdup( (void*)cur->Config[i] );
- else
- new->Config[i] = 0;
- break;
- }
- }
-
// Maintain a global list of threads
SHORTLOCK( &glThreadListLock );
new->GlobalPrev = NULL; // Protect against bugs
tThread *Threads_CloneThreadZero(void)
{
tThread *new;
- int i;
// Allocate and duplicate
new = malloc(sizeof(tThread));
return NULL;
}
memcpy(new, &gThreadZero, sizeof(tThread));
+
+ new->Process->nThreads ++;
new->CurCPU = -1;
new->Next = NULL;
new->CurFaultNum = 0;
new->FaultHandler = 0;
- for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
- {
- new->Config[i] = 0;
- }
-
// Maintain a global list of threads
SHORTLOCK( &glThreadListLock );
new->GlobalPrev = NULL; // Protect against bugs
return new;
}
-/**
- * \brief Get a configuration pointer from the Per-Thread data area
- * \param ID Config slot ID
- * \return Pointer at ID
- */
-Uint *Threads_GetCfgPtr(int ID)
-{
- if(ID < 0 || ID >= NUM_CFG_ENTRIES) {
- Warning("Threads_GetCfgPtr: Index %i is out of bounds", ID);
- return NULL;
- }
-
- return &Proc_GetCurThread()->Config[ID];
-}
-
/**
* \brief Wait for a task to change state
* \param TID Thread ID to wait on (-1: Any child thread, 0: Any Child/Sibling, <-1: -PID)
// Specific Thread
if(TID > 0) {
tThread *t = Threads_GetThread(TID);
- int initStatus = t->Status;
tTID ret;
// Wait for the thread to die!
- if(initStatus != THREAD_STAT_ZOMBIE) {
- // TODO: Handle child also being suspended if wanted
- while(t->Status != THREAD_STAT_ZOMBIE) {
- Threads_Sleep();
- Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
- Threads_GetTID(), t->TID, t->Status);
- }
+ // TODO: Handle child also being suspended if wanted
+ while(t->Status != THREAD_STAT_ZOMBIE) {
+ Threads_Sleep();
+ Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
+ Threads_GetTID(), t->TID, t->Status);
}
// Set return status
- Log_Debug("Threads", "%i waiting for %i, t->Status = %i",
- Threads_GetTID(), t->TID, t->Status);
ret = t->TID;
switch(t->Status)
{
* \param Thread Thread to find
* \return \a Thread
*/
-tThread *Threads_int_DelFromQueue(tThread **List, tThread *Thread)
+tThread *Threads_int_DelFromQueue(tThreadList *List, tThread *Thread)
{
tThread *ret, *prev = NULL;
- for(ret = *List;
+ for(ret = List->Head;
ret && ret != Thread;
prev = ret, ret = ret->Next
);
}
if( !prev ) {
- *List = Thread->Next;
+ List->Head = Thread->Next;
//LogF("%p(%s) removed from head of %p\n", Thread, Thread->ThreadName, List);
}
else {
prev->Next = Thread->Next;
//LogF("%p(%s) removed from %p (prev=%p)\n", Thread, Thread->ThreadName, List, prev);
}
+ if( Thread->Next == NULL )
+ List->Tail = prev;
return Thread;
}
+void Threads_int_AddToList(tThreadList *List, tThread *Thread)
+{
+ if( List->Head )
+ List->Tail->Next = Thread;
+ else
+ List->Head = Thread;
+ List->Tail = Thread;
+ Thread->Next = NULL;
+}
+
/**
* \brief Exit the current process (or another?)
* \param TID Thread ID to kill
// Currently active thread
case THREAD_STAT_ACTIVE:
- #if SCHEDULER_TYPE == SCHED_RR_PRI
- if( Threads_int_DelFromQueue( &gaActiveThreads[Thread->Priority], Thread ) )
- #else
- if( Threads_int_DelFromQueue( &gActiveThreads, Thread ) )
- #endif
+ if( Thread != Proc_GetCurThread() )
{
- // Ensure that we are not rescheduled
- Thread->Remaining = 0; // Clear Remaining Quantum
- Thread->Quantum = 0; // Clear Quantum to indicate dead thread
-
- // Update bookkeeping
- giNumActiveThreads --;
+ #if SCHEDULER_TYPE == SCHED_RR_PRI
+ tThreadList *list = &gaActiveThreads[Thread->Priority];
+ #else
+ tThreadList *list = &gActiveThreads;
+ #endif
+ if( Threads_int_DelFromQueue( list, Thread ) )
+ {
+ }
+ else
+ {
+ Log_Warning("Threads",
+ "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
+ Thread, Thread->TID, Thread->ThreadName
+ );
+ }
#if SCHEDULER_TYPE == SCHED_LOTTERY
- if( Thread != Proc_GetCurThread() )
- giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
+ giFreeTickets -= caiTICKET_COUNTS[ Thread->Priority ];
#endif
}
- else
- {
- Log_Warning("Threads",
- "Threads_Kill - Thread %p(%i,%s) marked as active, but not on list",
- Thread, Thread->TID, Thread->ThreadName
- );
- }
+ // Ensure that we are not rescheduled
+ Thread->Remaining = 0; // Clear Remaining Quantum
+ Thread->Quantum = 0; // Clear Quantum to indicate dead thread
+
+ // Update bookkeeping
+ giNumActiveThreads --;
break;
// Kill it while it sleeps!
case THREAD_STAT_SLEEPING:
Thread->RetStatus = Status;
SHORTREL( &Thread->IsLocked );
- // Clear out process state
- Proc_ClearThread(Thread);
Thread->Status = THREAD_STAT_ZOMBIE;
SHORTREL( &glThreadListLock );
cur->Status = THREAD_STAT_SLEEPING;
// Add to Sleeping List (at the top)
- cur->Next = gSleepingThreads;
- gSleepingThreads = cur;
-
+ Threads_int_AddToList( &gSleepingThreads, cur );
#if DEBUG_TRACE_STATE
Log("Threads_Sleep: %p (%i %s) sleeping", cur, cur->TID, cur->ThreadName);
// Thread->CurCPU = -1;
// Add to active list
{
- tThread *tmp, *prev = NULL;
#if SCHEDULER_TYPE == SCHED_RR_PRI
- for( tmp = gaActiveThreads[Thread->Priority]; tmp; prev = tmp, tmp = tmp->Next );
- if(prev)
- prev->Next = Thread;
- else
- gaActiveThreads[Thread->Priority] = Thread;
+ tThreadList *list = &gaActiveThreads[Thread->Priority];
#else
- for( tmp = gActiveThreads; tmp; prev = tmp, tmp = tmp->Next );
- if(prev)
- prev->Next = Thread;
- else
- gActiveThreads = Thread;
+ tThreadList *list = &gActiveThreads;
#endif
- Thread->Next = NULL;
+ Threads_int_AddToList( list, Thread );
}
// Update bookkeeping
*/
tThread *Threads_RemActive(void)
{
+ #if 0
tThread *ret = Proc_GetCurThread();
if( !IS_LOCKED(&glThreadListLock) ) {
if( !Threads_int_DelFromQueue(&gActiveThreads, ret) )
#endif
{
- SHORTREL( &glThreadListLock );
Log_Warning("Threads", "Current thread %p(%i %s) is not on active queue",
ret, ret->TID, ret->ThreadName
);
#endif
return ret;
+ #else
+ return Proc_GetCurThread();
+ #endif
}
/**
// --- Process Structure Access Functions ---
tPID Threads_GetPID(void)
{
- return Proc_GetCurThread()->TGID;
+ return Proc_GetCurThread()->Process->PID;
}
tTID Threads_GetTID(void)
{
}
tUID Threads_GetUID(void)
{
- return Proc_GetCurThread()->UID;
+ return Proc_GetCurThread()->Process->UID;
}
tGID Threads_GetGID(void)
{
- return Proc_GetCurThread()->GID;
+ return Proc_GetCurThread()->Process->GID;
}
-int Threads_SetUID(Uint *Errno, tUID ID)
+int Threads_SetUID(tUID ID)
{
tThread *t = Proc_GetCurThread();
- if( t->UID != 0 ) {
- *Errno = -EACCES;
+ if( t->Process->UID != 0 ) {
+ errno = -EACCES;
return -1;
}
- Log_Debug("Threads", "TID %i's UID set to %i", t->TID, ID);
- t->UID = ID;
+ Log_Debug("Threads", "PID %i's UID set to %i", t->Process->PID, ID);
+ t->Process->UID = ID;
return 0;
}
-int Threads_SetGID(Uint *Errno, tGID ID)
+int Threads_SetGID(tGID ID)
{
tThread *t = Proc_GetCurThread();
- if( t->UID != 0 ) {
- *Errno = -EACCES;
+ if( t->Process->UID != 0 ) {
+ errno = -EACCES;
return -1;
}
- Log_Debug("Threads", "TID %i's GID set to %i", t->TID, ID);
- t->GID = ID;
+ Log_Debug("Threads", "PID %i's GID set to %i", t->Process->PID, ID);
+ t->Process->GID = ID;
return 0;
}
+// --- Per-thread storage ---
+int *Threads_GetErrno(void)
+{
+ return &Proc_GetCurThread()->_errno;
+}
+
+// --- Configuration ---
+int *Threads_GetMaxFD(void)
+{
+ return &Proc_GetCurThread()->Process->MaxFD;
+}
+char **Threads_GetChroot(void)
+{
+ return &Proc_GetCurThread()->Process->RootDir;
+}
+char **Threads_GetCWD(void)
+{
+ return &Proc_GetCurThread()->Process->CurrentWorkingDir;
+}
+// ---
+
/**
* \fn void Threads_Dump(void)
*/
void Threads_DumpActive(void)
{
tThread *thread;
+ tThreadList *list;
#if SCHEDULER_TYPE == SCHED_RR_PRI
int i;
#endif
#if SCHEDULER_TYPE == SCHED_RR_PRI
for( i = 0; i < MIN_PRIORITY+1; i++ )
{
- for(thread=gaActiveThreads[i];thread;thread=thread->Next)
+ list = &gaActiveThreads[i];
#else
- for(thread=gActiveThreads;thread;thread=thread->Next)
+ list = &gActiveThreads;
#endif
+ for(thread=list->Head;thread;thread=thread->Next)
{
Log(" %p %i (%i) - %s (CPU %i)",
- thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+ thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
if(thread->Status != THREAD_STAT_ACTIVE)
- Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)", thread->Status, THREAD_STAT_ACTIVE);
+ Log(" ERROR State (%i) != THREAD_STAT_ACTIVE (%i)",
+ thread->Status, THREAD_STAT_ACTIVE);
Log(" Priority %i, Quantum %i", thread->Priority, thread->Quantum);
Log(" KStack 0x%x", thread->KernelStack);
if( thread->bInstrTrace )
for(thread=gAllThreads;thread;thread=thread->GlobalNext)
{
Log(" %p %i (%i) - %s (CPU %i)",
- thread, thread->TID, thread->TGID, thread->ThreadName, thread->CurCPU);
+ thread, thread->TID, thread->Process->PID, thread->ThreadName, thread->CurCPU);
Log(" State %i (%s)", thread->Status, casTHREAD_STAT[thread->Status]);
switch(thread->Status)
{
#endif
return NULL;
}
-
+
+ #if 0
#if SCHEDULER_TYPE != SCHED_RR_PRI
// Special case: 1 thread
if(giNumActiveThreads == 1) {
- if( gActiveThreads->CurCPU == -1 )
- gActiveThreads->CurCPU = CPU;
+ if( gActiveThreads.Head->CurCPU == -1 )
+ gActiveThreads.Head->CurCPU = CPU;
SHORTREL( &glThreadListLock );
- if( gActiveThreads->CurCPU == CPU )
- return gActiveThreads;
+ if( gActiveThreads.Head->CurCPU == CPU )
+ return gActiveThreads.Head;
return NULL; // CPU has nothing to do
}
#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
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
int ticket, number;
# if 1
number = 0;
- for(thread = gActiveThreads; thread; thread = thread->Next) {
- if(thread->CurCPU >= 0) continue;
+ 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);
ticket = number = rand() % giFreeTickets;
// Find the next thread
- for(thread=gActiveThreads;thread;thread=thread->Next)
+ for(thread = gActiveThreads.Head; thread; prev = thread, thread = thread->Next )
{
- if(thread->CurCPU >= 0) continue;
if( caiTICKET_COUNTS[ thread->Priority ] > number) break;
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",
#elif SCHEDULER_TYPE == SCHED_RR_PRI
{
int i;
+ thread = NULL;
for( i = 0; i < MIN_PRIORITY + 1; i ++ )
{
- for(thread = gaActiveThreads[i]; thread; thread = thread->Next)
- {
- if( thread->CurCPU == -1 ) break;
- }
- // If we fall onto the same queue again, special handling is
- // needed
- if( Last && Last->Status == THREAD_STAT_ACTIVE && i == Last->Priority ) {
- tThread *savedThread = thread;
-
- // Find the next unscheduled thread in the list
- for( thread = Last->Next; thread; thread = thread->Next )
- {
- if( thread->CurCPU == -1 ) break;
- }
- // If we don't find anything after, just use the one
- // found above.
- if( !thread ) thread = savedThread;
- }
- // Found a thread? Schedule it!
- if( thread ) break;
+ 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?
}
}
#elif SCHEDULER_TYPE == SCHED_RR_SIM
- {
- // Find the next unscheduled thread in the list
- for( thread = Last->Next; thread; thread = thread->Next )
- {
- if( thread->CurCPU == -1 ) break;
- }
- // If we don't find anything after, search from the beginning
- if( !thread )
- {
- for(thread = gActiveThreads; thread; thread = thread->Next)
- {
- if( thread->CurCPU == -1 ) break;
- }
- }
+ {
+ // 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 ) {