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)
12 #define off_t _acess_off_t
14 #undef NULL // Remove acess definition
17 #include <semaphore.h>
20 #undef CLONE_VM // Such a hack
25 #include <sys/types.h>
27 #include "/usr/include/signal.h"
30 #define THREAD_EVENT_WAKEUP 0x80000000
33 void VFS_CloneHandleList(int PID);
44 typedef struct sProcess
55 struct sThread *GlobalNext;
63 struct sThread *Parent;
67 int State; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
71 // Threads waiting for this thread to exit.
73 // - Wait for `WaitingThreads` to be non-null (maybe?)
74 // - Wake first in the queue, wait for it to be removed
76 // - Free thread and quit kernel thread
77 struct sThread *WaitingThreads;
78 struct sThread *WaitingThreadsEnd;
82 Uint32 Events, WaitMask;
88 int Threads_Wake(tThread *Thread);
91 tProcess gProcessZero = {
97 tThread gThreadZero = {
99 .ThreadName="ThreadZero",
100 .Process = &gProcessZero
102 tThread *gpThreads = &gThreadZero;
103 __thread tThread *gpCurrentThread = &gThreadZero;
104 int giThreads_NextThreadID = 1;
107 tThread *Proc_GetCurThread(void)
109 return gpCurrentThread;
112 void Threads_Dump(void)
115 for( thread = gpThreads; thread; thread = thread->GlobalNext )
117 Log_Log("Threads", "TID %i (%s), PID %i",
118 thread->TID, thread->ThreadName, thread->PID);
119 Log_Log("Threads", "User: %i, Group: %i",
120 thread->UID, thread->GID);
121 Log_Log("Threads", "Kernel Thread ID: %i",
126 void Threads_SetThread(int TID)
129 for( thread = gpThreads; thread; thread = thread->GlobalNext )
131 if( thread->TID == TID ) {
132 gpCurrentThread = thread;
136 Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
139 tThread *Threads_GetThread(int TID)
142 for( thread = gpThreads; thread; thread = thread->GlobalNext )
144 if( thread->TID == TID )
151 * \brief Clone a thread control block (with a different TID)
153 tThread *Threads_CloneTCB(tThread *TemplateThread)
155 tThread *ret = malloc(sizeof(tThread));
157 memcpy(ret, TemplateThread, sizeof(tThread));
159 ret->TID = giThreads_NextThreadID ++;
161 ret->ThreadName = strdup(TemplateThread->ThreadName);
162 ret->EventSem = SDL_CreateSemaphore(0);
164 ret->WaitingThreads = NULL;
165 ret->WaitingThreadsEnd = NULL;
167 // Add to the end of the queue
168 // TODO: Handle concurrency issues
169 ret->GlobalNext = gpThreads;
175 tUID Threads_GetUID() { return gpCurrentThread->UID; }
176 tGID Threads_GetGID() { return gpCurrentThread->GID; }
177 tTID Threads_GetTID() { return gpCurrentThread->TID; }
178 tPID Threads_GetPID() { return gpCurrentThread->PID; }
180 int Threads_SetUID(tUID NewUID)
182 if(Threads_GetUID() != 0) {
187 gpCurrentThread->UID = NewUID;
191 int Threads_SetGID(tGID NewGID)
193 if(Threads_GetUID() != 0) {
198 gpCurrentThread->GID = NewGID;
202 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
203 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
204 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
205 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
207 tTID Threads_WaitTID(int TID, int *Status)
211 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
215 // Any peer/child thread
217 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
223 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
230 tThread *thread = Threads_GetThread(TID);
231 tThread *us = gpCurrentThread;
232 if(!thread) return -1;
237 if(thread->WaitingThreadsEnd)
239 thread->WaitingThreadsEnd->Next = us;
240 thread->WaitingThreadsEnd = us;
244 thread->WaitingThreads = us;
245 thread->WaitingThreadsEnd = us;
248 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
250 if(Status) *Status = thread->ExitStatus;
251 thread->WaitingThreads = thread->WaitingThreads->Next;
260 void Threads_Sleep(void)
262 // TODO: Add to a sleeping queue
266 void Threads_Yield(void)
271 void Threads_Exit(int TID, int Status)
275 // VFS_Handles_Cleanup();
277 gpCurrentThread->ExitStatus = Status;
280 if( gpCurrentThread->Parent )
282 // Wait for the thread to be waited upon
283 while( gpCurrentThread->WaitingThreads == NULL )
288 while( (toWake = gpCurrentThread->WaitingThreads) )
290 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
292 Threads_Wake(toWake);
294 while(gpCurrentThread->WaitingThreads == toWake)
299 int Threads_Wake(tThread *Thread)
302 Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
306 int Threads_WakeTID(tTID TID)
309 thread = Threads_GetThread(TID);
310 if( !thread ) return -1;
311 return Threads_Wake(thread);
314 int Threads_CreateRootProcess(void)
316 tThread *thread = Threads_CloneTCB(&gThreadZero);
317 thread->PID = thread->TID;
319 // Handle list is created on first open
324 int Threads_Fork(void)
326 tThread *thread = Threads_CloneTCB(gpCurrentThread);
327 thread->PID = thread->TID;
328 // Duplicate the VFS handles (and nodes) from vfs_handle.c
330 VFS_CloneHandleList(thread->PID);
335 int Mutex_Acquire(tMutex *Mutex)
337 if(!Mutex->Protector.IsValid) {
338 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
339 Mutex->Protector.IsValid = 1;
341 pthread_mutex_lock( &Mutex->Protector.Mutex );
345 void Mutex_Release(tMutex *Mutex)
347 pthread_mutex_unlock( &Mutex->Protector.Mutex );
350 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
352 memset(Sem, 0, sizeof(tSemaphore));
353 // HACK: Use `Sem->Protector` as space for the semaphore pointer
354 *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
357 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
359 SDL_SemWait( *(void**)(&Sem->Protector) );
363 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
366 for( i = 0; i < AmmountToAdd; i ++ )
367 SDL_SemPost( *(void**)(&Sem->Protector) );
371 Uint32 Threads_WaitEvents(Uint32 Mask)
375 Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);
377 gpCurrentThread->WaitMask = Mask;
378 if( !(gpCurrentThread->Events & Mask) )
380 SDL_SemWait( gpCurrentThread->EventSem );
382 rv = gpCurrentThread->Events & Mask;
383 gpCurrentThread->Events &= ~Mask;
384 gpCurrentThread->WaitMask = -1;
389 void Threads_PostEvent(tThread *Thread, Uint32 Events)
391 Thread->Events |= Events;
392 Log_Debug("Threads", "Trigger event %x (->Events = %p)", Events, Thread->Events);
394 if( Thread->WaitMask & Events ) {
395 SDL_SemPost( Thread->EventSem );
396 // Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);