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

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