f80447334fcc89e47d5d7332c2d1e3c526600c40
[tpg/acess2.git] / Tools / nativelib / threads.c
1 /*
2  * Acess2 libnative (Kernel Simulation Library)
3  * - By John Hodge (thePowersGang)
4  *
5  * threads.c
6  * - Threads handling
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <threads.h>
11 #include <threads_int.h>
12 #include <mutex.h>
13
14 // === PROTOTYPES ===
15 void    Threads_int_Init(void)  __attribute__((constructor(101)));
16 tThread *Threads_int_CreateTCB(tThread *Parent);
17
18 // === GLOBALS ===
19 tThread *gThreads_List;
20 tThread __thread        *lpThreads_This;
21  int    giThreads_NextTID = 1;
22 tShortSpinlock  glThreadListLock;
23
24 // === CODE ===
25 void Threads_int_Init(void)
26 {
27         if( !lpThreads_This ) {
28                 lpThreads_This = Threads_int_CreateTCB(NULL);
29                 Threads_SetName("ThreadZero");
30         }
31 }
32
33 tThread *Proc_GetCurThread(void)
34 {
35         return lpThreads_This;
36 }
37
38 tUID Threads_GetUID(void) { return 0; }
39 tGID Threads_GetGID(void) { return 0; }
40
41 tTID Threads_GetTID(void) { return lpThreads_This ? lpThreads_This->TID : 0; }
42
43 static inline tProcess* getproc(tProcess *Process) {
44         return (Process ? Process : lpThreads_This->Process);
45 }
46 int *Threads_GetMaxFD(tProcess *Process)        { return &getproc(Process)->MaxFDs;  }
47 char **Threads_GetCWD(tProcess *Process)        { return &getproc(Process)->CWD;     }
48 char **Threads_GetChroot(tProcess *Process)     { return &getproc(Process)->Chroot;  }
49 void **Threads_GetHandlesPtr(void) { return &lpThreads_This->Process->Handles; }
50
51 void Threads_Yield(void)
52 {
53         Log_KernelPanic("Threads", "Threads_Yield DEFINITELY shouldn't be used (%p)",
54                 __builtin_return_address(0));
55 }
56
57 void Threads_Sleep(void)
58 {
59         Log_Warning("Threads", "Threads_Sleep shouldn't be used");
60 }
61
62 int Threads_SetName(const char *Name)
63 {
64         if( !lpThreads_This )
65                 return 0;
66
67         if( lpThreads_This->ThreadName )
68                 free(lpThreads_This->ThreadName);
69         lpThreads_This->ThreadName = strdup(Name);
70
71         return 0;
72 }
73
74 int *Threads_GetErrno(void) __attribute__ ((weak));
75
76 int *Threads_GetErrno(void)
77 {
78         static int a_errno;
79         return &a_errno;
80 }
81
82 tThread *Threads_RemActive(void)
83 {
84         return lpThreads_This;
85 }
86
87 void Threads_AddActive(tThread *Thread)
88 {
89         Thread->Status = THREAD_STAT_ACTIVE;
90         // Increment state-change semaphore
91         LOG("Waking %p(%i %s)", Thread, Thread->TID, Thread->ThreadName);
92         Threads_int_SemSignal(Thread->WaitSemaphore);
93 }
94
95 struct sProcess *Threads_int_CreateProcess(void)
96 {
97         struct sProcess *ret = calloc(sizeof(struct sProcess), 1);
98
99         ret->MaxFDs = 32;
100
101         return ret;
102 }
103
104 tThread *Threads_int_CreateTCB(tThread *Parent)
105 {
106         tThread *ret = calloc( sizeof(tThread), 1 );
107         ret->TID = giThreads_NextTID ++;
108         ret->WaitSemaphore = Threads_int_SemCreate();
109         //ret->Protector = Threads_int_MutexCreate();
110
111         if( !Parent )
112         {
113                 ret->Process = Threads_int_CreateProcess();
114         }
115         else
116                 ret->Process = Parent->Process;
117
118         ret->ProcNext = ret->Process->Threads;
119         ret->Process->Threads = ret;
120
121         ret->Next = gThreads_List;
122         gThreads_List = ret;
123         
124         return ret;
125 }
126
127 struct sThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
128 {
129         if( !Threads_int_ThreadingEnabled() )
130         {
131                 Log_Error("Threads", "Multithreading is disabled in this build");
132                 return NULL;
133         }
134         else
135         {
136                 tThread *ret = Threads_int_CreateTCB(lpThreads_This);
137                 ret->SpawnFcn = Fcn;
138                 ret->SpawnData = Data;
139                 Threads_int_CreateThread(ret);
140                 return ret;
141         }
142 }
143
144 void Threads_int_WaitForStatusEnd(enum eThreadStatus Status)
145 {
146         tThread *us = Proc_GetCurThread();
147         assert(Status != THREAD_STAT_ACTIVE);
148         assert(Status != THREAD_STAT_DEAD);
149         LOG("%i(%s) - %i", us->TID, us->ThreadName, Status);
150         while( us->Status == Status )
151         {
152                 Threads_int_SemWaitAll(us->WaitSemaphore);
153                 if( us->Status == Status )
154                         Log_Warning("Threads", "Thread %p(%i %s) rescheduled while in %s state",
155                                 us, us->TID, us->ThreadName, casTHREAD_STAT[Status]);
156         }
157         LOG("%p(%i %s) Awake", us, us->TID, us->ThreadName);
158 }
159
160 int Threads_int_Sleep(enum eThreadStatus Status, void *Ptr, int Num, tThread **ListHead, tThread **ListTail, tShortSpinlock *Lock)
161 {
162         tThread *us = Proc_GetCurThread();
163         us->Next = NULL;
164         // - Mark as sleeping
165         us->Status = Status;
166         us->WaitPointer = Ptr;
167         us->RetStatus = Num;    // Use RetStatus as a temp variable
168                 
169         // - Add to waiting
170         if( ListTail ) {
171                 if(*ListTail) {
172                         (*ListTail)->Next = us;
173                 }
174                 else {
175                         *ListHead = us;
176                 }
177                 *ListTail = us;
178         }
179         else if(ListHead) {
180                 us->Next = *ListHead;
181                 *ListHead = us;
182         }
183         else {
184                 // nothing
185         }
186         
187         if( Lock ) {
188                 SHORTREL( Lock );
189         }
190         Threads_int_WaitForStatusEnd(Status);
191         us->WaitPointer = NULL;
192         return us->RetStatus;
193 }
194

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