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

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