AcessNative - Huge changes, cleaning up and getting it to work
[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 sThread
36 {
37         struct sThread  *GlobalNext;
38         struct sThread  *Next;
39
40          int    KernelTID;
41
42         tTID    TID, PID;
43         tUID    UID, GID;
44
45         struct sThread  *Parent;
46
47         char    *ThreadName;
48
49          int    State;  // 0: Dead, 1: Active, 2: Paused, 3: Asleep
50          int    ExitStatus;
51         #if 0
52         tState  CurState;
53         #endif
54
55         // Threads waiting for this thread to exit.
56         // Quit logic:
57         // - Wait for `WaitingThreads` to be non-null (maybe?)
58         // - Wake first in the queue, wait for it to be removed
59         // - Repeat
60         // - Free thread and quit kernel thread
61         struct sThread  *WaitingThreads;
62         struct sThread  *WaitingThreadsEnd;
63
64         // Config?
65         Uint    Config[NUM_CFG_ENTRIES];
66 }       tThread;
67
68 // === PROTOTYPES ===
69  int    Threads_Wake(tThread *Thread);
70
71 // === GLOBALS ===
72 tThread gThreadZero = {
73         State: 1,
74         ThreadName: "ThreadZero"
75 };
76 tThread *gpThreads = &gThreadZero;
77 __thread tThread        *gpCurrentThread = &gThreadZero;
78  int    giThreads_NextThreadID = 1;
79
80 // === CODE ===
81 void Threads_Dump(void)
82 {
83         tThread *thread;
84         for( thread = gpThreads; thread; thread = thread->GlobalNext )
85         {
86                 Log_Log("Threads", "TID %i (%s), PID %i",
87                         thread->TID, thread->ThreadName, thread->PID);
88                 Log_Log("Threads", "User: %i, Group: %i",
89                         thread->UID, thread->GID);
90                 Log_Log("Threads", "Kernel Thread ID: %i",
91                         thread->KernelTID);
92         }
93 }
94
95 tThread *Threads_GetThread(int TID)
96 {
97         tThread *thread;
98         for( thread = gpThreads; thread; thread = thread->GlobalNext )
99         {
100                 if( thread->TID == TID )
101                         return thread;
102         }
103         return NULL;
104 }
105
106 /**
107  * \brief Clone a thread control block (with a different TID)
108  */
109 tThread *Threads_CloneTCB(tThread *TemplateThread)
110 {
111         tThread *ret = malloc(sizeof(tThread));
112         
113         memcpy(ret, TemplateThread, sizeof(tThread));
114         
115         ret->TID = giThreads_NextThreadID ++;
116         
117         ret->ThreadName = strdup(TemplateThread->ThreadName);
118         
119         ret->WaitingThreads = NULL;
120         ret->WaitingThreadsEnd = NULL;
121         
122         // Add to the end of the queue
123         // TODO: Handle concurrency issues
124         ret->GlobalNext = gpThreads;
125         gpThreads = ret;
126         
127         return ret;
128 }
129
130 tUID Threads_GetUID() { return gpCurrentThread->UID; }
131 tGID Threads_GetGID() { return gpCurrentThread->GID; }
132 tTID Threads_GetTID() { return gpCurrentThread->TID; }
133 tPID Threads_GetPID() { return gpCurrentThread->PID; }
134
135 int Threads_SetUID(int *Errno, tUID NewUID)
136 {
137         if(Threads_GetUID() != 0) {
138                 if(Errno)       *Errno = -EACCES;
139                 return -1;
140         }
141         
142         gpCurrentThread->UID = NewUID;
143         return 0;
144 }
145
146 int Threads_SetGID(int *Errno, tGID NewGID)
147 {
148         if(Threads_GetUID() != 0) {
149                 if(Errno)       *Errno = -EACCES;
150                 return -1;
151         }
152         
153         gpCurrentThread->GID = NewGID;
154         return 0;
155 }
156
157 Uint *Threads_GetCfgPtr(int Index)
158 {
159         if( Index < 0 || Index >= NUM_CFG_ENTRIES )
160                 return NULL;
161         if( !gpCurrentThread )
162                 return NULL;
163         return &gpCurrentThread->Config[Index];
164 }
165
166 int 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->State = 3;
195                 if(thread->WaitingThreadsEnd)
196                 {
197                         thread->WaitingThreadsEnd->Next = us;
198                         thread->WaitingThreadsEnd = us;
199                 }
200                 else
201                 {
202                         thread->WaitingThreads = us;
203                         thread->WaitingThreadsEnd = us;
204                 }
205                 
206                 while(thread->State != 0)
207                         pause();
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         #if 1
237         // Wait for the thread to be waited upon
238         while( gpCurrentThread->WaitingThreads == NULL )
239                 SDL_Delay(10);
240         #endif
241         
242         while( (toWake = gpCurrentThread->WaitingThreads) )
243         {
244                 Threads_Wake(toWake);
245                 
246                 while(gpCurrentThread->WaitingThreads == toWake)
247                         SDL_Delay(10);
248         }
249 }
250
251 int Threads_Wake(tThread *Thread)
252 {
253         kill( Thread->KernelTID, SIGUSR1 );
254         return 0;
255 }
256
257 int Threads_WakeTID(tTID TID)
258 {
259         tThread *thread;
260         thread = Threads_GetThread(TID);
261         if( !thread )   return -1;
262         return Threads_Wake(thread);
263 }
264
265 int Threads_CreateRootProcess(void)
266 {
267         tThread *thread = Threads_CloneTCB(&gThreadZero);
268         thread->PID = thread->TID;
269         
270         // Handle list is created on first open
271         
272         return thread->PID;
273 }
274
275 int Threads_Fork(void)
276 {
277         tThread *thread = Threads_CloneTCB(gpCurrentThread);
278         thread->PID = thread->TID;
279         // Duplicate the VFS handles (and nodes) from vfs_handle.c
280         
281         VFS_CloneHandleList(thread->PID);
282         
283         return thread->PID;
284 }
285
286 int Mutex_Acquire(tMutex *Mutex)
287 {
288         if(!Mutex->Protector.IsValid) {
289                 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
290                 Mutex->Protector.IsValid = 1;
291         }
292         pthread_mutex_lock( &Mutex->Protector.Mutex );
293         return 0;
294 }
295
296 void Mutex_Release(tMutex *Mutex)
297 {
298         pthread_mutex_unlock( &Mutex->Protector.Mutex );
299 }
300
301 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
302 {
303         memset(Sem, 0, sizeof(tSemaphore));
304         // HACK: Use `Sem->Protector` as space for the semaphore pointer
305         *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
306 }
307
308 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
309 {
310         SDL_SemWait( *(void**)(&Sem->Protector) );
311         return 1;
312 }
313
314 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
315 {
316          int    i;
317         for( i = 0; i < AmmountToAdd; i ++ )
318                 SDL_SemPost( *(void**)(&Sem->Protector) );
319         return AmmountToAdd;
320 }
321
322 #if 0
323 void Threads_Sleep()
324 {
325         gpCurrentThread->State = 3;
326         if( setjmp(&gpCurrentThread->CurState) == 0 ) {
327                 // Return to user wait
328                 // Hmm... maybe I should have a "kernel" thread for every "user" thread
329         }
330         else {
331                 // Just woken up, return
332                 return ;
333         }
334 }
335
336 int SaveState(tState *To)
337 {
338         Uint    ip;
339         __asm__ __volatile__(
340                 "call 1f;\n\t"
341                 "1f:\n\t"
342                 "pop %%eax"
343                 : "=a" (ip)
344                 : );
345         // If we just returned
346         if(!ip) return 1;
347
348         To->IP = ip;
349         __asm__ __volatile__ ("mov %%esp, %1" : "=r"(To->SP));
350         __asm__ __volatile__ ("mov %%ebp, %1" : "=r"(To->BP));
351 }
352 #endif
353

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