Fix libogc hardware lighting (GX_SetChanCtrl) - patch from https://sourceforge.net...
[libogc.git] / libogc / lwp.c
blobcaaa1c5fb971bdc1de5cf2a67fd7d2d52251b644
1 /*-------------------------------------------------------------
3 lwp.c -- Thread subsystem I
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
28 -------------------------------------------------------------*/
31 #include <stdlib.h>
32 #include <errno.h>
33 #include "asm.h"
34 #include "processor.h"
35 #include "lwp_threadq.h"
36 #include "lwp_threads.h"
37 #include "lwp_wkspace.h"
38 #include "lwp_objmgr.h"
39 #include "lwp_config.h"
40 #include "lwp.h"
42 #define LWP_OBJTYPE_THREAD 1
43 #define LWP_OBJTYPE_TQUEUE 2
45 #define LWP_CHECK_THREAD(hndl) \
46 { \
47 if(((hndl)==LWP_THREAD_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_THREAD)) \
48 return NULL; \
51 #define LWP_CHECK_TQUEUE(hndl) \
52 { \
53 if(((hndl)==LWP_TQUEUE_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_TQUEUE)) \
54 return NULL; \
57 typedef struct _tqueue_st {
58 lwp_obj object;
59 lwp_thrqueue tqueue;
60 } tqueue_st;
62 lwp_objinfo _lwp_thr_objects;
63 lwp_objinfo _lwp_tqueue_objects;
65 extern int __crtmain();
67 extern u8 __stack_addr[],__stack_end[];
69 static __inline__ u32 __lwp_priotocore(u32 prio)
71 return (255 - prio);
74 static __inline__ lwp_cntrl* __lwp_cntrl_open(lwp_t thr_id)
76 LWP_CHECK_THREAD(thr_id);
77 return (lwp_cntrl*)__lwp_objmgr_get(&_lwp_thr_objects,LWP_OBJMASKID(thr_id));
80 static __inline__ tqueue_st* __lwp_tqueue_open(lwpq_t tqueue)
82 LWP_CHECK_TQUEUE(tqueue);
83 return (tqueue_st*)__lwp_objmgr_get(&_lwp_tqueue_objects,LWP_OBJMASKID(tqueue));
86 static lwp_cntrl* __lwp_cntrl_allocate()
88 lwp_cntrl *thethread;
90 __lwp_thread_dispatchdisable();
91 thethread = (lwp_cntrl*)__lwp_objmgr_allocate(&_lwp_thr_objects);
92 if(thethread) {
93 __lwp_objmgr_open(&_lwp_thr_objects,&thethread->object);
94 return thethread;
96 __lwp_thread_dispatchenable();
97 return NULL;
100 static tqueue_st* __lwp_tqueue_allocate()
102 tqueue_st *tqueue;
104 __lwp_thread_dispatchdisable();
105 tqueue = (tqueue_st*)__lwp_objmgr_allocate(&_lwp_tqueue_objects);
106 if(tqueue) {
107 __lwp_objmgr_open(&_lwp_tqueue_objects,&tqueue->object);
108 return tqueue;
110 __lwp_thread_dispatchenable();
111 return NULL;
114 static __inline__ void __lwp_cntrl_free(lwp_cntrl *thethread)
116 __lwp_objmgr_close(&_lwp_thr_objects,&thethread->object);
117 __lwp_objmgr_free(&_lwp_thr_objects,&thethread->object);
120 static __inline__ void __lwp_tqueue_free(tqueue_st *tq)
122 __lwp_objmgr_close(&_lwp_tqueue_objects,&tq->object);
123 __lwp_objmgr_free(&_lwp_tqueue_objects,&tq->object);
126 static void* idle_func(void *arg)
128 while(1);
129 return 0;
132 void __lwp_sysinit()
134 __lwp_objmgr_initinfo(&_lwp_thr_objects,LWP_MAX_THREADS,sizeof(lwp_cntrl));
135 __lwp_objmgr_initinfo(&_lwp_tqueue_objects,LWP_MAX_TQUEUES,sizeof(tqueue_st));
137 // create idle thread, is needed iff all threads are locked on a queue
138 _thr_idle = (lwp_cntrl*)__lwp_objmgr_allocate(&_lwp_thr_objects);
139 __lwp_thread_init(_thr_idle,NULL,0,255,0,TRUE);
140 _thr_executing = _thr_heir = _thr_idle;
141 __lwp_thread_start(_thr_idle,idle_func,NULL);
142 __lwp_objmgr_open(&_lwp_thr_objects,&_thr_idle->object);
144 // create main thread, as this is our entry point
145 // for every GC application.
146 _thr_main = (lwp_cntrl*)__lwp_objmgr_allocate(&_lwp_thr_objects);
147 __lwp_thread_init(_thr_main,__stack_end,((u32)__stack_addr-(u32)__stack_end),191,0,TRUE);
148 __lwp_thread_start(_thr_main,(void*)__crtmain,NULL);
149 __lwp_objmgr_open(&_lwp_thr_objects,&_thr_main->object);
152 BOOL __lwp_thread_isalive(lwp_t thr_id)
154 if(thr_id==LWP_THREAD_NULL || LWP_OBJTYPE(thr_id)!=LWP_OBJTYPE_THREAD) return FALSE;
156 lwp_cntrl *thethread = (lwp_cntrl*)__lwp_objmgr_getnoprotection(&_lwp_thr_objects,LWP_OBJMASKID(thr_id));
158 if(thethread) {
159 u32 *stackbase = thethread->stack;
160 if(stackbase[0]==0xDEADBABE && !__lwp_statedormant(thethread->cur_state) && !__lwp_statetransient(thethread->cur_state))
161 return TRUE;
164 return FALSE;
167 lwp_t __lwp_thread_currentid()
169 return _thr_executing->object.id;
172 BOOL __lwp_thread_exists(lwp_t thr_id)
174 if(thr_id==LWP_THREAD_NULL || LWP_OBJTYPE(thr_id)!=LWP_OBJTYPE_THREAD) return FALSE;
175 return (__lwp_objmgr_getnoprotection(&_lwp_thr_objects,LWP_OBJMASKID(thr_id))!=NULL);
178 frame_context* __lwp_thread_context(lwp_t thr_id)
180 lwp_cntrl *thethread;
181 frame_context *pctx = NULL;
183 LWP_CHECK_THREAD(thr_id);
184 thethread = (lwp_cntrl*)__lwp_objmgr_getnoprotection(&_lwp_thr_objects,LWP_OBJMASKID(thr_id));
185 if(thethread) pctx = &thethread->context;
187 return pctx;
190 s32 LWP_CreateThread(lwp_t *thethread,void* (*entry)(void *),void *arg,void *stackbase,u32 stack_size,u8 prio)
192 u32 status;
193 lwp_cntrl *lwp_thread;
195 if(!thethread || !entry) return -1;
197 lwp_thread = __lwp_cntrl_allocate();
198 if(!lwp_thread) return -1;
200 status = __lwp_thread_init(lwp_thread,stackbase,stack_size,__lwp_priotocore(prio),0,TRUE);
201 if(!status) {
202 __lwp_cntrl_free(lwp_thread);
203 __lwp_thread_dispatchenable();
204 return -1;
207 status = __lwp_thread_start(lwp_thread,entry,arg);
208 if(!status) {
209 __lwp_cntrl_free(lwp_thread);
210 __lwp_thread_dispatchenable();
211 return -1;
214 *thethread = (lwp_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_THREAD)|LWP_OBJMASKID(lwp_thread->object.id));
215 __lwp_thread_dispatchenable();
217 return 0;
220 s32 LWP_SuspendThread(lwp_t thethread)
222 lwp_cntrl *lwp_thread;
224 lwp_thread = __lwp_cntrl_open(thethread);
225 if(!lwp_thread) return -1;
227 if(!__lwp_statesuspended(lwp_thread->cur_state)) {
228 __lwp_thread_suspend(lwp_thread);
229 __lwp_thread_dispatchenable();
230 return LWP_SUCCESSFUL;
232 __lwp_thread_dispatchenable();
233 return LWP_ALREADY_SUSPENDED;
236 s32 LWP_ResumeThread(lwp_t thethread)
238 lwp_cntrl *lwp_thread;
240 lwp_thread = __lwp_cntrl_open(thethread);
241 if(!lwp_thread) return -1;
243 if(__lwp_statesuspended(lwp_thread->cur_state)) {
244 __lwp_thread_resume(lwp_thread,TRUE);
245 __lwp_thread_dispatchenable();
246 return LWP_SUCCESSFUL;
248 __lwp_thread_dispatchenable();
249 return LWP_NOT_SUSPENDED;
252 lwp_t LWP_GetSelf()
254 lwp_t ret;
256 __lwp_thread_dispatchdisable();
257 ret = (lwp_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_THREAD)|LWP_OBJMASKID(_thr_executing->object.id));
258 __lwp_thread_dispatchunnest();
260 return ret;
263 void LWP_SetThreadPriority(lwp_t thethread,u32 prio)
265 lwp_cntrl *lwp_thread;
267 if(thethread==LWP_THREAD_NULL) thethread = LWP_GetSelf();
269 lwp_thread = __lwp_cntrl_open(thethread);
270 if(!lwp_thread) return;
272 __lwp_thread_changepriority(lwp_thread,__lwp_priotocore(prio),TRUE);
273 __lwp_thread_dispatchenable();
276 void LWP_YieldThread()
278 __lwp_thread_dispatchdisable();
279 __lwp_thread_yield();
280 __lwp_thread_dispatchenable();
283 void LWP_Reschedule(u32 prio)
285 __lwp_thread_dispatchdisable();
286 __lwp_rotate_readyqueue(prio);
287 __lwp_thread_dispatchenable();
290 BOOL LWP_ThreadIsSuspended(lwp_t thethread)
292 BOOL state;
293 lwp_cntrl *lwp_thread;
295 lwp_thread = __lwp_cntrl_open(thethread);
296 if(!lwp_thread) return FALSE;
298 state = (__lwp_statesuspended(lwp_thread->cur_state) ? TRUE : FALSE);
300 __lwp_thread_dispatchenable();
301 return state;
305 s32 LWP_JoinThread(lwp_t thethread,void **value_ptr)
307 u32 level;
308 void *return_ptr;
309 lwp_cntrl *exec,*lwp_thread;
311 lwp_thread = __lwp_cntrl_open(thethread);
312 if(!lwp_thread) return 0;
314 if(__lwp_thread_isexec(lwp_thread)) {
315 __lwp_thread_dispatchenable();
316 return EDEADLK; //EDEADLK
319 exec = _thr_executing;
320 _CPU_ISR_Disable(level);
321 __lwp_threadqueue_csenter(&lwp_thread->join_list);
322 exec->wait.ret_code = 0;
323 exec->wait.ret_arg_1 = NULL;
324 exec->wait.ret_arg = (void*)&return_ptr;
325 exec->wait.queue = &lwp_thread->join_list;
326 exec->wait.id = thethread;
327 _CPU_ISR_Restore(level);
328 __lwp_threadqueue_enqueue(&lwp_thread->join_list,LWP_WD_NOTIMEOUT);
329 __lwp_thread_dispatchenable();
331 if(value_ptr) *value_ptr = return_ptr;
332 return 0;
335 s32 LWP_InitQueue(lwpq_t *thequeue)
337 tqueue_st *tq;
339 if(!thequeue) return -1;
341 tq = __lwp_tqueue_allocate();
342 if(!tq) return -1;
344 __lwp_threadqueue_init(&tq->tqueue,LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_ON_THREADQ,0);
346 *thequeue = (lwpq_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_TQUEUE)|LWP_OBJMASKID(tq->object.id));
347 __lwp_thread_dispatchenable();
349 return 0;
352 void LWP_CloseQueue(lwpq_t thequeue)
354 lwp_cntrl *thethread;
355 tqueue_st *tq = (tqueue_st*)thequeue;
357 tq = __lwp_tqueue_open(thequeue);
358 if(!tq) return;
360 do {
361 thethread = __lwp_threadqueue_dequeue(&tq->tqueue);
362 } while(thethread);
363 __lwp_thread_dispatchenable();
365 __lwp_tqueue_free(tq);
366 return;
369 s32 LWP_ThreadSleep(lwpq_t thequeue)
371 u32 level;
372 tqueue_st *tq;
373 lwp_cntrl *exec = NULL;
375 tq = __lwp_tqueue_open(thequeue);
376 if(!tq) return -1;
378 exec = _thr_executing;
379 _CPU_ISR_Disable(level);
380 __lwp_threadqueue_csenter(&tq->tqueue);
381 exec->wait.ret_code = 0;
382 exec->wait.ret_arg = NULL;
383 exec->wait.ret_arg_1 = NULL;
384 exec->wait.queue = &tq->tqueue;
385 exec->wait.id = thequeue;
386 _CPU_ISR_Restore(level);
387 __lwp_threadqueue_enqueue(&tq->tqueue,LWP_THREADQ_NOTIMEOUT);
388 __lwp_thread_dispatchenable();
389 return 0;
392 void LWP_ThreadBroadcast(lwpq_t thequeue)
394 tqueue_st *tq;
395 lwp_cntrl *thethread;
397 tq = __lwp_tqueue_open(thequeue);
398 if(!tq) return;
400 do {
401 thethread = __lwp_threadqueue_dequeue(&tq->tqueue);
402 } while(thethread);
403 __lwp_thread_dispatchenable();
406 void LWP_ThreadSignal(lwpq_t thequeue)
408 tqueue_st *tq;
409 lwp_cntrl *thethread;
411 tq = __lwp_tqueue_open(thequeue);
412 if(!tq) return;
414 thethread = __lwp_threadqueue_dequeue(&tq->tqueue);
415 __lwp_thread_dispatchenable();