1 /*-------------------------------------------------------------
2
3 cond.c -- Thread subsystem V
4
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8
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.
12
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:
16
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.
21
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
24
25 3. This notice may not be removed or altered from any source
26 distribution.
27
28 -------------------------------------------------------------*/
29
30 #include <stdlib.h>
31 #include <errno.h>
32 #include "asm.h"
33 #include "mutex.h"
34 #include "lwp_threadq.h"
35 #include "lwp_objmgr.h"
36 #include "lwp_config.h"
37 #include "cond.h"
38
39 #define LWP_OBJTYPE_COND 5
40
41 #define LWP_CHECK_COND(hndl) \
42 { \
43 if(((hndl)==LWP_COND_NULL) || (LWP_OBJTYPE(hndl)!=LWP_OBJTYPE_COND)) \
44 return NULL; \
45 }
46
47 typedef struct _cond_st {
48 lwp_obj object;
49 mutex_t lock;
50 lwp_thrqueue wait_queue;
51 } cond_st;
52
53 lwp_objinfo _lwp_cond_objects;
54
55 extern int clock_gettime(struct timespec *tp);
56 extern void timespec_subtract(const struct timespec *tp_start,const struct timespec *tp_end,struct timespec *result);
57
__lwp_cond_init()58 void __lwp_cond_init()
59 {
60 __lwp_objmgr_initinfo(&_lwp_cond_objects,LWP_MAX_CONDVARS,sizeof(cond_st));
61 }
62
__lwp_cond_open(cond_t cond)63 static __inline__ cond_st* __lwp_cond_open(cond_t cond)
64 {
65 LWP_CHECK_COND(cond);
66 return (cond_st*)__lwp_objmgr_get(&_lwp_cond_objects,LWP_OBJMASKID(cond));
67 }
68
__lwp_cond_free(cond_st * cond)69 static __inline__ void __lwp_cond_free(cond_st *cond)
70 {
71 __lwp_objmgr_close(&_lwp_cond_objects,&cond->object);
72 __lwp_objmgr_free(&_lwp_cond_objects,&cond->object);
73 }
74
__lwp_cond_allocate()75 static cond_st* __lwp_cond_allocate()
76 {
77 cond_st *cond;
78
79 __lwp_thread_dispatchdisable();
80 cond = (cond_st*)__lwp_objmgr_allocate(&_lwp_cond_objects);
81 if(cond) {
82 __lwp_objmgr_open(&_lwp_cond_objects,&cond->object);
83 return cond;
84 }
85 __lwp_thread_dispatchenable();
86 return NULL;
87 }
88
__lwp_cond_waitsupp(cond_t cond,mutex_t mutex,u64 timeout,u8 timedout)89 static s32 __lwp_cond_waitsupp(cond_t cond,mutex_t mutex,u64 timeout,u8 timedout)
90 {
91 u32 status,mstatus,level;
92 cond_st *thecond = __lwp_cond_open(cond);
93
94 if(!thecond) return -1;
95
96 if(thecond->lock!=LWP_MUTEX_NULL && thecond->lock!=mutex) {
97 __lwp_thread_dispatchenable();
98 return EINVAL;
99 }
100
101 LWP_MutexUnlock(mutex);
102 if(!timedout) {
103 thecond->lock = mutex;
104 _CPU_ISR_Disable(level);
105 __lwp_threadqueue_csenter(&thecond->wait_queue);
106 _thr_executing->wait.ret_code = 0;
107 _thr_executing->wait.queue = &thecond->wait_queue;
108 _thr_executing->wait.id = cond;
109 _CPU_ISR_Restore(level);
110 __lwp_threadqueue_enqueue(&thecond->wait_queue,timeout);
111 __lwp_thread_dispatchenable();
112
113 status = _thr_executing->wait.ret_code;
114 if(status && status!=ETIMEDOUT)
115 return status;
116 } else {
117 __lwp_thread_dispatchenable();
118 status = ETIMEDOUT;
119 }
120
121 mstatus = LWP_MutexLock(mutex);
122 if(mstatus)
123 return EINVAL;
124
125 return status;
126 }
127
__lwp_cond_signalsupp(cond_t cond,u8 isbroadcast)128 static s32 __lwp_cond_signalsupp(cond_t cond,u8 isbroadcast)
129 {
130 lwp_cntrl *thethread;
131 cond_st *thecond = __lwp_cond_open(cond);
132 if(!thecond) return -1;
133
134 do {
135 thethread = __lwp_threadqueue_dequeue(&thecond->wait_queue);
136 if(!thethread) thecond->lock = LWP_MUTEX_NULL;
137 } while(isbroadcast && thethread);
138 __lwp_thread_dispatchenable();
139 return 0;
140 }
141
LWP_CondInit(cond_t * cond)142 s32 LWP_CondInit(cond_t *cond)
143 {
144 cond_st *ret;
145
146 if(!cond) return -1;
147
148 ret = __lwp_cond_allocate();
149 if(!ret) return ENOMEM;
150
151 ret->lock = LWP_MUTEX_NULL;
152 __lwp_threadqueue_init(&ret->wait_queue,LWP_THREADQ_MODEFIFO,LWP_STATES_WAITING_FOR_CONDVAR,ETIMEDOUT);
153
154 *cond = (cond_t)(LWP_OBJMASKTYPE(LWP_OBJTYPE_COND)|LWP_OBJMASKID(ret->object.id));
155 __lwp_thread_dispatchenable();
156
157 return 0;
158 }
159
LWP_CondWait(cond_t cond,mutex_t mutex)160 s32 LWP_CondWait(cond_t cond,mutex_t mutex)
161 {
162 return __lwp_cond_waitsupp(cond,mutex,LWP_THREADQ_NOTIMEOUT,FALSE);
163 }
164
LWP_CondSignal(cond_t cond)165 s32 LWP_CondSignal(cond_t cond)
166 {
167 return __lwp_cond_signalsupp(cond,FALSE);
168 }
169
LWP_CondBroadcast(cond_t cond)170 s32 LWP_CondBroadcast(cond_t cond)
171 {
172 return __lwp_cond_signalsupp(cond,TRUE);
173 }
174
LWP_CondTimedWait(cond_t cond,mutex_t mutex,const struct timespec * abstime)175 s32 LWP_CondTimedWait(cond_t cond,mutex_t mutex,const struct timespec *abstime)
176 {
177 u64 timeout = LWP_THREADQ_NOTIMEOUT;
178 bool timedout = FALSE;
179
180 if(abstime) timeout = __lwp_wd_calc_ticks(abstime);
181 return __lwp_cond_waitsupp(cond,mutex,timeout,timedout);
182 }
183
LWP_CondDestroy(cond_t cond)184 s32 LWP_CondDestroy(cond_t cond)
185 {
186 cond_st *ptr = __lwp_cond_open(cond);
187 if(!ptr) return -1;
188
189 if(__lwp_threadqueue_first(&ptr->wait_queue)) {
190 __lwp_thread_dispatchenable();
191 return EBUSY;
192 }
193 __lwp_thread_dispatchenable();
194
195 __lwp_cond_free(ptr);
196 return 0;
197 }
198