AcessNative - Rework of thread handling
[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 DEBUG   1
9 #include <arch.h>
10 #include <acess.h>
11 #include <mutex.h>
12 #include "../../KernelLand/Kernel/include/semaphore.h"
13 typedef signed long long int    time_t;
14 #include "../../Usermode/Libraries/ld-acess.so_src/include_exp/acess/syscall_types.h"
15 #include <rwlock.h>
16 #include <events.h>
17 #include <threads_int.h>
18 #include <limits.h>
19 #include "include/threads_glue.h"
20 #include <stdbool.h>
21
22 #define THREAD_EVENT_WAKEUP     0x80000000
23
24 // === IMPORTS ===
25 extern void     VFS_CloneHandleList(int PID);
26 extern void     VFS_CloneHandlesFromList(int PID, int nFD, int FDs[]);
27 extern void     VFS_ClearHandles(int PID);
28
29 // === STRUCTURES ===
30 // === PROTOTYPES ===
31  int    Threads_Wake(tThread *Thread);
32
33 // === GLOBALS ===
34 tProcess gProcessZero = {
35         .NativePID = 0,
36         .CWD = "/",
37         .Chroot = "/",
38         .MaxFD = 100
39 };
40 tThread gThreadZero = {
41         .Status=THREAD_STAT_ACTIVE,
42         .ThreadName="ThreadZero",
43         .Process = &gProcessZero
44 };
45 tThread *gpThreads = &gThreadZero;
46 __thread tThread        *gpCurrentThread = &gThreadZero;
47  int    giThreads_NextThreadID = 1;
48
49 // === CODE ===
50 tThread *Proc_GetCurThread(void)
51 {
52         return gpCurrentThread;
53 }
54
55 void Threads_Dump(void)
56 {
57         for( tThread *thread = gpThreads; thread; thread = thread->GlobalNext )
58         {
59                 Log_Log("Threads", "TID %i (%s), PID %i",
60                         thread->TID, thread->ThreadName, thread->Process->PID);
61                 Log_Log("Threads", "User: %i, Group: %i",
62                         thread->Process->UID, thread->Process->GID);
63                 Log_Log("Threads", "Kernel Thread ID: %i",
64                         thread->KernelTID);
65         }
66 }
67
68 void Threads_SetThread(int TID, void *Client)
69 {
70         for( tThread *thread = gpThreads; thread; thread = thread->GlobalNext )
71         {
72                 if( thread->TID == TID ) {
73                         gpCurrentThread = thread;
74                         thread->ClientPtr = Client;
75                         return ;
76                 }
77         }
78         Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
79 }
80
81 tThread *Threads_GetThread(Uint TID)
82 {
83         for( tThread *thread = gpThreads; thread; thread = thread->GlobalNext )
84         {
85                 if( thread->TID == TID ) {
86                         return thread;
87                 }
88         }
89         return NULL;
90 }
91
92 /**
93  * \brief Clone a thread control block (with a different TID)
94  */
95 tThread *Threads_CloneTCB(tThread *TemplateThread, bool bNewProcess)
96 {
97         tThread *ret = malloc(sizeof(tThread));
98         memcpy(ret, TemplateThread, sizeof(tThread));
99         
100         ret->TID = giThreads_NextThreadID ++;
101         
102         ret->ThreadName = strdup(TemplateThread->ThreadName);
103         Threads_Glue_SemInit( &ret->EventSem, 0 );
104         
105         ret->WaitingThreads = NULL;
106         ret->WaitingThreadsEnd = NULL;
107
108         if( bNewProcess )
109         {
110                 tProcess *proc = malloc( sizeof(tProcess) );
111                 memcpy(proc, ret->Process, sizeof(tProcess));
112                 proc->nThreads = 0;
113                 proc->CWD = strdup(proc->CWD);
114                 proc->Chroot = strdup(proc->Chroot);
115                 
116                 proc->PID = ret->TID;
117                 
118                 ret->Process = proc;
119         }       
120
121         ret->Process->nThreads ++;
122
123         // Add to the end of the queue
124         // TODO: Handle concurrency issues
125         ret->GlobalNext = gpThreads;
126         gpThreads = ret;
127         
128         return ret;
129 }
130
131 void Threads_int_Destroy(tThread *Thread)
132 {
133         // Clear WaitingThreads
134         
135         Threads_Glue_SemDestroy(Thread->EventSem);
136         free(Thread->ThreadName);
137         Thread->Process->nThreads --;
138 }
139
140 void Threads_Terminate(void)
141 {
142         tThread *us = gpCurrentThread;
143         tProcess *proc = us->Process;
144
145         if( us->TID == proc->PID )
146         {
147                 // If we're the process leader, then tear down the entire process
148                 VFS_ClearHandles(proc->PID);
149                 tThread **next_ptr = &gpThreads;
150                 for( tThread *thread = gpThreads; thread; thread = *next_ptr )
151                 {
152                         if( thread->Process == proc ) {
153                                 Threads_int_Destroy(thread);
154                         }
155                         else {
156                                 next_ptr = &thread->Next;
157                         }
158                 }
159         }
160         else
161         {
162                 // Just a lowly thread, remove from process
163                 Threads_int_Destroy(us);
164         }
165         
166         if( proc->nThreads == 0 )
167         {
168                 free(proc->Chroot);
169                 free(proc->CWD);
170                 free(proc);
171         }
172 }
173
174 tUID Threads_GetUID() { return gpCurrentThread->Process->UID; }
175 tGID Threads_GetGID() { return gpCurrentThread->Process->GID; }
176 tTID Threads_GetTID() { return gpCurrentThread->TID; }
177 tPID Threads_GetPID() { return gpCurrentThread->Process->PID; }
178
179 int Threads_SetUID(tUID NewUID)
180 {
181         if(Threads_GetUID() != 0) {
182                 errno = EACCES;
183                 return -1;
184         }
185         
186         gpCurrentThread->Process->UID = NewUID;
187         return 0;
188 }
189
190 int Threads_SetGID(tGID NewGID)
191 {
192         if(Threads_GetUID() != 0) {
193                 errno = -EACCES;
194                 return -1;
195         }
196         
197         gpCurrentThread->Process->GID = NewGID;
198         return 0;
199 }
200
201 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
202 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
203 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
204 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
205
206 tTID Threads_WaitTID(int TID, int *Status)
207 {
208         // Any Child
209         if(TID == -1) {
210                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
211                 return -1;
212         }
213         
214         // Any peer/child thread
215         if(TID == 0) {
216                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
217                 return -1;
218         }
219         
220         // TGID = abs(TID)
221         if(TID < -1) {
222                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
223                 return -1;
224         }
225         
226         // Specific Thread
227         if(TID > 0)
228         {
229                 tThread *thread = Threads_GetThread(TID);
230                 tThread *us = gpCurrentThread;
231                 if(!thread)     return -1;
232                 
233                 us->Next = NULL;
234                 us->Status = THREAD_STAT_WAITING;
235                 // TODO: Locking
236                 if(thread->WaitingThreadsEnd)
237                 {
238                         thread->WaitingThreadsEnd->Next = us;
239                         thread->WaitingThreadsEnd = us;
240                 }
241                 else
242                 {
243                         thread->WaitingThreads = us;
244                         thread->WaitingThreadsEnd = us;
245                 }
246                 
247                 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
248                 
249                 if(Status)      *Status = thread->RetStatus;
250                 thread->WaitingThreads = thread->WaitingThreads->Next;
251                 us->Next = NULL;
252                 
253                 return TID;
254         }
255         
256         return 0;
257 }
258
259 void Threads_Exit(int TID, int Status)
260 {
261         tThread *toWake;
262         
263 //      VFS_Handles_Cleanup();
264
265         gpCurrentThread->RetStatus = Status;
266         
267         #if 1
268         if( gpCurrentThread->Parent )
269         {
270                 // Wait for the thread to be waited upon
271                 while( gpCurrentThread->WaitingThreads == NULL )
272                         Threads_Glue_Yield();
273         }
274         #endif
275         
276         while( (toWake = gpCurrentThread->WaitingThreads) )
277         {
278                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
279
280                 Threads_Wake(toWake);
281                 
282                 while(gpCurrentThread->WaitingThreads == toWake)
283                         Threads_Glue_Yield();
284         }
285 }
286
287 void Threads_Sleep()
288 {
289         gpCurrentThread->Status = THREAD_STAT_SLEEPING;
290         Threads_int_WaitForStatusEnd(THREAD_STAT_SLEEPING);
291 }
292
293 int Threads_Wake(tThread *Thread)
294 {
295         Thread->Status = THREAD_STAT_ACTIVE;
296         Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
297         return 0;
298 }
299
300 int Threads_WakeTID(tTID TID)
301 {
302         tThread *thread;
303         thread = Threads_GetThread(TID);
304         if( !thread )   return -1;
305         return Threads_Wake(thread);
306 }
307
308 int Threads_CreateRootProcess(void)
309 {
310         tThread *thread = Threads_CloneTCB(&gThreadZero, true);
311         
312         // Handle list is created on first open
313         
314         return thread->Process->PID;
315 }
316
317 int Threads_Fork(void)
318 {
319         tThread *thread = Threads_CloneTCB(gpCurrentThread, true);
320
321         // Duplicate the VFS handles (and nodes) from vfs_handle.c
322         VFS_CloneHandleList(thread->Process->PID);
323         
324         return thread->Process->PID;
325 }
326
327 int Threads_Spawn(int nFD, int FDs[], struct s_sys_spawninfo *info)
328 {
329         tThread *thread = Threads_CloneTCB(gpCurrentThread, true);
330         if( info )
331         {
332                 // TODO: PGID?
333                 //if( info->flags & SPAWNFLAG_NEWPGID )
334                 //      thread->PGID = thread->PID;
335                 if( thread->Process->UID == 0 )
336                 {
337                         if( info->gid )
338                                 thread->Process->GID = info->gid;
339                         if( info->uid )
340                                 thread->Process->UID = info->uid;
341                 }
342         }
343         
344         VFS_CloneHandlesFromList(thread->Process->PID, nFD, FDs);
345
346         return thread->Process->PID;
347 }
348
349 // ----
350 // ----
351 void Threads_int_Terminate(tThread *Thread)
352 {
353         Thread->RetStatus = -1;
354         Threads_AddActive(Thread);
355 }
356
357 void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
358 {
359         tThread *us = Proc_GetCurThread();
360         ASSERT(Status != THREAD_STAT_ACTIVE);
361         ASSERT(Status != THREAD_STAT_DEAD);
362         LOG("%i(%s) - %i", us->TID, us->ThreadName, Status);
363         while( us->Status == Status )
364         {
365                 if( Threads_Glue_SemWait(gpCurrentThread->EventSem, INT_MAX) == -1 ) {
366                         Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
367                                 gpCurrentThread, gpCurrentThread->EventSem);
368                         return ;
369                 }
370                 if( us->Status == Status )
371                         Log_Warning("Threads", "Thread %p(%i %s) rescheduled while in %s state",
372                                 us, us->TID, us->ThreadName, casTHREAD_STAT[Status]);
373         }
374 }
375
376 int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock)
377 {
378         tThread *us = Proc_GetCurThread();
379         us->Next = NULL;
380         // - Mark as sleeping
381         us->Status = Status;
382         us->WaitPointer = Ptr;
383         us->RetStatus = Num;    // Use RetStatus as a temp variable
384                 
385         // - Add to waiting
386         if( ListTail ) {
387                 if(*ListTail) {
388                         (*ListTail)->Next = us;
389                 }
390                 else {
391                         *ListHead = us;
392                 }
393                 *ListTail = us;
394         }
395         else {
396                 *ListHead = us;
397         }
398         
399         if( Lock ) {
400                 SHORTREL( Lock );
401         }
402         Threads_int_WaitForStatusEnd(Status);
403         us->WaitPointer = NULL;
404         return us->RetStatus;
405 }
406
407 void Threads_AddActive(tThread *Thread)
408 {
409         LOG("%i(%s)", Thread->TID, Thread->ThreadName);
410         Thread->Status = THREAD_STAT_ACTIVE;
411         Threads_Glue_SemSignal(Thread->EventSem, 1);
412 }
413
414 // --------------------------------------------------------------------
415 // Signals
416 // --------------------------------------------------------------------
417 void Threads_PostSignal(int SigNum)
418 {
419         Log_Error("Threads", "TODO: %s", __func__);
420 }
421 void Threads_SignalGroup(tPGID PGID, int SignalNum)
422 {
423         Log_Error("Threads", "TODO: %s", __func__);
424 }
425

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