71fa2941c5fa4852ad05140d457b12cfdd2fdba1
[tpg/acess2.git] / AcessNative / acesskernel_src / threads.c
1 /*
2  * Acess2 Native Kernel
3  * - Acess kernel emulation on another OS using SDL and UDP
4  *
5  * threads.c
6  * - Thread and process handling
7  */
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
12 #define off_t   _acess_off_t
13 #include <arch.h>
14 #undef NULL     // Remove acess definition
15 #include <acess.h>
16 #include <mutex.h>
17 #include <semaphore.h>
18 #include <events.h>
19
20 #undef CLONE_VM // Such a hack
21 #undef off_t    
22
23 // - Native headers
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <stdint.h>
27 #include "/usr/include/signal.h"
28 #include <SDL/SDL.h>
29
30 #define THREAD_EVENT_WAKEUP     0x80000000
31
32 // === IMPORTS ===
33 void    VFS_CloneHandleList(int PID);
34
35 // === STRUCTURES ===
36 #if 0
37 typedef struct sState
38 {
39         void    *CurState;
40         Uint    SP, BP, IP;
41 }       tState;
42 #endif
43
44 typedef struct sProcess
45 {
46          int    nThreads;
47          int    NativePID;
48         char    *CWD;
49         char    *Chroot;
50          int    MaxFD;
51 } tProcess;
52
53 struct sThread
54 {
55         struct sThread  *GlobalNext;
56         struct sThread  *Next;
57
58          int    KernelTID;
59
60         tTID    TID, PID;
61         tUID    UID, GID;
62
63         struct sThread  *Parent;
64
65         char    *ThreadName;
66
67          int    State;  // 0: Dead, 1: Active, 2: Paused, 3: Asleep
68          int    ExitStatus;
69          int    _errno;
70
71         // Threads waiting for this thread to exit.
72         // Quit logic:
73         // - Wait for `WaitingThreads` to be non-null (maybe?)
74         // - Wake first in the queue, wait for it to be removed
75         // - Repeat
76         // - Free thread and quit kernel thread
77         struct sThread  *WaitingThreads;
78         struct sThread  *WaitingThreadsEnd;
79
80         tProcess        *Process;       
81
82         Uint32  Events, WaitMask;
83         SDL_sem *EventSem;
84
85 };
86
87 // === PROTOTYPES ===
88  int    Threads_Wake(tThread *Thread);
89
90 // === GLOBALS ===
91 tProcess gProcessZero = {
92         .NativePID = 0,
93         .CWD = "/",
94         .Chroot = "/",
95         .MaxFD = 100
96 };
97 tThread gThreadZero = {
98         .State=1,
99         .ThreadName="ThreadZero",
100         .Process = &gProcessZero
101 };
102 tThread *gpThreads = &gThreadZero;
103 __thread tThread        *gpCurrentThread = &gThreadZero;
104  int    giThreads_NextThreadID = 1;
105
106 // === CODE ===
107 tThread *Proc_GetCurThread(void)
108 {
109         return gpCurrentThread;
110 }
111
112 void Threads_Dump(void)
113 {
114         tThread *thread;
115         for( thread = gpThreads; thread; thread = thread->GlobalNext )
116         {
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",
122                         thread->KernelTID);
123         }
124 }
125
126 void Threads_SetThread(int TID)
127 {
128         tThread *thread;
129         for( thread = gpThreads; thread; thread = thread->GlobalNext )
130         {
131                 if( thread->TID == TID ) {
132                         gpCurrentThread = thread;
133                         return ;
134                 }
135         }
136         Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
137 }
138
139 tThread *Threads_GetThread(int TID)
140 {
141         tThread *thread;
142         for( thread = gpThreads; thread; thread = thread->GlobalNext )
143         {
144                 if( thread->TID == TID )
145                         return thread;
146         }
147         return NULL;
148 }
149
150 /**
151  * \brief Clone a thread control block (with a different TID)
152  */
153 tThread *Threads_CloneTCB(tThread *TemplateThread)
154 {
155         tThread *ret = malloc(sizeof(tThread));
156         
157         memcpy(ret, TemplateThread, sizeof(tThread));
158         
159         ret->TID = giThreads_NextThreadID ++;
160         
161         ret->ThreadName = strdup(TemplateThread->ThreadName);
162         ret->EventSem = SDL_CreateSemaphore(0);
163         
164         ret->WaitingThreads = NULL;
165         ret->WaitingThreadsEnd = NULL;
166         
167         // Add to the end of the queue
168         // TODO: Handle concurrency issues
169         ret->GlobalNext = gpThreads;
170         gpThreads = ret;
171         
172         return ret;
173 }
174
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; }
179
180 int Threads_SetUID(tUID NewUID)
181 {
182         if(Threads_GetUID() != 0) {
183                 errno = EACCES;
184                 return -1;
185         }
186         
187         gpCurrentThread->UID = NewUID;
188         return 0;
189 }
190
191 int Threads_SetGID(tGID NewGID)
192 {
193         if(Threads_GetUID() != 0) {
194                 errno = -EACCES;
195                 return -1;
196         }
197         
198         gpCurrentThread->GID = NewGID;
199         return 0;
200 }
201
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; };
206
207 tTID Threads_WaitTID(int TID, int *Status)
208 {
209         // Any Child
210         if(TID == -1) {
211                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
212                 return -1;
213         }
214         
215         // Any peer/child thread
216         if(TID == 0) {
217                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
218                 return -1;
219         }
220         
221         // TGID = abs(TID)
222         if(TID < -1) {
223                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
224                 return -1;
225         }
226         
227         // Specific Thread
228         if(TID > 0) {
229                 
230                 tThread *thread = Threads_GetThread(TID);
231                 tThread *us = gpCurrentThread;
232                 if(!thread)     return -1;
233                 
234                 us->Next = NULL;
235                 us->State = 3;
236                 // TODO: Locking
237                 if(thread->WaitingThreadsEnd)
238                 {
239                         thread->WaitingThreadsEnd->Next = us;
240                         thread->WaitingThreadsEnd = us;
241                 }
242                 else
243                 {
244                         thread->WaitingThreads = us;
245                         thread->WaitingThreadsEnd = us;
246                 }
247                 
248                 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
249                 
250                 if(Status)      *Status = thread->ExitStatus;
251                 thread->WaitingThreads = thread->WaitingThreads->Next;
252                 us->Next = NULL;
253                 
254                 return TID;
255         }
256         
257         return 0;
258 }
259
260 void Threads_Sleep(void)
261 {
262         // TODO: Add to a sleeping queue
263         pause();
264 }
265
266 void Threads_Yield(void)
267 {
268 //      yield();
269 }
270
271 void Threads_Exit(int TID, int Status)
272 {
273         tThread *toWake;
274         
275 //      VFS_Handles_Cleanup();
276
277         gpCurrentThread->ExitStatus = Status;
278         
279         #if 1
280         if( gpCurrentThread->Parent )
281         {
282                 // Wait for the thread to be waited upon
283                 while( gpCurrentThread->WaitingThreads == NULL )
284                         SDL_Delay(10);
285         }
286         #endif
287         
288         while( (toWake = gpCurrentThread->WaitingThreads) )
289         {
290                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
291
292                 Threads_Wake(toWake);
293                 
294                 while(gpCurrentThread->WaitingThreads == toWake)
295                         SDL_Delay(10);
296         }
297 }
298
299 int Threads_Wake(tThread *Thread)
300 {
301         Thread->State = 0;
302         Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
303         return 0;
304 }
305
306 int Threads_WakeTID(tTID TID)
307 {
308         tThread *thread;
309         thread = Threads_GetThread(TID);
310         if( !thread )   return -1;
311         return Threads_Wake(thread);
312 }
313
314 int Threads_CreateRootProcess(void)
315 {
316         tThread *thread = Threads_CloneTCB(&gThreadZero);
317         thread->PID = thread->TID;
318         
319         // Handle list is created on first open
320         
321         return thread->PID;
322 }
323
324 int Threads_Fork(void)
325 {
326         tThread *thread = Threads_CloneTCB(gpCurrentThread);
327         thread->PID = thread->TID;
328         // Duplicate the VFS handles (and nodes) from vfs_handle.c
329         
330         VFS_CloneHandleList(thread->PID);
331         
332         return thread->PID;
333 }
334
335 int Mutex_Acquire(tMutex *Mutex)
336 {
337         if(!Mutex->Protector.IsValid) {
338                 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
339                 Mutex->Protector.IsValid = 1;
340         }
341         pthread_mutex_lock( &Mutex->Protector.Mutex );
342         return 0;
343 }
344
345 void Mutex_Release(tMutex *Mutex)
346 {
347         pthread_mutex_unlock( &Mutex->Protector.Mutex );
348 }
349
350 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
351 {
352         memset(Sem, 0, sizeof(tSemaphore));
353         // HACK: Use `Sem->Protector` as space for the semaphore pointer
354         *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
355 }
356
357 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
358 {
359         SDL_SemWait( *(void**)(&Sem->Protector) );
360         return 1;
361 }
362
363 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
364 {
365          int    i;
366         for( i = 0; i < AmmountToAdd; i ++ )
367                 SDL_SemPost( *(void**)(&Sem->Protector) );
368         return AmmountToAdd;
369 }
370
371 Uint32 Threads_WaitEvents(Uint32 Mask)
372 {
373         Uint32  rv;
374
375         Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);        
376
377         gpCurrentThread->WaitMask = Mask;
378         if( !(gpCurrentThread->Events & Mask) )
379         {
380                 SDL_SemWait( gpCurrentThread->EventSem );
381         }
382         rv = gpCurrentThread->Events & Mask;
383         gpCurrentThread->Events &= ~Mask;
384         gpCurrentThread->WaitMask = -1;
385         
386         return rv;
387 }
388
389 void Threads_PostEvent(tThread *Thread, Uint32 Events)
390 {
391         Thread->Events |= Events;
392         Log_Debug("Threads", "Trigger event %x (->Events = %p)", Events, Thread->Events);
393         
394         if( Thread->WaitMask & Events ) {
395                 SDL_SemPost( Thread->EventSem );
396 //              Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
397         }
398 }
399

UCC git Repository :: git.ucc.asn.au