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

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