dc4d643aae75b169b491a42b57b72225cf35f4fe
[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                 // TODO: Locking
211                 if(thread->WaitingThreadsEnd)
212                 {
213                         thread->WaitingThreadsEnd->Next = us;
214                         thread->WaitingThreadsEnd = us;
215                 }
216                 else
217                 {
218                         thread->WaitingThreads = us;
219                         thread->WaitingThreadsEnd = us;
220                 }
221                 
222                 while(thread->State != 0)
223                 {
224                         pause();
225                         Log_Debug("Threads", "Huh?... state = %i", thread->State);
226                 }
227                 
228                 if(Status)      *Status = thread->ExitStatus;
229                 thread->WaitingThreads = thread->WaitingThreads->Next;
230                 us->Next = NULL;
231                 
232                 return TID;
233         }
234         
235         return 0;
236 }
237
238 void Threads_Sleep(void)
239 {
240         // TODO: Add to a sleeping queue
241         pause();
242 }
243
244 void Threads_Yield(void)
245 {
246 //      yield();
247 }
248
249 void Threads_Exit(int TID, int Status)
250 {
251         tThread *toWake;
252         
253 //      VFS_Handles_Cleanup();
254
255         gpCurrentThread->ExitStatus = Status;
256         
257         #if 1
258         if( gpCurrentThread->Parent )
259         {
260                 // Wait for the thread to be waited upon
261                 while( gpCurrentThread->WaitingThreads == NULL )
262                         SDL_Delay(10);
263         }
264         #endif
265         
266         while( (toWake = gpCurrentThread->WaitingThreads) )
267         {
268                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
269
270                 Threads_Wake(toWake);
271                 
272                 while(gpCurrentThread->WaitingThreads == toWake)
273                         SDL_Delay(10);
274         }
275 }
276
277 int Threads_Wake(tThread *Thread)
278 {
279         Thread->State = 0;
280         kill( Thread->KernelTID, SIGUSR1 );
281         return 0;
282 }
283
284 int Threads_WakeTID(tTID TID)
285 {
286         tThread *thread;
287         thread = Threads_GetThread(TID);
288         if( !thread )   return -1;
289         return Threads_Wake(thread);
290 }
291
292 int Threads_CreateRootProcess(void)
293 {
294         tThread *thread = Threads_CloneTCB(&gThreadZero);
295         thread->PID = thread->TID;
296         
297         // Handle list is created on first open
298         
299         return thread->PID;
300 }
301
302 int Threads_Fork(void)
303 {
304         tThread *thread = Threads_CloneTCB(gpCurrentThread);
305         thread->PID = thread->TID;
306         // Duplicate the VFS handles (and nodes) from vfs_handle.c
307         
308         VFS_CloneHandleList(thread->PID);
309         
310         return thread->PID;
311 }
312
313 int Mutex_Acquire(tMutex *Mutex)
314 {
315         if(!Mutex->Protector.IsValid) {
316                 pthread_mutex_init( &Mutex->Protector.Mutex, NULL );
317                 Mutex->Protector.IsValid = 1;
318         }
319         pthread_mutex_lock( &Mutex->Protector.Mutex );
320         return 0;
321 }
322
323 void Mutex_Release(tMutex *Mutex)
324 {
325         pthread_mutex_unlock( &Mutex->Protector.Mutex );
326 }
327
328 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
329 {
330         memset(Sem, 0, sizeof(tSemaphore));
331         // HACK: Use `Sem->Protector` as space for the semaphore pointer
332         *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
333 }
334
335 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
336 {
337         SDL_SemWait( *(void**)(&Sem->Protector) );
338         return 1;
339 }
340
341 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
342 {
343          int    i;
344         for( i = 0; i < AmmountToAdd; i ++ )
345                 SDL_SemPost( *(void**)(&Sem->Protector) );
346         return AmmountToAdd;
347 }
348
349 #if 0
350 void Threads_Sleep()
351 {
352         gpCurrentThread->State = 3;
353         if( setjmp(&gpCurrentThread->CurState) == 0 ) {
354                 // Return to user wait
355                 // Hmm... maybe I should have a "kernel" thread for every "user" thread
356         }
357         else {
358                 // Just woken up, return
359                 return ;
360         }
361 }
362
363 int SaveState(tState *To)
364 {
365         Uint    ip;
366         __asm__ __volatile__(
367                 "call 1f;\n\t"
368                 "1f:\n\t"
369                 "pop %%eax"
370                 : "=a" (ip)
371                 : );
372         // If we just returned
373         if(!ip) return 1;
374
375         To->IP = ip;
376         __asm__ __volatile__ ("mov %%esp, %1" : "=r"(To->SP));
377         __asm__ __volatile__ ("mov %%ebp, %1" : "=r"(To->BP));
378 }
379 #endif
380

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