All - Changes for AcessNative on windows
[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
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
21 #define THREAD_EVENT_WAKEUP     0x80000000
22
23 // === IMPORTS ===
24 extern void     VFS_CloneHandleList(int PID);
25 extern void     VFS_CloneHandlesFromList(int PID, int nFD, int FDs[]);
26
27 // === STRUCTURES ===
28 // === PROTOTYPES ===
29  int    Threads_Wake(tThread *Thread);
30
31 // === GLOBALS ===
32 tProcess gProcessZero = {
33         .NativePID = 0,
34         .CWD = "/",
35         .Chroot = "/",
36         .MaxFD = 100
37 };
38 tThread gThreadZero = {
39         .Status=THREAD_STAT_ACTIVE,
40         .ThreadName="ThreadZero",
41         .Process = &gProcessZero
42 };
43 tThread *gpThreads = &gThreadZero;
44 __thread tThread        *gpCurrentThread = &gThreadZero;
45  int    giThreads_NextThreadID = 1;
46
47 // === CODE ===
48 tThread *Proc_GetCurThread(void)
49 {
50         return gpCurrentThread;
51 }
52
53 void Threads_Dump(void)
54 {
55         tThread *thread;
56         for( thread = gpThreads; thread; thread = thread->GlobalNext )
57         {
58                 Log_Log("Threads", "TID %i (%s), PID %i",
59                         thread->TID, thread->ThreadName, thread->PID);
60                 Log_Log("Threads", "User: %i, Group: %i",
61                         thread->UID, thread->GID);
62                 Log_Log("Threads", "Kernel Thread ID: %i",
63                         thread->KernelTID);
64         }
65 }
66
67 void Threads_SetThread(int TID)
68 {
69         tThread *thread;
70         for( thread = gpThreads; thread; thread = thread->GlobalNext )
71         {
72                 if( thread->TID == TID ) {
73                         gpCurrentThread = thread;
74                         return ;
75                 }
76         }
77         Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
78 }
79
80 tThread *Threads_GetThread(Uint TID)
81 {
82         tThread *thread;
83         for( 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)
96 {
97         tThread *ret = malloc(sizeof(tThread));
98         
99         memcpy(ret, TemplateThread, sizeof(tThread));
100         
101         ret->TID = giThreads_NextThreadID ++;
102         
103         ret->ThreadName = strdup(TemplateThread->ThreadName);
104         Threads_Glue_SemInit( &ret->EventSem, 0 );
105         
106         ret->WaitingThreads = NULL;
107         ret->WaitingThreadsEnd = NULL;
108         
109         // Add to the end of the queue
110         // TODO: Handle concurrency issues
111         ret->GlobalNext = gpThreads;
112         gpThreads = ret;
113         
114         return ret;
115 }
116
117 tUID Threads_GetUID() { return gpCurrentThread->UID; }
118 tGID Threads_GetGID() { return gpCurrentThread->GID; }
119 tTID Threads_GetTID() { return gpCurrentThread->TID; }
120 tPID Threads_GetPID() { return gpCurrentThread->PID; }
121
122 int Threads_SetUID(tUID NewUID)
123 {
124         if(Threads_GetUID() != 0) {
125                 errno = EACCES;
126                 return -1;
127         }
128         
129         gpCurrentThread->UID = NewUID;
130         return 0;
131 }
132
133 int Threads_SetGID(tGID NewGID)
134 {
135         if(Threads_GetUID() != 0) {
136                 errno = -EACCES;
137                 return -1;
138         }
139         
140         gpCurrentThread->GID = NewGID;
141         return 0;
142 }
143
144 int *Threads_GetErrno(void) { return &gpCurrentThread->_errno; }
145 char **Threads_GetCWD(void) { return &gpCurrentThread->Process->CWD; }
146 char **Threads_GetChroot(void) { return &gpCurrentThread->Process->Chroot; }
147 int *Threads_GetMaxFD(void) { return &gpCurrentThread->Process->MaxFD; };
148
149 tTID Threads_WaitTID(int TID, int *Status)
150 {
151         // Any Child
152         if(TID == -1) {
153                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=-1) - Any Child");
154                 return -1;
155         }
156         
157         // Any peer/child thread
158         if(TID == 0) {
159                 Log_Error("Threads", "TODO: Threads_WaitTID(TID=0) - Any Child/Sibling");
160                 return -1;
161         }
162         
163         // TGID = abs(TID)
164         if(TID < -1) {
165                 Log_Error("Threads", "TODO: Threads_WaitTID(TID<0) - TGID");
166                 return -1;
167         }
168         
169         // Specific Thread
170         if(TID > 0) {
171                 
172                 tThread *thread = Threads_GetThread(TID);
173                 tThread *us = gpCurrentThread;
174                 if(!thread)     return -1;
175                 
176                 us->Next = NULL;
177                 us->Status = THREAD_STAT_WAITING;
178                 // TODO: Locking
179                 if(thread->WaitingThreadsEnd)
180                 {
181                         thread->WaitingThreadsEnd->Next = us;
182                         thread->WaitingThreadsEnd = us;
183                 }
184                 else
185                 {
186                         thread->WaitingThreads = us;
187                         thread->WaitingThreadsEnd = us;
188                 }
189                 
190                 Threads_WaitEvents( THREAD_EVENT_WAKEUP );
191                 
192                 if(Status)      *Status = thread->ExitStatus;
193                 thread->WaitingThreads = thread->WaitingThreads->Next;
194                 us->Next = NULL;
195                 
196                 return TID;
197         }
198         
199         return 0;
200 }
201
202 void Threads_Sleep(void)
203 {
204         // TODO: Add to a sleeping queue
205         //pause();
206 }
207
208 void Threads_Yield(void)
209 {
210 //      yield();
211 }
212
213 void Threads_Exit(int TID, int Status)
214 {
215         tThread *toWake;
216         
217 //      VFS_Handles_Cleanup();
218
219         gpCurrentThread->ExitStatus = Status;
220         
221         #if 1
222         if( gpCurrentThread->Parent )
223         {
224                 // Wait for the thread to be waited upon
225                 while( gpCurrentThread->WaitingThreads == NULL )
226                         Threads_Glue_Yield();
227         }
228         #endif
229         
230         while( (toWake = gpCurrentThread->WaitingThreads) )
231         {
232                 Log_Debug("Threads", "Threads_Exit - Waking %p %i '%s'", toWake, toWake->TID, toWake->ThreadName);
233
234                 Threads_Wake(toWake);
235                 
236                 while(gpCurrentThread->WaitingThreads == toWake)
237                         Threads_Glue_Yield();
238         }
239 }
240
241 int Threads_Wake(tThread *Thread)
242 {
243         Thread->Status = THREAD_STAT_ACTIVE;
244         Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
245         return 0;
246 }
247
248 int Threads_WakeTID(tTID TID)
249 {
250         tThread *thread;
251         thread = Threads_GetThread(TID);
252         if( !thread )   return -1;
253         return Threads_Wake(thread);
254 }
255
256 int Threads_CreateRootProcess(void)
257 {
258         tThread *thread = Threads_CloneTCB(&gThreadZero);
259         thread->PID = thread->TID;
260         
261         // Handle list is created on first open
262         
263         return thread->PID;
264 }
265
266 int Threads_Fork(void)
267 {
268         tThread *thread = Threads_CloneTCB(gpCurrentThread);
269         thread->PID = thread->TID;
270
271         // Duplicate the VFS handles (and nodes) from vfs_handle.c
272         VFS_CloneHandleList(thread->PID);
273         
274         return thread->PID;
275 }
276
277 int Threads_Spawn(int nFD, int FDs[], struct s_sys_spawninfo *info)
278 {
279         tThread *thread = Threads_CloneTCB(gpCurrentThread);
280         thread->PID = thread->TID;
281         if( info )
282         {
283                 // TODO: PGID?
284                 //if( info->flags & SPAWNFLAG_NEWPGID )
285                 //      thread->PGID = thread->PID;
286                 if( info->gid && thread->UID == 0 )
287                         thread->GID = info->gid;
288                 if( info->uid && thread->UID == 0 )     // last because ->UID is used above
289                         thread->UID = info->uid;
290         }
291         
292         VFS_CloneHandlesFromList(thread->PID, nFD, FDs);
293
294         Log_Debug("Threads", "_spawn: %i", thread->PID);
295         return thread->PID;
296 }
297
298 // --------------------------------------------------------------------
299 // Mutexes 
300 // --------------------------------------------------------------------
301 int Mutex_Acquire(tMutex *Mutex)
302 {
303         Threads_Glue_AcquireMutex(&Mutex->Protector.Mutex);
304         return 0;
305 }
306
307 void Mutex_Release(tMutex *Mutex)
308 {
309         Threads_Glue_ReleaseMutex(&Mutex->Protector.Mutex);
310 }
311
312 // --------------------------------------------------------------------
313 // Semaphores
314 // --------------------------------------------------------------------
315 void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
316 {
317         memset(Sem, 0, sizeof(tSemaphore));
318         // HACK: Use `Sem->Protector` as space for the semaphore pointer
319         Threads_Glue_SemInit( &Sem->Protector.Mutex, InitValue );
320 }
321
322 int Semaphore_Wait(tSemaphore *Sem, int MaxToTake)
323 {
324         return Threads_Glue_SemWait( Sem->Protector.Mutex, MaxToTake );
325 }
326
327 int Semaphore_Signal(tSemaphore *Sem, int AmmountToAdd)
328 {
329         return Threads_Glue_SemSignal( Sem->Protector.Mutex, AmmountToAdd );
330 }
331
332 // --------------------------------------------------------------------
333 // Event handling
334 // --------------------------------------------------------------------
335 Uint32 Threads_WaitEvents(Uint32 Mask)
336 {
337         Uint32  rv;
338
339         //Log_Debug("Threads", "Mask = %x, ->Events = %x", Mask, gpCurrentThread->Events);      
340
341         gpCurrentThread->WaitMask = Mask;
342         if( !(gpCurrentThread->EventState & Mask) )
343         {
344                 if( Threads_Glue_SemWait(gpCurrentThread->EventSem, INT_MAX) == -1 ) {
345                         Log_Warning("Threads", "Wait on eventsem of %p, %p failed",
346                                 gpCurrentThread, gpCurrentThread->EventSem);
347                 }
348                 //Log_Debug("Threads", "Woken from nap (%i here)", SDL_SemValue(gpCurrentThread->EventSem));
349         }
350         rv = gpCurrentThread->EventState & Mask;
351         gpCurrentThread->EventState &= ~Mask;
352         gpCurrentThread->WaitMask = -1;
353
354         //Log_Debug("Threads", "- rv = %x", rv);
355
356         return rv;
357 }
358
359 void Threads_PostEvent(tThread *Thread, Uint32 Events)
360 {
361         Thread->EventState |= Events;
362 //      Log_Debug("Threads", "Trigger event %x (->Events = %p) on %p", Events, Thread->Events, Thread);
363
364         if( Events == 0 || Thread->WaitMask & Events ) {
365                 Threads_Glue_SemSignal( Thread->EventSem, 1 );
366 //              Log_Debug("Threads", "Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
367         }
368 }
369
370 void Threads_ClearEvent(Uint32 EventMask)
371 {
372         gpCurrentThread->EventState &= ~EventMask;
373 }
374

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