Modules - Use short command annotation in makefile ([CC] not $(CC))
[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 static tProcess *proc(tProcess *Proc) { return Proc ? Proc : gpCurrentThread->Process; }
203 char **Threads_GetCWD   (tProcess *Proc) { return &proc(Proc)->CWD; }
204 char **Threads_GetChroot(tProcess *Proc) { return &proc(Proc)->Chroot; }
205 int *Threads_GetMaxFD   (tProcess *Proc) { return &proc(Proc)->MaxFD; };
206
207 tTID Threads_WaitTID(int TID, int *Status)
208 {
209         // Any Child
210         if(TID == -1) {
211                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
212                 return -1;
213         }
214         
215         // Any peer/child thread
216         if(TID == 0) {
217                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
218                 return -1;
219         }
220         
221         // TGID = abs(TID)
222         if(TID < -1) {
223                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
224                 return -1;
225         }
226         
227         // Specific Thread
228         if(TID > 0)
229         {
230                 tThread *thread = Threads_GetThread(TID);
231                 tThread *us = gpCurrentThread;
232                 if(!thread)     return -1;
233                 
234                 us->Next = NULL;
235                 us->Status = THREAD_STAT_WAITING;
236                 // TODO: Locking
237                 if(thread->WaitingThreadsEnd)
238                 {
239                         thread->WaitingThreadsEnd->Next = us;
240                         thread->WaitingThreadsEnd = us;
241                 }
242                 else
243                 {
244                         thread->WaitingThreads = us;
245                         thread->WaitingThreadsEnd = us;
246                 }
247                 
248                 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
249                 
250                 if(Status)      *Status = thread->RetStatus;
251                 thread->WaitingThreads = thread->WaitingThreads->Next;
252                 us->Next = NULL;
253                 
254                 return TID;
255         }
256         
257         return 0;
258 }
259
260 void Threads_Exit(int TID, int Status)
261 {
262         tThread *toWake;
263         
264 //      VFS_Handles_Cleanup();
265
266         gpCurrentThread->RetStatus = Status;
267         
268         #if 1
269         if( gpCurrentThread->Parent )
270         {
271                 // Wait for the thread to be waited upon
272                 while( gpCurrentThread->WaitingThreads == NULL )
273                         Threads_Glue_Yield();
274         }
275         #endif
276         
277         while( (toWake = gpCurrentThread->WaitingThreads) )
278         {
279                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
280
281                 Threads_Wake(toWake);
282                 
283                 while(gpCurrentThread->WaitingThreads == toWake)
284                         Threads_Glue_Yield();
285         }
286 }
287
288 void Threads_Sleep()
289 {
290         gpCurrentThread->Status = THREAD_STAT_SLEEPING;
291         Threads_int_WaitForStatusEnd(THREAD_STAT_SLEEPING);
292 }
293
294 int Threads_Wake(tThread *Thread)
295 {
296         Thread->Status = THREAD_STAT_ACTIVE;
297         Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
298         return 0;
299 }
300
301 int Threads_WakeTID(tTID TID)
302 {
303         tThread *thread;
304         thread = Threads_GetThread(TID);
305         if( !thread )   return -1;
306         return Threads_Wake(thread);
307 }
308
309 int Threads_CreateRootProcess(void)
310 {
311         tThread *thread = Threads_CloneTCB(&gThreadZero, true);
312         
313         // Handle list is created on first open
314         
315         return thread->Process->PID;
316 }
317
318 int Threads_Fork(void)
319 {
320         tThread *thread = Threads_CloneTCB(gpCurrentThread, true);
321
322         // Duplicate the VFS handles (and nodes) from vfs_handle.c
323         VFS_CloneHandleList(thread->Process->PID);
324         
325         return thread->Process->PID;
326 }
327
328 int Threads_Spawn(int nFD, int FDs[], struct s_sys_spawninfo *info)
329 {
330         tThread *thread = Threads_CloneTCB(gpCurrentThread, true);
331         if( info )
332         {
333                 // TODO: PGID?
334                 //if( info->flags & SPAWNFLAG_NEWPGID )
335                 //      thread->PGID = thread->PID;
336                 if( thread->Process->UID == 0 )
337                 {
338                         if( info->gid )
339                                 thread->Process->GID = info->gid;
340                         if( info->uid )
341                                 thread->Process->UID = info->uid;
342                 }
343         }
344         
345         VFS_CloneHandlesFromList(thread->Process->PID, nFD, FDs);
346
347         return thread->Process->PID;
348 }
349
350 // ----
351 // ----
352 void Threads_int_Terminate(tThread *Thread)
353 {
354         Thread->RetStatus = -1;
355         Threads_AddActive(Thread);
356 }
357
358 void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
359 {
360         tThread *us = Proc_GetCurThread();
361         ASSERT(Status != THREAD_STAT_ACTIVE);
362         ASSERT(Status != THREAD_STAT_DEAD);
363         LOG("%i(%s) - %i", us->TID, us->ThreadName, Status);
364         while( us->Status == Status )
365         {
366                 if( Threads_Glue_SemWait(gpCurrentThread->EventSem, INT_MAX) == -1 ) {
367                         Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
368                                 gpCurrentThread, gpCurrentThread->EventSem);
369                         return ;
370                 }
371                 if( us->Status == Status )
372                         Log_Warning("Threads", "Thread %p(%i %s) rescheduled while in %s state",
373                                 us, us->TID, us->ThreadName, casTHREAD_STAT[Status]);
374         }
375 }
376
377 int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock)
378 {
379         tThread *us = Proc_GetCurThread();
380         us->Next = NULL;
381         // - Mark as sleeping
382         us->Status = Status;
383         us->WaitPointer = Ptr;
384         us->RetStatus = Num;    // Use RetStatus as a temp variable
385                 
386         // - Add to waiting
387         if( ListTail ) {
388                 if(*ListTail) {
389                         (*ListTail)->Next = us;
390                 }
391                 else {
392                         *ListHead = us;
393                 }
394                 *ListTail = us;
395         }
396         else {
397                 *ListHead = us;
398         }
399         
400         if( Lock ) {
401                 SHORTREL( Lock );
402         }
403         Threads_int_WaitForStatusEnd(Status);
404         us->WaitPointer = NULL;
405         return us->RetStatus;
406 }
407
408 void Threads_AddActive(tThread *Thread)
409 {
410         LOG("%i(%s)", Thread->TID, Thread->ThreadName);
411         Thread->Status = THREAD_STAT_ACTIVE;
412         Threads_Glue_SemSignal(Thread->EventSem, 1);
413 }
414
415 // --------------------------------------------------------------------
416 // Signals
417 // --------------------------------------------------------------------
418 void Threads_PostSignal(int SigNum)
419 {
420         Log_Error("Threads", "TODO: %s", __func__);
421 }
422 void Threads_SignalGroup(tPGID PGID, int SignalNum)
423 {
424         Log_Error("Threads", "TODO: %s", __func__);
425 }
426

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