AcessNative - Cleaning up debug
[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         for( thread = gpThreads; thread; thread = thread->GlobalNext )
101         {
102                 if( thread->TID == TID ) {
103                         return thread;
104                 }
105         }
106         return NULL;
107 }
108
109 /**
110  * \brief Clone a thread control block (with a different TID)
111  */
112 tThread *Threads_CloneTCB(tThread *TemplateThread)
113 {
114         tThread *ret = malloc(sizeof(tThread));
115         
116         memcpy(ret, TemplateThread, sizeof(tThread));
117         
118         ret->TID = giThreads_NextThreadID ++;
119         
120         ret->ThreadName = strdup(TemplateThread->ThreadName);
121         ret->EventSem = SDL_CreateSemaphore(0);
122         
123         ret->WaitingThreads = NULL;
124         ret->WaitingThreadsEnd = NULL;
125         
126         // Add to the end of the queue
127         // TODO: Handle concurrency issues
128         ret->GlobalNext = gpThreads;
129         gpThreads = ret;
130         
131         return ret;
132 }
133
134 tUID Threads_GetUID() { return gpCurrentThread->UID; }
135 tGID Threads_GetGID() { return gpCurrentThread->GID; }
136 tTID Threads_GetTID() { return gpCurrentThread->TID; }
137 tPID Threads_GetPID() { return gpCurrentThread->PID; }
138
139 int Threads_SetUID(tUID NewUID)
140 {
141         if(Threads_GetUID() != 0) {
142                 errno = EACCES;
143                 return -1;
144         }
145         
146         gpCurrentThread->UID = NewUID;
147         return 0;
148 }
149
150 int Threads_SetGID(tGID NewGID)
151 {
152         if(Threads_GetUID() != 0) {
153                 errno = -EACCES;
154                 return -1;
155         }
156         
157         gpCurrentThread->GID = NewGID;
158         return 0;
159 }
160
161 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
162 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
163 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
164 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
165
166 tTID Threads_WaitTID(int TID, int *Status)
167 {
168         // Any Child
169         if(TID == -1) {
170                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
171                 return -1;
172         }
173         
174         // Any peer/child thread
175         if(TID == 0) {
176                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
177                 return -1;
178         }
179         
180         // TGID = abs(TID)
181         if(TID < -1) {
182                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
183                 return -1;
184         }
185         
186         // Specific Thread
187         if(TID > 0) {
188                 
189                 tThread *thread = Threads_GetThread(TID);
190                 tThread *us = gpCurrentThread;
191                 if(!thread)     return -1;
192                 
193                 us->Next = NULL;
194                 us->Status = THREAD_STAT_WAITING;
195                 // TODO: Locking
196                 if(thread->WaitingThreadsEnd)
197                 {
198                         thread->WaitingThreadsEnd->Next = us;
199                         thread->WaitingThreadsEnd = us;
200                 }
201                 else
202                 {
203                         thread->WaitingThreads = us;
204                         thread->WaitingThreadsEnd = us;
205                 }
206                 
207                 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
208                 
209                 if(Status)      *Status = thread->ExitStatus;
210                 thread->WaitingThreads = thread->WaitingThreads->Next;
211                 us->Next = NULL;
212                 
213                 return TID;
214         }
215         
216         return 0;
217 }
218
219 void Threads_Sleep(void)
220 {
221         // TODO: Add to a sleeping queue
222         pause();
223 }
224
225 void Threads_Yield(void)
226 {
227 //      yield();
228 }
229
230 void Threads_Exit(int TID, int Status)
231 {
232         tThread *toWake;
233         
234 //      VFS_Handles_Cleanup();
235
236         gpCurrentThread->ExitStatus = Status;
237         
238         #if 1
239         if( gpCurrentThread->Parent )
240         {
241                 // Wait for the thread to be waited upon
242                 while( gpCurrentThread->WaitingThreads == NULL )
243                         SDL_Delay(10);
244         }
245         #endif
246         
247         while( (toWake = gpCurrentThread->WaitingThreads) )
248         {
249                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
250
251                 Threads_Wake(toWake);
252                 
253                 while(gpCurrentThread->WaitingThreads == toWake)
254                         SDL_Delay(10);
255         }
256 }
257
258 int Threads_Wake(tThread *Thread)
259 {
260         Thread->Status = THREAD_STAT_ACTIVE;
261         Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
262         return 0;
263 }
264
265 int Threads_WakeTID(tTID TID)
266 {
267         tThread *thread;
268         thread = Threads_GetThread(TID);
269         if( !thread )   return -1;
270         return Threads_Wake(thread);
271 }
272
273 int Threads_CreateRootProcess(void)
274 {
275         tThread *thread = Threads_CloneTCB(&gThreadZero);
276         thread->PID = thread->TID;
277         
278         // Handle list is created on first open
279         
280         return thread->PID;
281 }
282
283 int Threads_Fork(void)
284 {
285         tThread *thread = Threads_CloneTCB(gpCurrentThread);
286         thread->PID = thread->TID;
287         // Duplicate the VFS handles (and nodes) from vfs_handle.c
288         
289         VFS_CloneHandleList(thread->PID);
290         
291         return thread->PID;
292 }
293
294 // --------------------------------------------------------------------
295 // Mutexes 
296 // --------------------------------------------------------------------
297 int Mutex_Acquire(tMutex *Mutex)
298 {
299         if(!Mutex->Protector.IsValid) {
300                 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
301                 Mutex->Protector.IsValid = 1;
302         }
303         pthread_mutex_lock( &Mutex->Protector.Mutex );
304         return 0;
305 }
306
307 void Mutex_Release(tMutex *Mutex)
308 {
309         pthread_mutex_unlock( &Mutex->Protector.Mutex );
310 }
311
312 // --------------------------------------------------------------------
313 // Semaphores
314 // --------------------------------------------------------------------
315 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
316 {
317         memset(Sem, 0, sizeof(tSemaphore));
318         // HACK: Use `Sem->Protector` as space for the semaphore pointer
319         *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
320 }
321
322 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
323 {
324         SDL_SemWait( *(void**)(&Sem->Protector) );
325         return 1;
326 }
327
328 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
329 {
330          int    i;
331         for( i = 0; i < AmmountToAdd; i ++ )
332                 SDL_SemPost( *(void**)(&Sem->Protector) );
333         return AmmountToAdd;
334 }
335
336 // --------------------------------------------------------------------
337 // Event handling
338 // --------------------------------------------------------------------
339 Uint32 Threads_WaitEvents(Uint32 Mask)
340 {
341         Uint32  rv;
342
343         Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);        
344
345         gpCurrentThread->WaitMask = Mask;
346         if( !(gpCurrentThread->Events & Mask) )
347         {
348                 SDL_SemWait( gpCurrentThread->EventSem );
349         }
350         rv = gpCurrentThread->Events & Mask;
351         gpCurrentThread->Events &= ~Mask;
352         gpCurrentThread->WaitMask = -1;
353         
354         return rv;
355 }
356
357 void Threads_PostEvent(tThread *Thread, Uint32 Events)
358 {
359         Thread->Events |= Events;
360         Log_Debug("Threads", "Trigger event %x (->Events = %p)", Events, Thread->Events);
361         
362         if( Thread->WaitMask & Events ) {
363                 SDL_SemPost( Thread->EventSem );
364 //              Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
365         }
366 }
367
368 void Threads_ClearEvent(Uint32 EventMask)
369 {
370         gpCurrentThread->Events &= ~EventMask;
371 }
372

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