3 * - Acess kernel emulation on another OS using SDL and UDP
6 * - Thread and process handling
12 #include "../../KernelLand/Kernel/include/semaphore.h"
15 #include <threads_int.h>
17 #include "include/threads_glue.h"
19 #define THREAD_EVENT_WAKEUP 0x80000000
22 void VFS_CloneHandleList(int PID);
26 int Threads_Wake(tThread *Thread);
29 tProcess gProcessZero = {
35 tThread gThreadZero = {
36 .Status=THREAD_STAT_ACTIVE,
37 .ThreadName="ThreadZero",
38 .Process = &gProcessZero
40 tThread *gpThreads = &gThreadZero;
41 __thread tThread *gpCurrentThread = &gThreadZero;
42 int giThreads_NextThreadID = 1;
45 tThread *Proc_GetCurThread(void)
47 return gpCurrentThread;
50 void Threads_Dump(void)
53 for( thread = gpThreads; thread; thread = thread->GlobalNext )
55 Log_Log("Threads", "TID %i (%s), PID %i",
56 thread->TID, thread->ThreadName, thread->PID);
57 Log_Log("Threads", "User: %i, Group: %i",
58 thread->UID, thread->GID);
59 Log_Log("Threads", "Kernel Thread ID: %i",
64 void Threads_SetThread(int TID)
67 for( thread = gpThreads; thread; thread = thread->GlobalNext )
69 if( thread->TID == TID ) {
70 gpCurrentThread = thread;
74 Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
77 tThread *Threads_GetThread(Uint TID)
80 for( thread = gpThreads; thread; thread = thread->GlobalNext )
82 if( thread->TID == TID ) {
90 * \brief Clone a thread control block (with a different TID)
92 tThread *Threads_CloneTCB(tThread *TemplateThread)
94 tThread *ret = malloc(sizeof(tThread));
96 memcpy(ret, TemplateThread, sizeof(tThread));
98 ret->TID = giThreads_NextThreadID ++;
100 ret->ThreadName = strdup(TemplateThread->ThreadName);
101 Threads_Glue_SemInit( &ret->EventSem, 0 );
103 ret->WaitingThreads = NULL;
104 ret->WaitingThreadsEnd = NULL;
106 // Add to the end of the queue
107 // TODO: Handle concurrency issues
108 ret->GlobalNext = gpThreads;
114 tUID Threads_GetUID() { return gpCurrentThread->UID; }
115 tGID Threads_GetGID() { return gpCurrentThread->GID; }
116 tTID Threads_GetTID() { return gpCurrentThread->TID; }
117 tPID Threads_GetPID() { return gpCurrentThread->PID; }
119 int Threads_SetUID(tUID NewUID)
121 if(Threads_GetUID() != 0) {
126 gpCurrentThread->UID = NewUID;
130 int Threads_SetGID(tGID NewGID)
132 if(Threads_GetUID() != 0) {
137 gpCurrentThread->GID = NewGID;
141 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
142 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
143 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
144 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
146 tTID Threads_WaitTID(int TID, int *Status)
150 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
154 // Any peer/child thread
156 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
162 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
169 tThread *thread = Threads_GetThread(TID);
170 tThread *us = gpCurrentThread;
171 if(!thread) return -1;
174 us->Status = THREAD_STAT_WAITING;
176 if(thread->WaitingThreadsEnd)
178 thread->WaitingThreadsEnd->Next = us;
179 thread->WaitingThreadsEnd = us;
183 thread->WaitingThreads = us;
184 thread->WaitingThreadsEnd = us;
187 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
189 if(Status) *Status = thread->ExitStatus;
190 thread->WaitingThreads = thread->WaitingThreads->Next;
199 void Threads_Sleep(void)
201 // TODO: Add to a sleeping queue
205 void Threads_Yield(void)
210 void Threads_Exit(int TID, int Status)
214 // VFS_Handles_Cleanup();
216 gpCurrentThread->ExitStatus = Status;
219 if( gpCurrentThread->Parent )
221 // Wait for the thread to be waited upon
222 while( gpCurrentThread->WaitingThreads == NULL )
223 Threads_Glue_Yield();
227 while( (toWake = gpCurrentThread->WaitingThreads) )
229 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
231 Threads_Wake(toWake);
233 while(gpCurrentThread->WaitingThreads == toWake)
234 Threads_Glue_Yield();
238 int Threads_Wake(tThread *Thread)
240 Thread->Status = THREAD_STAT_ACTIVE;
241 Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
245 int Threads_WakeTID(tTID TID)
248 thread = Threads_GetThread(TID);
249 if( !thread ) return -1;
250 return Threads_Wake(thread);
253 int Threads_CreateRootProcess(void)
255 tThread *thread = Threads_CloneTCB(&gThreadZero);
256 thread->PID = thread->TID;
258 // Handle list is created on first open
263 int Threads_Fork(void)
265 tThread *thread = Threads_CloneTCB(gpCurrentThread);
266 thread->PID = thread->TID;
267 // Duplicate the VFS handles (and nodes) from vfs_handle.c
269 VFS_CloneHandleList(thread->PID);
274 // --------------------------------------------------------------------
276 // --------------------------------------------------------------------
277 int Mutex_Acquire(tMutex *Mutex)
279 Threads_Glue_AcquireMutex(&Mutex->Protector.Mutex);
283 void Mutex_Release(tMutex *Mutex)
285 Threads_Glue_ReleaseMutex(&Mutex->Protector.Mutex);
288 // --------------------------------------------------------------------
290 // --------------------------------------------------------------------
291 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
293 memset(Sem, 0, sizeof(tSemaphore));
294 // HACK: Use `Sem->Protector` as space for the semaphore pointer
295 Threads_Glue_SemInit( &Sem->Protector.Mutex, InitValue );
298 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
300 return Threads_Glue_SemWait( Sem->Protector.Mutex, MaxToTake );
303 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
305 return Threads_Glue_SemSignal( Sem->Protector.Mutex, AmmountToAdd );
308 // --------------------------------------------------------------------
310 // --------------------------------------------------------------------
311 Uint32 Threads_WaitEvents(Uint32 Mask)
315 //Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);
317 gpCurrentThread->WaitMask = Mask;
318 if( !(gpCurrentThread->Events & Mask) )
320 if( Threads_Glue_SemWait(gpCurrentThread->EventSem, INT_MAX) == -1 ) {
321 Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
322 gpCurrentThread, gpCurrentThread->EventSem);
324 //Log_Debug("Threads", "Woken from nap (%i here)", SDL_SemValue(gpCurrentThread->EventSem));
326 rv = gpCurrentThread->Events & Mask;
327 gpCurrentThread->Events &= ~Mask;
328 gpCurrentThread->WaitMask = -1;
330 //Log_Debug("Threads", "- rv = %x", rv);
335 void Threads_PostEvent(tThread *Thread, Uint32 Events)
337 Thread->Events |= Events;
338 Log_Debug("Threads", "Trigger event %x (->Events = %p) on %p", Events, Thread->Events, Thread);
340 if( Events == 0 || Thread->WaitMask & Events ) {
341 Threads_Glue_SemSignal( Thread->EventSem, 1 );
342 // Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
346 void Threads_ClearEvent(Uint32 EventMask)
348 gpCurrentThread->Events &= ~EventMask;