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

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