AcessNative - Loads login process and runs again (shell doesn't spawn)
[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 <rwlock.h>
19 #include <events.h>
20 #include <threads_int.h>
21
22 #undef CLONE_VM // Such a hack
23 #undef off_t    
24
25 // - Native headers
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <stdint.h>
29 #include "/usr/include/signal.h"
30 #include <SDL/SDL.h>
31
32 #define THREAD_EVENT_WAKEUP     0x80000000
33
34 // === IMPORTS ===
35 void    VFS_CloneHandleList(int PID);
36
37 // === STRUCTURES ===
38 #if 0
39 typedef struct sState
40 {
41         void    *CurState;
42         Uint    SP, BP, IP;
43 }       tState;
44 #endif
45
46 // === PROTOTYPES ===
47  int    Threads_Wake(tThread *Thread);
48
49 // === GLOBALS ===
50 tProcess gProcessZero = {
51         .NativePID = 0,
52         .CWD = "/",
53         .Chroot = "/",
54         .MaxFD = 100
55 };
56 tThread gThreadZero = {
57         .Status=THREAD_STAT_ACTIVE,
58         .ThreadName="ThreadZero",
59         .Process = &gProcessZero
60 };
61 tThread *gpThreads = &gThreadZero;
62 __thread tThread        *gpCurrentThread = &gThreadZero;
63  int    giThreads_NextThreadID = 1;
64
65 // === CODE ===
66 tThread *Proc_GetCurThread(void)
67 {
68         return gpCurrentThread;
69 }
70
71 void Threads_Dump(void)
72 {
73         tThread *thread;
74         for( thread = gpThreads; thread; thread = thread->GlobalNext )
75         {
76                 Log_Log("Threads", "TID %i (%s), PID %i",
77                         thread->TID, thread->ThreadName, thread->PID);
78                 Log_Log("Threads", "User: %i, Group: %i",
79                         thread->UID, thread->GID);
80                 Log_Log("Threads", "Kernel Thread ID: %i",
81                         thread->KernelTID);
82         }
83 }
84
85 void Threads_SetThread(int TID)
86 {
87         tThread *thread;
88         for( thread = gpThreads; thread; thread = thread->GlobalNext )
89         {
90                 if( thread->TID == TID ) {
91                         gpCurrentThread = thread;
92                         return ;
93                 }
94         }
95         Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
96 }
97
98 tThread *Threads_GetThread(Uint TID)
99 {
100         tThread *thread;
101         for( thread = gpThreads; thread; thread = thread->GlobalNext )
102         {
103                 if( thread->TID == TID ) {
104                         return thread;
105                 }
106         }
107         return NULL;
108 }
109
110 /**
111  * \brief Clone a thread control block (with a different TID)
112  */
113 tThread *Threads_CloneTCB(tThread *TemplateThread)
114 {
115         tThread *ret = malloc(sizeof(tThread));
116         
117         memcpy(ret, TemplateThread, sizeof(tThread));
118         
119         ret->TID = giThreads_NextThreadID ++;
120         
121         ret->ThreadName = strdup(TemplateThread->ThreadName);
122         ret->EventSem = SDL_CreateSemaphore(0);
123         if( !ret->EventSem ) {
124                 Log_Warning("Threads", "Semaphore creation failed - %s", SDL_GetError());
125         }
126         
127         ret->WaitingThreads = NULL;
128         ret->WaitingThreadsEnd = NULL;
129         
130         // Add to the end of the queue
131         // TODO: Handle concurrency issues
132         ret->GlobalNext = gpThreads;
133         gpThreads = ret;
134         
135         return ret;
136 }
137
138 tUID Threads_GetUID() { return gpCurrentThread->UID; }
139 tGID Threads_GetGID() { return gpCurrentThread->GID; }
140 tTID Threads_GetTID() { return gpCurrentThread->TID; }
141 tPID Threads_GetPID() { return gpCurrentThread->PID; }
142
143 int Threads_SetUID(tUID NewUID)
144 {
145         if(Threads_GetUID() != 0) {
146                 errno = EACCES;
147                 return -1;
148         }
149         
150         gpCurrentThread->UID = NewUID;
151         return 0;
152 }
153
154 int Threads_SetGID(tGID NewGID)
155 {
156         if(Threads_GetUID() != 0) {
157                 errno = -EACCES;
158                 return -1;
159         }
160         
161         gpCurrentThread->GID = NewGID;
162         return 0;
163 }
164
165 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
166 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
167 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
168 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
169
170 tTID Threads_WaitTID(int TID, int *Status)
171 {
172         // Any Child
173         if(TID == -1) {
174                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
175                 return -1;
176         }
177         
178         // Any peer/child thread
179         if(TID == 0) {
180                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
181                 return -1;
182         }
183         
184         // TGID = abs(TID)
185         if(TID < -1) {
186                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
187                 return -1;
188         }
189         
190         // Specific Thread
191         if(TID > 0) {
192                 
193                 tThread *thread = Threads_GetThread(TID);
194                 tThread *us = gpCurrentThread;
195                 if(!thread)     return -1;
196                 
197                 us->Next = NULL;
198                 us->Status = THREAD_STAT_WAITING;
199                 // TODO: Locking
200                 if(thread->WaitingThreadsEnd)
201                 {
202                         thread->WaitingThreadsEnd->Next = us;
203                         thread->WaitingThreadsEnd = us;
204                 }
205                 else
206                 {
207                         thread->WaitingThreads = us;
208                         thread->WaitingThreadsEnd = us;
209                 }
210                 
211                 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
212                 
213                 if(Status)      *Status = thread->ExitStatus;
214                 thread->WaitingThreads = thread->WaitingThreads->Next;
215                 us->Next = NULL;
216                 
217                 return TID;
218         }
219         
220         return 0;
221 }
222
223 void Threads_Sleep(void)
224 {
225         // TODO: Add to a sleeping queue
226         pause();
227 }
228
229 void Threads_Yield(void)
230 {
231 //      yield();
232 }
233
234 void Threads_Exit(int TID, int Status)
235 {
236         tThread *toWake;
237         
238 //      VFS_Handles_Cleanup();
239
240         gpCurrentThread->ExitStatus = Status;
241         
242         #if 1
243         if( gpCurrentThread->Parent )
244         {
245                 // Wait for the thread to be waited upon
246                 while( gpCurrentThread->WaitingThreads == NULL )
247                         SDL_Delay(10);
248         }
249         #endif
250         
251         while( (toWake = gpCurrentThread->WaitingThreads) )
252         {
253                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
254
255                 Threads_Wake(toWake);
256                 
257                 while(gpCurrentThread->WaitingThreads == toWake)
258                         SDL_Delay(10);
259         }
260 }
261
262 int Threads_Wake(tThread *Thread)
263 {
264         Thread->Status = THREAD_STAT_ACTIVE;
265         Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
266         return 0;
267 }
268
269 int Threads_WakeTID(tTID TID)
270 {
271         tThread *thread;
272         thread = Threads_GetThread(TID);
273         if( !thread )   return -1;
274         return Threads_Wake(thread);
275 }
276
277 int Threads_CreateRootProcess(void)
278 {
279         tThread *thread = Threads_CloneTCB(&gThreadZero);
280         thread->PID = thread->TID;
281         
282         // Handle list is created on first open
283         
284         return thread->PID;
285 }
286
287 int Threads_Fork(void)
288 {
289         tThread *thread = Threads_CloneTCB(gpCurrentThread);
290         thread->PID = thread->TID;
291         // Duplicate the VFS handles (and nodes) from vfs_handle.c
292         
293         VFS_CloneHandleList(thread->PID);
294         
295         return thread->PID;
296 }
297
298 // --------------------------------------------------------------------
299 // Mutexes 
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 // --------------------------------------------------------------------
317 // Semaphores
318 // --------------------------------------------------------------------
319 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
320 {
321         memset(Sem, 0, sizeof(tSemaphore));
322         // HACK: Use `Sem->Protector` as space for the semaphore pointer
323         *(void**)(&Sem->Protector) = SDL_CreateSemaphore(InitValue);
324 }
325
326 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
327 {
328         SDL_SemWait( *(void**)(&Sem->Protector) );
329         return 1;
330 }
331
332 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
333 {
334          int    i;
335         for( i = 0; i < AmmountToAdd; i ++ )
336                 SDL_SemPost( *(void**)(&Sem->Protector) );
337         return AmmountToAdd;
338 }
339
340 // --------------------------------------------------------------------
341 // Event handling
342 // --------------------------------------------------------------------
343 int RWLock_AcquireRead(tRWLock *Lock)
344 {
345         if( !Lock->ReaderWaiting ) {
346                 Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
347                 pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
348         }
349         pthread_rwlock_rdlock( (void*)Lock->ReaderWaiting );
350         return 0;
351 }
352 int RWLock_AcquireWrite(tRWLock *Lock)
353 {
354         if( !Lock->ReaderWaiting ) {
355                 Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
356                 pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
357         }
358         pthread_rwlock_wrlock( (void*)Lock->ReaderWaiting );
359         return 0;
360 }
361 void RWLock_Release(tRWLock *Lock)
362 {
363         pthread_rwlock_unlock( (void*)Lock->ReaderWaiting );
364 }
365
366
367 // --------------------------------------------------------------------
368 // Event handling
369 // --------------------------------------------------------------------
370 Uint32 Threads_WaitEvents(Uint32 Mask)
371 {
372         Uint32  rv;
373
374         Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);        
375
376         gpCurrentThread->WaitMask = Mask;
377         if( !(gpCurrentThread->Events & Mask) )
378         {
379                 do {
380                         if( SDL_SemWait( gpCurrentThread->EventSem ) == -1 ) {
381                                 Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
382                                         gpCurrentThread, gpCurrentThread->EventSem);
383                                 break;
384                         }
385                 } while(SDL_SemValue(gpCurrentThread->EventSem));
386                 // NOTE: While loop catches multiple event occurances
387                 Log_Debug("Threads", "Woken from nap (%i here)", SDL_SemValue(gpCurrentThread->EventSem));
388         }
389         rv = gpCurrentThread->Events & Mask;
390         gpCurrentThread->Events &= ~Mask;
391         gpCurrentThread->WaitMask = -1;
392
393         Log_Debug("Threads", "- rv = %x", rv);
394
395         return rv;
396 }
397
398 void Threads_PostEvent(tThread *Thread, Uint32 Events)
399 {
400         Thread->Events |= Events;
401         Log_Debug("Threads", "Trigger event %x (->Events = %p)", Events, Thread->Events);
402         
403         if( Thread->WaitMask & Events ) {
404                 SDL_SemPost( Thread->EventSem );
405 //              Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
406         }
407 }
408
409 void Threads_ClearEvent(Uint32 EventMask)
410 {
411         gpCurrentThread->Events &= ~EventMask;
412 }
413

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