AcessNative - Fixing Fixing Fixing
[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 void Threads_SetThread(int TID)
96 {
97         tThread *thread;
98         for( thread = gpThreads; thread; thread = thread->GlobalNext )
99         {
100                 if( thread->TID == TID ) {
101                         gpCurrentThread = thread;
102                         return ;
103                 }
104         }
105         Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
106 }
107
108 tThread *Threads_GetThread(int TID)
109 {
110         tThread *thread;
111         for( thread = gpThreads; thread; thread = thread->GlobalNext )
112         {
113                 if( thread->TID == TID )
114                         return thread;
115         }
116         return NULL;
117 }
118
119 /**
120  * \brief Clone a thread control block (with a different TID)
121  */
122 tThread *Threads_CloneTCB(tThread *TemplateThread)
123 {
124         tThread *ret = malloc(sizeof(tThread));
125         
126         memcpy(ret, TemplateThread, sizeof(tThread));
127         
128         ret->TID = giThreads_NextThreadID ++;
129         
130         ret->ThreadName = strdup(TemplateThread->ThreadName);
131         
132         ret->WaitingThreads = NULL;
133         ret->WaitingThreadsEnd = NULL;
134         
135         // Add to the end of the queue
136         // TODO: Handle concurrency issues
137         ret->GlobalNext = gpThreads;
138         gpThreads = ret;
139         
140         return ret;
141 }
142
143 tUID Threads_GetUID() { return gpCurrentThread->UID; }
144 tGID Threads_GetGID() { return gpCurrentThread->GID; }
145 tTID Threads_GetTID() { return gpCurrentThread->TID; }
146 tPID Threads_GetPID() { return gpCurrentThread->PID; }
147
148 int Threads_SetUID(int *Errno, tUID NewUID)
149 {
150         if(Threads_GetUID() != 0) {
151                 if(Errno)       *Errno = -EACCES;
152                 return -1;
153         }
154         
155         gpCurrentThread->UID = NewUID;
156         return 0;
157 }
158
159 int Threads_SetGID(int *Errno, tGID NewGID)
160 {
161         if(Threads_GetUID() != 0) {
162                 if(Errno)       *Errno = -EACCES;
163                 return -1;
164         }
165         
166         gpCurrentThread->GID = NewGID;
167         return 0;
168 }
169
170 Uint *Threads_GetCfgPtr(int Index)
171 {
172 //      Log_Debug("Threads", "Index=%i, gpCurrentThread=%p",
173 //              Index, gpCurrentThread);
174         if( Index < 0 || Index >= NUM_CFG_ENTRIES )
175                 return NULL;
176         if( !gpCurrentThread )
177                 return NULL;
178         return &gpCurrentThread->Config[Index];
179 }
180
181 int Threads_WaitTID(int TID, int *Status)
182 {
183         // Any Child
184         if(TID == -1) {
185                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
186                 return -1;
187         }
188         
189         // Any peer/child thread
190         if(TID == 0) {
191                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
192                 return -1;
193         }
194         
195         // TGID = abs(TID)
196         if(TID < -1) {
197                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
198                 return -1;
199         }
200         
201         // Specific Thread
202         if(TID > 0) {
203                 
204                 tThread *thread = Threads_GetThread(TID);
205                 tThread *us = gpCurrentThread;
206                 if(!thread)     return -1;
207                 
208                 us->Next = NULL;
209                 us->State = 3;
210                 if(thread->WaitingThreadsEnd)
211                 {
212                         thread->WaitingThreadsEnd->Next = us;
213                         thread->WaitingThreadsEnd = us;
214                 }
215                 else
216                 {
217                         thread->WaitingThreads = us;
218                         thread->WaitingThreadsEnd = us;
219                 }
220                 
221                 while(thread->State != 0)
222                         pause();
223                 
224                 if(Status)      *Status = thread->ExitStatus;
225                 thread->WaitingThreads = thread->WaitingThreads->Next;
226                 us->Next = NULL;
227                 
228                 return TID;
229         }
230         
231         return 0;
232 }
233
234 void Threads_Sleep(void)
235 {
236         // TODO: Add to a sleeping queue
237         pause();
238 }
239
240 void Threads_Yield(void)
241 {
242 //      yield();
243 }
244
245 void Threads_Exit(int TID, int Status)
246 {
247         tThread *toWake;
248         
249 //      VFS_Handles_Cleanup();
250         
251         #if 1
252         // Wait for the thread to be waited upon
253         while( gpCurrentThread->WaitingThreads == NULL )
254                 SDL_Delay(10);
255         #endif
256         
257         while( (toWake = gpCurrentThread->WaitingThreads) )
258         {
259                 Threads_Wake(toWake);
260                 
261                 while(gpCurrentThread->WaitingThreads == toWake)
262                         SDL_Delay(10);
263         }
264 }
265
266 int Threads_Wake(tThread *Thread)
267 {
268         kill( Thread->KernelTID, SIGUSR1 );
269         return 0;
270 }
271
272 int Threads_WakeTID(tTID TID)
273 {
274         tThread *thread;
275         thread = Threads_GetThread(TID);
276         if( !thread )   return -1;
277         return Threads_Wake(thread);
278 }
279
280 int Threads_CreateRootProcess(void)
281 {
282         tThread *thread = Threads_CloneTCB(&gThreadZero);
283         thread->PID = thread->TID;
284         
285         // Handle list is created on first open
286         
287         return thread->PID;
288 }
289
290 int Threads_Fork(void)
291 {
292         tThread *thread = Threads_CloneTCB(gpCurrentThread);
293         thread->PID = thread->TID;
294         // Duplicate the VFS handles (and nodes) from vfs_handle.c
295         
296         VFS_CloneHandleList(thread->PID);
297         
298         return thread->PID;
299 }
300
301 int Mutex_Acquire(tMutex *Mutex)
302 {
303         if(!Mutex->Protector.IsValid) {
304                 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
305                 Mutex->Protector.IsValid = 1;
306         }
307         pthread_mutex_lock( &Mutex->Protector.Mutex );
308         return 0;
309 }
310
311 void Mutex_Release(tMutex *Mutex)
312 {
313         pthread_mutex_unlock( &Mutex->Protector.Mutex );
314 }
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 #if 0
338 void Threads_Sleep()
339 {
340         gpCurrentThread->State = 3;
341         if( setjmp(&gpCurrentThread->CurState) == 0 ) {
342                 // Return to user wait
343                 // Hmm... maybe I should have a "kernel" thread for every "user" thread
344         }
345         else {
346                 // Just woken up, return
347                 return ;
348         }
349 }
350
351 int SaveState(tState *To)
352 {
353         Uint    ip;
354         __asm__ __volatile__(
355                 "call 1f;\n\t"
356                 "1f:\n\t"
357                 "pop %%eax"
358                 : "=a" (ip)
359                 : );
360         // If we just returned
361         if(!ip) return 1;
362
363         To->IP = ip;
364         __asm__ __volatile__ ("mov %%esp, %1" : "=r"(To->SP));
365         __asm__ __volatile__ ("mov %%ebp, %1" : "=r"(To->BP));
366 }
367 #endif
368

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