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