* threads.c
* - Thread and process handling
*/
-#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 <arch.h>
-#undef NULL // Remove acess definition
#include <acess.h>
#include <mutex.h>
-#include <semaphore.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdint.h>
-#include "/usr/include/signal.h"
-#include <SDL/SDL.h>
+#include "../../KernelLand/Kernel/include/semaphore.h"
+#include <rwlock.h>
+#include <events.h>
+#include <threads_int.h>
+#include <limits.h>
+#include "include/threads_glue.h"
+
+#define THREAD_EVENT_WAKEUP 0x80000000
// === IMPORTS ===
void VFS_CloneHandleList(int PID);
// === STRUCTURES ===
-#if 0
-typedef struct sState
-{
- void *CurState;
- Uint SP, BP, IP;
-} tState;
-#endif
-
-typedef struct sThread
-{
- struct sThread *GlobalNext;
- struct sThread *Next;
-
- int KernelTID;
-
- tTID TID, PID;
- tUID UID, GID;
-
- struct sThread *Parent;
-
- char *ThreadName;
-
- int State; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
- int ExitStatus;
- #if 0
- tState CurState;
- #endif
-
- // 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;
-
- // Config?
- Uint Config[NUM_CFG_ENTRIES];
-} tThread;
-
// === PROTOTYPES ===
int Threads_Wake(tThread *Thread);
// === GLOBALS ===
+tProcess gProcessZero = {
+ .NativePID = 0,
+ .CWD = "/",
+ .Chroot = "/",
+ .MaxFD = 100
+};
tThread gThreadZero = {
- State: 1,
- ThreadName: "ThreadZero"
+ .Status=THREAD_STAT_ACTIVE,
+ .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;
}
}
-tThread *Threads_GetThread(int TID)
+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(Uint TID)
{
tThread *thread;
for( thread = gpThreads; thread; thread = thread->GlobalNext )
{
- if( thread->TID == TID )
+ if( thread->TID == TID ) {
return thread;
+ }
}
return NULL;
}
ret->TID = giThreads_NextThreadID ++;
ret->ThreadName = strdup(TemplateThread->ThreadName);
+ Threads_Glue_SemInit( &ret->EventSem, 0 );
ret->WaitingThreads = NULL;
ret->WaitingThreadsEnd = NULL;
tTID Threads_GetTID() { return gpCurrentThread->TID; }
tPID Threads_GetPID() { return gpCurrentThread->PID; }
-int Threads_SetUID(int *Errno, tUID NewUID)
+int Threads_SetUID(tUID NewUID)
{
if(Threads_GetUID() != 0) {
- if(Errno) *Errno = -EACCES;
+ errno = EACCES;
return -1;
}
return 0;
}
-int Threads_SetGID(int *Errno, tGID NewGID)
+int Threads_SetGID(tGID NewGID)
{
if(Threads_GetUID() != 0) {
- if(Errno) *Errno = -EACCES;
+ errno = -EACCES;
return -1;
}
return 0;
}
-Uint *Threads_GetCfgPtr(int Index)
-{
- if( Index < 0 || Index >= NUM_CFG_ENTRIES )
- return NULL;
- if( !gpCurrentThread )
- return NULL;
- return &gpCurrentThread->Config[Index];
-}
+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)
+tTID Threads_WaitTID(int TID, int *Status)
{
// Any Child
if(TID == -1) {
if(!thread) return -1;
us->Next = NULL;
- us->State = 3;
+ us->Status = THREAD_STAT_WAITING;
+ // TODO: Locking
if(thread->WaitingThreadsEnd)
{
thread->WaitingThreadsEnd->Next = us;
thread->WaitingThreadsEnd = us;
}
- while(thread->State != 0)
- pause();
+ Threads_WaitEvents( THREAD_EVENT_WAKEUP );
if(Status) *Status = thread->ExitStatus;
thread->WaitingThreads = thread->WaitingThreads->Next;
void Threads_Sleep(void)
{
// TODO: Add to a sleeping queue
- pause();
+ //pause();
}
void Threads_Yield(void)
tThread *toWake;
// VFS_Handles_Cleanup();
+
+ gpCurrentThread->ExitStatus = Status;
#if 1
- // Wait for the thread to be waited upon
- while( gpCurrentThread->WaitingThreads == NULL )
- SDL_Delay(10);
+ if( gpCurrentThread->Parent )
+ {
+ // Wait for the thread to be waited upon
+ while( gpCurrentThread->WaitingThreads == NULL )
+ Threads_Glue_Yield();
+ }
#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);
+ Threads_Glue_Yield();
}
}
int Threads_Wake(tThread *Thread)
{
- kill( Thread->KernelTID, SIGUSR1 );
+ Thread->Status = THREAD_STAT_ACTIVE;
+ Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
return 0;
}
return thread->PID;
}
+// --------------------------------------------------------------------
+// Mutexes
+// --------------------------------------------------------------------
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 );
+ Threads_Glue_AcquireMutex(&Mutex->Protector.Mutex);
return 0;
}
void Mutex_Release(tMutex *Mutex)
{
- pthread_mutex_unlock( &Mutex->Protector.Mutex );
+ Threads_Glue_ReleaseMutex(&Mutex->Protector.Mutex);
}
+// --------------------------------------------------------------------
+// Semaphores
+// --------------------------------------------------------------------
void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
{
memset(Sem, 0, sizeof(tSemaphore));
// HACK: Use `Sem->Protector` as space for the semaphore pointer
- *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
+ Threads_Glue_SemInit( &Sem->Protector.Mutex, InitValue );
}
int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
{
- SDL_SemWait( *(void**)(&Sem->Protector) );
- return 1;
+ return Threads_Glue_SemWait( Sem->Protector.Mutex, MaxToTake );
}
int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
{
- int i;
- for( i = 0; i < AmmountToAdd; i ++ )
- SDL_SemPost( *(void**)(&Sem->Protector) );
- return AmmountToAdd;
+ return Threads_Glue_SemSignal( Sem->Protector.Mutex, AmmountToAdd );
}
-#if 0
-void Threads_Sleep()
+// --------------------------------------------------------------------
+// Event handling
+// --------------------------------------------------------------------
+Uint32 Threads_WaitEvents(Uint32 Mask)
{
- gpCurrentThread->State = 3;
- if( setjmp(&gpCurrentThread->CurState) == 0 ) {
- // Return to user wait
- // Hmm... maybe I should have a "kernel" thread for every "user" thread
+ Uint32 rv;
+
+ Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);
+
+ gpCurrentThread->WaitMask = Mask;
+ if( !(gpCurrentThread->Events & Mask) )
+ {
+ if( Threads_Glue_SemWait(gpCurrentThread->EventSem, INT_MAX) == -1 ) {
+ Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
+ gpCurrentThread, gpCurrentThread->EventSem);
+ }
+ Log_Debug("Threads", "Woken from nap (%i here)", SDL_SemValue(gpCurrentThread->EventSem));
}
- else {
- // Just woken up, return
- return ;
+ rv = gpCurrentThread->Events & Mask;
+ gpCurrentThread->Events &= ~Mask;
+ gpCurrentThread->WaitMask = -1;
+
+ Log_Debug("Threads", "- rv = %x", rv);
+
+ return rv;
+}
+
+void Threads_PostEvent(tThread *Thread, Uint32 Events)
+{
+ Thread->Events |= Events;
+ Log_Debug("Threads", "Trigger event %x (->Events = %p)", Events, Thread->Events);
+
+ if( Events == 0 || Thread->WaitMask & Events ) {
+ Threads_Glue_SemSignal( Thread->EventSem, 1 );
+// Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
}
}
-int SaveState(tState *To)
+void Threads_ClearEvent(Uint32 EventMask)
{
- Uint ip;
- __asm__ __volatile__(
- "call 1f;\n\t"
- "1f:\n\t"
- "pop %%eax"
- : "=a" (ip)
- : );
- // If we just returned
- if(!ip) return 1;
-
- To->IP = ip;
- __asm__ __volatile__ ("mov %%esp, %1" : "=r"(To->SP));
- __asm__ __volatile__ ("mov %%ebp, %1" : "=r"(To->BP));
+ gpCurrentThread->Events &= ~EventMask;
}
-#endif