X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=AcessNative%2Facesskernel_src%2Fthreads.c;h=1e7d0c3fa61e89b072ad0d2b51ebf0b2e1d5cc3c;hb=6bcb63ea0505129d32b249772b554b0848bb5612;hp=5f29f7601346a2fabb3ea2383d97574c32aad339;hpb=c0758a3d1053010f2c6f122365acde3efda2ba77;p=tpg%2Facess2.git diff --git a/AcessNative/acesskernel_src/threads.c b/AcessNative/acesskernel_src/threads.c index 5f29f760..1e7d0c3f 100644 --- a/AcessNative/acesskernel_src/threads.c +++ b/AcessNative/acesskernel_src/threads.c @@ -5,12 +5,23 @@ * threads.c * - Thread and process handling */ -#define _SIGNAL_H_ +#define _SIGNAL_H_ // Stop the acess signal.h being used +#define _HEAP_H_ // Stop heap.h being imported (collides with stdlib heap) +#define _VFS_EXT_H // Stop vfs_ext.h being imported (collides with fd_set) #undef CLONE_VM // Such a hack +#include +#undef NULL // Remove acess definition #include +#include +#include #include +#include #include #include "/usr/include/signal.h" +#include + +// === IMPORTS === +void VFS_CloneHandleList(int PID); // === STRUCTURES === #if 0 @@ -21,8 +32,18 @@ typedef struct sState } tState; #endif +typedef struct sProcess +{ + int nThreads; + int NativePID; + char *CWD; + char *Chroot; + int MaxFD; +} tProcess; + typedef struct sThread { + struct sThread *GlobalNext; struct sThread *Next; int KernelTID; @@ -35,23 +56,78 @@ typedef struct sThread char *ThreadName; int State; // 0: Dead, 1: Active, 2: Paused, 3: Asleep - #if 0 - tState CurState; - #endif + int ExitStatus; + int _errno; + + // Threads waiting for this thread to exit. + // Quit logic: + // - Wait for `WaitingThreads` to be non-null (maybe?) + // - Wake first in the queue, wait for it to be removed + // - Repeat + // - Free thread and quit kernel thread + struct sThread *WaitingThreads; + struct sThread *WaitingThreadsEnd; + + tProcess *Process; - // Config? - Uint Config[NUM_CFG_ENTRIES]; } tThread; +// === PROTOTYPES === + int Threads_Wake(tThread *Thread); + // === GLOBALS === -tThread *gpThreads; -__thread tThread *gpCurrentThread; +tProcess gProcessZero = { + .NativePID = 0, + .CWD = "/", + .Chroot = "/", + .MaxFD = 100 +}; +tThread gThreadZero = { + .State=1, + .ThreadName="ThreadZero", + .Process = &gProcessZero +}; +tThread *gpThreads = &gThreadZero; +__thread tThread *gpCurrentThread = &gThreadZero; + int giThreads_NextThreadID = 1; // === CODE === +tThread *Proc_GetCurThread(void) +{ + return gpCurrentThread; +} + +void Threads_Dump(void) +{ + tThread *thread; + for( thread = gpThreads; thread; thread = thread->GlobalNext ) + { + Log_Log("Threads", "TID %i (%s), PID %i", + thread->TID, thread->ThreadName, thread->PID); + Log_Log("Threads", "User: %i, Group: %i", + thread->UID, thread->GID); + Log_Log("Threads", "Kernel Thread ID: %i", + thread->KernelTID); + } +} + +void Threads_SetThread(int TID) +{ + tThread *thread; + for( thread = gpThreads; thread; thread = thread->GlobalNext ) + { + if( thread->TID == TID ) { + gpCurrentThread = thread; + return ; + } + } + Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID); +} + tThread *Threads_GetThread(int TID) { tThread *thread; - for( thread = gpThreads; thread; thread = thread->Next ) + for( thread = gpThreads; thread; thread = thread->GlobalNext ) { if( thread->TID == TID ) return thread; @@ -59,18 +135,122 @@ tThread *Threads_GetThread(int TID) return NULL; } +/** + * \brief Clone a thread control block (with a different TID) + */ +tThread *Threads_CloneTCB(tThread *TemplateThread) +{ + tThread *ret = malloc(sizeof(tThread)); + + memcpy(ret, TemplateThread, sizeof(tThread)); + + ret->TID = giThreads_NextThreadID ++; + + ret->ThreadName = strdup(TemplateThread->ThreadName); + + ret->WaitingThreads = NULL; + ret->WaitingThreadsEnd = NULL; + + // Add to the end of the queue + // TODO: Handle concurrency issues + ret->GlobalNext = gpThreads; + gpThreads = ret; + + return ret; +} + tUID Threads_GetUID() { return gpCurrentThread->UID; } tGID Threads_GetGID() { return gpCurrentThread->GID; } tTID Threads_GetTID() { return gpCurrentThread->TID; } tPID Threads_GetPID() { return gpCurrentThread->PID; } -Uint *Threads_GetCfgPtr(int Index) +int Threads_SetUID(int *Errno, tUID NewUID) +{ + if(Threads_GetUID() != 0) { + if(Errno) *Errno = -EACCES; + return -1; + } + + gpCurrentThread->UID = NewUID; + return 0; +} + +int Threads_SetGID(int *Errno, tGID NewGID) +{ + if(Threads_GetUID() != 0) { + if(Errno) *Errno = -EACCES; + return -1; + } + + gpCurrentThread->GID = NewGID; + return 0; +} + +int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; } +char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; } +char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; } +int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; }; + +int Threads_WaitTID(int TID, int *Status) { - return &gpCurrentThread->Config[Index]; + // Any Child + if(TID == -1) { + Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child"); + return -1; + } + + // Any peer/child thread + if(TID == 0) { + Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling"); + return -1; + } + + // TGID = abs(TID) + if(TID < -1) { + Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID"); + return -1; + } + + // Specific Thread + if(TID > 0) { + + tThread *thread = Threads_GetThread(TID); + tThread *us = gpCurrentThread; + if(!thread) return -1; + + us->Next = NULL; + us->State = 3; + // TODO: Locking + if(thread->WaitingThreadsEnd) + { + thread->WaitingThreadsEnd->Next = us; + thread->WaitingThreadsEnd = us; + } + else + { + thread->WaitingThreads = us; + thread->WaitingThreadsEnd = us; + } + + while(thread->State != 0) + { + pause(); + Log_Debug("Threads", "Huh?... state = %i", thread->State); + } + + if(Status) *Status = thread->ExitStatus; + thread->WaitingThreads = thread->WaitingThreads->Next; + us->Next = NULL; + + return TID; + } + + return 0; } void Threads_Sleep(void) { + // TODO: Add to a sleeping queue pause(); } @@ -79,22 +259,78 @@ void Threads_Yield(void) // yield(); } +void Threads_Exit(int TID, int Status) +{ + tThread *toWake; + +// VFS_Handles_Cleanup(); + + gpCurrentThread->ExitStatus = Status; + + #if 1 + if( gpCurrentThread->Parent ) + { + // Wait for the thread to be waited upon + while( gpCurrentThread->WaitingThreads == NULL ) + SDL_Delay(10); + } + #endif + + while( (toWake = gpCurrentThread->WaitingThreads) ) + { + Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName); + + Threads_Wake(toWake); + + while(gpCurrentThread->WaitingThreads == toWake) + SDL_Delay(10); + } +} + +int Threads_Wake(tThread *Thread) +{ + Thread->State = 0; + kill( Thread->KernelTID, SIGUSR1 ); + return 0; +} + int Threads_WakeTID(tTID TID) { tThread *thread; thread = Threads_GetThread(TID); if( !thread ) return -1; - kill( thread->KernelTID, SIGUSR1 ); - return 0; + return Threads_Wake(thread); } -void Mutex_Acquire(tMutex *Mutex) +int Threads_CreateRootProcess(void) +{ + tThread *thread = Threads_CloneTCB(&gThreadZero); + thread->PID = thread->TID; + + // Handle list is created on first open + + return thread->PID; +} + +int Threads_Fork(void) +{ + tThread *thread = Threads_CloneTCB(gpCurrentThread); + thread->PID = thread->TID; + // Duplicate the VFS handles (and nodes) from vfs_handle.c + + VFS_CloneHandleList(thread->PID); + + return thread->PID; +} + +int Mutex_Acquire(tMutex *Mutex) { if(!Mutex->Protector.IsValid) { pthread_mutex_init( &Mutex->Protector.Mutex, NULL ); Mutex->Protector.IsValid = 1; } pthread_mutex_lock( &Mutex->Protector.Mutex ); + return 0; } void Mutex_Release(tMutex *Mutex) @@ -102,35 +338,24 @@ void Mutex_Release(tMutex *Mutex) pthread_mutex_unlock( &Mutex->Protector.Mutex ); } -#if 0 -void Threads_Sleep() +void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name) { - gpCurrentThread->State = 3; - if( setjmp(&gpCurrentThread->CurState) == 0 ) { - // Return to user wait - // Hmm... maybe I should have a "kernel" thread for every "user" thread - } - else { - // Just woken up, return - return ; - } + memset(Sem, 0, sizeof(tSemaphore)); + // HACK: Use `Sem->Protector` as space for the semaphore pointer + *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue); } -int SaveState(tState *To) +int Semaphore_Wait(tSemaphore *Sem, int MaxToTake) { - Uint ip; - __asm__ __volatile__( - "call 1f;\n\t" - "1f:\n\t" - "pop %%eax" - : "=a" (ip) - : ); - // If we just returned - if(!ip) return 1; + SDL_SemWait( *(void**)(&Sem->Protector) ); + return 1; +} - To->IP = ip; - __asm__ __volatile__ ("mov %%esp, %1" : "=r"(To->SP)); - __asm__ __volatile__ ("mov %%ebp, %1" : "=r"(To->BP)); +int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd) +{ + int i; + for( i = 0; i < AmmountToAdd; i ++ ) + SDL_SemPost( *(void**)(&Sem->Protector) ); + return AmmountToAdd; } -#endif