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

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