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 #include <threads_int.h>
22 #undef CLONE_VM // Such a hack
27 #include <sys/types.h>
29 #include "/usr/include/signal.h"
32 #define THREAD_EVENT_WAKEUP 0x80000000
35 void VFS_CloneHandleList(int PID);
47 int Threads_Wake(tThread *Thread);
50 tProcess gProcessZero = {
56 tThread gThreadZero = {
57 .Status=THREAD_STAT_ACTIVE,
58 .ThreadName="ThreadZero",
59 .Process = &gProcessZero
61 tThread *gpThreads = &gThreadZero;
62 __thread tThread *gpCurrentThread = &gThreadZero;
63 int giThreads_NextThreadID = 1;
66 tThread *Proc_GetCurThread(void)
68 return gpCurrentThread;
71 void Threads_Dump(void)
74 for( thread = gpThreads; thread; thread = thread->GlobalNext )
76 Log_Log("Threads", "TID %i (%s), PID %i",
77 thread->TID, thread->ThreadName, thread->PID);
78 Log_Log("Threads", "User: %i, Group: %i",
79 thread->UID, thread->GID);
80 Log_Log("Threads", "Kernel Thread ID: %i",
85 void Threads_SetThread(int TID)
88 for( thread = gpThreads; thread; thread = thread->GlobalNext )
90 if( thread->TID == TID ) {
91 gpCurrentThread = thread;
95 Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
98 tThread *Threads_GetThread(Uint TID)
101 for( thread = gpThreads; thread; thread = thread->GlobalNext )
103 if( thread->TID == TID ) {
111 * \brief Clone a thread control block (with a different TID)
113 tThread *Threads_CloneTCB(tThread *TemplateThread)
115 tThread *ret = malloc(sizeof(tThread));
117 memcpy(ret, TemplateThread, sizeof(tThread));
119 ret->TID = giThreads_NextThreadID ++;
121 ret->ThreadName = strdup(TemplateThread->ThreadName);
122 ret->EventSem = SDL_CreateSemaphore(0);
123 if( !ret->EventSem ) {
124 Log_Warning("Threads", "Semaphore creation failed - %s", SDL_GetError());
127 ret->WaitingThreads = NULL;
128 ret->WaitingThreadsEnd = NULL;
130 // Add to the end of the queue
131 // TODO: Handle concurrency issues
132 ret->GlobalNext = gpThreads;
138 tUID Threads_GetUID() { return gpCurrentThread->UID; }
139 tGID Threads_GetGID() { return gpCurrentThread->GID; }
140 tTID Threads_GetTID() { return gpCurrentThread->TID; }
141 tPID Threads_GetPID() { return gpCurrentThread->PID; }
143 int Threads_SetUID(tUID NewUID)
145 if(Threads_GetUID() != 0) {
150 gpCurrentThread->UID = NewUID;
154 int Threads_SetGID(tGID NewGID)
156 if(Threads_GetUID() != 0) {
161 gpCurrentThread->GID = NewGID;
165 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
166 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
167 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
168 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
170 tTID Threads_WaitTID(int TID, int *Status)
174 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
178 // Any peer/child thread
180 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
186 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
193 tThread *thread = Threads_GetThread(TID);
194 tThread *us = gpCurrentThread;
195 if(!thread) return -1;
198 us->Status = THREAD_STAT_WAITING;
200 if(thread->WaitingThreadsEnd)
202 thread->WaitingThreadsEnd->Next = us;
203 thread->WaitingThreadsEnd = us;
207 thread->WaitingThreads = us;
208 thread->WaitingThreadsEnd = us;
211 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
213 if(Status) *Status = thread->ExitStatus;
214 thread->WaitingThreads = thread->WaitingThreads->Next;
223 void Threads_Sleep(void)
225 // TODO: Add to a sleeping queue
229 void Threads_Yield(void)
234 void Threads_Exit(int TID, int Status)
238 // VFS_Handles_Cleanup();
240 gpCurrentThread->ExitStatus = Status;
243 if( gpCurrentThread->Parent )
245 // Wait for the thread to be waited upon
246 while( gpCurrentThread->WaitingThreads == NULL )
251 while( (toWake = gpCurrentThread->WaitingThreads) )
253 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
255 Threads_Wake(toWake);
257 while(gpCurrentThread->WaitingThreads == toWake)
262 int Threads_Wake(tThread *Thread)
264 Thread->Status = THREAD_STAT_ACTIVE;
265 Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
269 int Threads_WakeTID(tTID TID)
272 thread = Threads_GetThread(TID);
273 if( !thread ) return -1;
274 return Threads_Wake(thread);
277 int Threads_CreateRootProcess(void)
279 tThread *thread = Threads_CloneTCB(&gThreadZero);
280 thread->PID = thread->TID;
282 // Handle list is created on first open
287 int Threads_Fork(void)
289 tThread *thread = Threads_CloneTCB(gpCurrentThread);
290 thread->PID = thread->TID;
291 // Duplicate the VFS handles (and nodes) from vfs_handle.c
293 VFS_CloneHandleList(thread->PID);
298 // --------------------------------------------------------------------
300 // --------------------------------------------------------------------
301 int Mutex_Acquire(tMutex *Mutex)
303 if(!Mutex->Protector.IsValid) {
304 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
305 Mutex->Protector.IsValid = 1;
307 pthread_mutex_lock( &Mutex->Protector.Mutex );
311 void Mutex_Release(tMutex *Mutex)
313 pthread_mutex_unlock( &Mutex->Protector.Mutex );
316 // --------------------------------------------------------------------
318 // --------------------------------------------------------------------
319 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
321 memset(Sem, 0, sizeof(tSemaphore));
322 // HACK: Use `Sem->Protector` as space for the semaphore pointer
323 *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
326 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
328 SDL_SemWait( *(void**)(&Sem->Protector) );
332 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
335 for( i = 0; i < AmmountToAdd; i ++ )
336 SDL_SemPost( *(void**)(&Sem->Protector) );
340 // --------------------------------------------------------------------
342 // --------------------------------------------------------------------
343 int RWLock_AcquireRead(tRWLock *Lock)
345 if( !Lock->ReaderWaiting ) {
346 Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
347 pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
349 pthread_rwlock_rdlock( (void*)Lock->ReaderWaiting );
352 int RWLock_AcquireWrite(tRWLock *Lock)
354 if( !Lock->ReaderWaiting ) {
355 Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
356 pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
358 pthread_rwlock_wrlock( (void*)Lock->ReaderWaiting );
361 void RWLock_Release(tRWLock *Lock)
363 pthread_rwlock_unlock( (void*)Lock->ReaderWaiting );
367 // --------------------------------------------------------------------
369 // --------------------------------------------------------------------
370 Uint32 Threads_WaitEvents(Uint32 Mask)
374 Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);
376 gpCurrentThread->WaitMask = Mask;
377 if( !(gpCurrentThread->Events & Mask) )
380 if( SDL_SemWait( gpCurrentThread->EventSem ) == -1 ) {
381 Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
382 gpCurrentThread, gpCurrentThread->EventSem);
385 } while(SDL_SemValue(gpCurrentThread->EventSem));
386 // NOTE: While loop catches multiple event occurances
387 Log_Debug("Threads", "Woken from nap (%i here)", SDL_SemValue(gpCurrentThread->EventSem));
389 rv = gpCurrentThread->Events & Mask;
390 gpCurrentThread->Events &= ~Mask;
391 gpCurrentThread->WaitMask = -1;
393 Log_Debug("Threads", "- rv = %x", rv);
398 void Threads_PostEvent(tThread *Thread, Uint32 Events)
400 Thread->Events |= Events;
401 Log_Debug("Threads", "Trigger event %x (->Events = %p)", Events, Thread->Events);
403 if( Events == 0 || Thread->WaitMask & Events ) {
404 SDL_SemPost( Thread->EventSem );
405 // Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
409 void Threads_ClearEvent(Uint32 EventMask)
411 gpCurrentThread->Events &= ~EventMask;