3 * - Acess kernel emulation on another OS using SDL and UDP
6 * - Thread and process handling
8 #define _SIGNAL_H_ // Stop the acess signal.h being used
9 #define _HEAP_H_ // Stop heap.h being imported (collides with stdlib heap)
10 #define _VFS_EXT_H // Stop vfs_ext.h being imported (collides with fd_set)
11 #undef CLONE_VM // Such a hack
13 #undef NULL // Remove acess definition
16 #include <semaphore.h>
18 #include <sys/types.h>
20 #include "/usr/include/signal.h"
24 void VFS_CloneHandleList(int PID);
35 typedef struct sThread
37 struct sThread *GlobalNext;
45 struct sThread *Parent;
49 int State; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
55 // Threads waiting for this thread to exit.
57 // - Wait for `WaitingThreads` to be non-null (maybe?)
58 // - Wake first in the queue, wait for it to be removed
60 // - Free thread and quit kernel thread
61 struct sThread *WaitingThreads;
62 struct sThread *WaitingThreadsEnd;
65 Uint Config[NUM_CFG_ENTRIES];
69 int Threads_Wake(tThread *Thread);
72 tThread gThreadZero = {
74 .ThreadName="ThreadZero"
76 tThread *gpThreads = &gThreadZero;
77 __thread tThread *gpCurrentThread = &gThreadZero;
78 int giThreads_NextThreadID = 1;
81 void Threads_Dump(void)
84 for( thread = gpThreads; thread; thread = thread->GlobalNext )
86 Log_Log("Threads", "TID %i (%s), PID %i",
87 thread->TID, thread->ThreadName, thread->PID);
88 Log_Log("Threads", "User: %i, Group: %i",
89 thread->UID, thread->GID);
90 Log_Log("Threads", "Kernel Thread ID: %i",
95 void Threads_SetThread(int TID)
98 for( thread = gpThreads; thread; thread = thread->GlobalNext )
100 if( thread->TID == TID ) {
101 gpCurrentThread = thread;
105 Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
108 tThread *Threads_GetThread(int TID)
111 for( thread = gpThreads; thread; thread = thread->GlobalNext )
113 if( thread->TID == TID )
120 * \brief Clone a thread control block (with a different TID)
122 tThread *Threads_CloneTCB(tThread *TemplateThread)
124 tThread *ret = malloc(sizeof(tThread));
126 memcpy(ret, TemplateThread, sizeof(tThread));
128 ret->TID = giThreads_NextThreadID ++;
130 ret->ThreadName = strdup(TemplateThread->ThreadName);
132 ret->WaitingThreads = NULL;
133 ret->WaitingThreadsEnd = NULL;
135 // Add to the end of the queue
136 // TODO: Handle concurrency issues
137 ret->GlobalNext = gpThreads;
143 tUID Threads_GetUID() { return gpCurrentThread->UID; }
144 tGID Threads_GetGID() { return gpCurrentThread->GID; }
145 tTID Threads_GetTID() { return gpCurrentThread->TID; }
146 tPID Threads_GetPID() { return gpCurrentThread->PID; }
148 int Threads_SetUID(int *Errno, tUID NewUID)
150 if(Threads_GetUID() != 0) {
151 if(Errno) *Errno = -EACCES;
155 gpCurrentThread->UID = NewUID;
159 int Threads_SetGID(int *Errno, tGID NewGID)
161 if(Threads_GetUID() != 0) {
162 if(Errno) *Errno = -EACCES;
166 gpCurrentThread->GID = NewGID;
170 Uint *Threads_GetCfgPtr(int Index)
172 // Log_Debug("Threads", "Index=%i, gpCurrentThread=%p",
173 // Index, gpCurrentThread);
174 if( Index < 0 || Index >= NUM_CFG_ENTRIES )
176 if( !gpCurrentThread )
178 return &gpCurrentThread->Config[Index];
181 int Threads_WaitTID(int TID, int *Status)
185 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
189 // Any peer/child thread
191 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
197 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
204 tThread *thread = Threads_GetThread(TID);
205 tThread *us = gpCurrentThread;
206 if(!thread) return -1;
211 if(thread->WaitingThreadsEnd)
213 thread->WaitingThreadsEnd->Next = us;
214 thread->WaitingThreadsEnd = us;
218 thread->WaitingThreads = us;
219 thread->WaitingThreadsEnd = us;
222 while(thread->State != 0)
225 Log_Debug("Threads", "Huh?... state = %i", thread->State);
228 if(Status) *Status = thread->ExitStatus;
229 thread->WaitingThreads = thread->WaitingThreads->Next;
238 void Threads_Sleep(void)
240 // TODO: Add to a sleeping queue
244 void Threads_Yield(void)
249 void Threads_Exit(int TID, int Status)
253 // VFS_Handles_Cleanup();
255 gpCurrentThread->ExitStatus = Status;
258 if( gpCurrentThread->Parent )
260 // Wait for the thread to be waited upon
261 while( gpCurrentThread->WaitingThreads == NULL )
266 while( (toWake = gpCurrentThread->WaitingThreads) )
268 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
270 Threads_Wake(toWake);
272 while(gpCurrentThread->WaitingThreads == toWake)
277 int Threads_Wake(tThread *Thread)
280 kill( Thread->KernelTID, SIGUSR1 );
284 int Threads_WakeTID(tTID TID)
287 thread = Threads_GetThread(TID);
288 if( !thread ) return -1;
289 return Threads_Wake(thread);
292 int Threads_CreateRootProcess(void)
294 tThread *thread = Threads_CloneTCB(&gThreadZero);
295 thread->PID = thread->TID;
297 // Handle list is created on first open
302 int Threads_Fork(void)
304 tThread *thread = Threads_CloneTCB(gpCurrentThread);
305 thread->PID = thread->TID;
306 // Duplicate the VFS handles (and nodes) from vfs_handle.c
308 VFS_CloneHandleList(thread->PID);
313 int Mutex_Acquire(tMutex *Mutex)
315 if(!Mutex->Protector.IsValid) {
316 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
317 Mutex->Protector.IsValid = 1;
319 pthread_mutex_lock( &Mutex->Protector.Mutex );
323 void Mutex_Release(tMutex *Mutex)
325 pthread_mutex_unlock( &Mutex->Protector.Mutex );
328 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
330 memset(Sem, 0, sizeof(tSemaphore));
331 // HACK: Use `Sem->Protector` as space for the semaphore pointer
332 *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
335 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
337 SDL_SemWait( *(void**)(&Sem->Protector) );
341 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
344 for( i = 0; i < AmmountToAdd; i ++ )
345 SDL_SemPost( *(void**)(&Sem->Protector) );
352 gpCurrentThread->State = 3;
353 if( setjmp(&gpCurrentThread->CurState) == 0 ) {
354 // Return to user wait
355 // Hmm... maybe I should have a "kernel" thread for every "user" thread
358 // Just woken up, return
363 int SaveState(tState *To)
366 __asm__ __volatile__(
372 // If we just returned
376 __asm__ __volatile__ ("mov %%esp, %1" : "=r"(To->SP));
377 __asm__ __volatile__ ("mov %%ebp, %1" : "=r"(To->BP));