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 sProcess
44 typedef struct sThread
46 struct sThread *GlobalNext;
54 struct sThread *Parent;
58 int State; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
62 // Threads waiting for this thread to exit.
64 // - Wait for `WaitingThreads` to be non-null (maybe?)
65 // - Wake first in the queue, wait for it to be removed
67 // - Free thread and quit kernel thread
68 struct sThread *WaitingThreads;
69 struct sThread *WaitingThreadsEnd;
73 Uint32 Events, WaitMask;
79 int Threads_Wake(tThread *Thread);
82 tProcess gProcessZero = {
88 tThread gThreadZero = {
90 .ThreadName="ThreadZero",
91 .Process = &gProcessZero
93 tThread *gpThreads = &gThreadZero;
94 __thread tThread *gpCurrentThread = &gThreadZero;
95 int giThreads_NextThreadID = 1;
98 tThread *Proc_GetCurThread(void)
100 return gpCurrentThread;
103 void Threads_Dump(void)
106 for( thread = gpThreads; thread; thread = thread->GlobalNext )
108 Log_Log("Threads", "TID %i (%s), PID %i",
109 thread->TID, thread->ThreadName, thread->PID);
110 Log_Log("Threads", "User: %i, Group: %i",
111 thread->UID, thread->GID);
112 Log_Log("Threads", "Kernel Thread ID: %i",
117 void Threads_SetThread(int TID)
120 for( thread = gpThreads; thread; thread = thread->GlobalNext )
122 if( thread->TID == TID ) {
123 gpCurrentThread = thread;
127 Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
130 tThread *Threads_GetThread(int TID)
133 for( thread = gpThreads; thread; thread = thread->GlobalNext )
135 if( thread->TID == TID )
142 * \brief Clone a thread control block (with a different TID)
144 tThread *Threads_CloneTCB(tThread *TemplateThread)
146 tThread *ret = malloc(sizeof(tThread));
148 memcpy(ret, TemplateThread, sizeof(tThread));
150 ret->TID = giThreads_NextThreadID ++;
152 ret->ThreadName = strdup(TemplateThread->ThreadName);
154 ret->WaitingThreads = NULL;
155 ret->WaitingThreadsEnd = NULL;
157 // Add to the end of the queue
158 // TODO: Handle concurrency issues
159 ret->GlobalNext = gpThreads;
165 tUID Threads_GetUID() { return gpCurrentThread->UID; }
166 tGID Threads_GetGID() { return gpCurrentThread->GID; }
167 tTID Threads_GetTID() { return gpCurrentThread->TID; }
168 tPID Threads_GetPID() { return gpCurrentThread->PID; }
170 int Threads_SetUID(int *Errno, tUID NewUID)
172 if(Threads_GetUID() != 0) {
173 if(Errno) *Errno = -EACCES;
177 gpCurrentThread->UID = NewUID;
181 int Threads_SetGID(int *Errno, tGID NewGID)
183 if(Threads_GetUID() != 0) {
184 if(Errno) *Errno = -EACCES;
188 gpCurrentThread->GID = NewGID;
192 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
193 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
194 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
195 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
197 int Threads_WaitTID(int TID, int *Status)
201 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
205 // Any peer/child thread
207 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
213 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
220 tThread *thread = Threads_GetThread(TID);
221 tThread *us = gpCurrentThread;
222 if(!thread) return -1;
227 if(thread->WaitingThreadsEnd)
229 thread->WaitingThreadsEnd->Next = us;
230 thread->WaitingThreadsEnd = us;
234 thread->WaitingThreads = us;
235 thread->WaitingThreadsEnd = us;
238 while(thread->State != 0)
241 Log_Debug("Threads", "Huh?... state = %i", thread->State);
244 if(Status) *Status = thread->ExitStatus;
245 thread->WaitingThreads = thread->WaitingThreads->Next;
254 void Threads_Sleep(void)
256 // TODO: Add to a sleeping queue
260 void Threads_Yield(void)
265 void Threads_Exit(int TID, int Status)
269 // VFS_Handles_Cleanup();
271 gpCurrentThread->ExitStatus = Status;
274 if( gpCurrentThread->Parent )
276 // Wait for the thread to be waited upon
277 while( gpCurrentThread->WaitingThreads == NULL )
282 while( (toWake = gpCurrentThread->WaitingThreads) )
284 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
286 Threads_Wake(toWake);
288 while(gpCurrentThread->WaitingThreads == toWake)
293 int Threads_Wake(tThread *Thread)
296 kill( Thread->KernelTID, SIGUSR1 );
300 int Threads_WakeTID(tTID TID)
303 thread = Threads_GetThread(TID);
304 if( !thread ) return -1;
305 return Threads_Wake(thread);
308 int Threads_CreateRootProcess(void)
310 tThread *thread = Threads_CloneTCB(&gThreadZero);
311 thread->PID = thread->TID;
313 // Handle list is created on first open
318 int Threads_Fork(void)
320 tThread *thread = Threads_CloneTCB(gpCurrentThread);
321 thread->PID = thread->TID;
322 // Duplicate the VFS handles (and nodes) from vfs_handle.c
324 VFS_CloneHandleList(thread->PID);
329 int Mutex_Acquire(tMutex *Mutex)
331 if(!Mutex->Protector.IsValid) {
332 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
333 Mutex->Protector.IsValid = 1;
335 pthread_mutex_lock( &Mutex->Protector.Mutex );
339 void Mutex_Release(tMutex *Mutex)
341 pthread_mutex_unlock( &Mutex->Protector.Mutex );
344 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
346 memset(Sem, 0, sizeof(tSemaphore));
347 // HACK: Use `Sem->Protector` as space for the semaphore pointer
348 *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
351 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
353 SDL_SemWait( *(void**)(&Sem->Protector) );
357 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
360 for( i = 0; i < AmmountToAdd; i ++ )
361 SDL_SemPost( *(void**)(&Sem->Protector) );
365 Uint32 Threads_WaitEvents(Uint32 Mask)
368 gpCurrentThread->WaitMask = Mask;
369 if( !(gpCurrentThread->Events & Mask) )
370 SDL_SemWait( gpCurrentThread->EventSem );
371 rv = gpCurrentThread->Events & Mask;
372 gpCurrentThread->Events &= ~Mask;
373 gpCurrentThread->WaitMask = -1;
377 void Threads_PostEvent(tThread *Thread, Uint32 Events)
379 Thread->Events |= Events;
381 if( Thread->WaitMask & Events )
382 SDL_SemPost( gpCurrentThread->EventSem );