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

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