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

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