xref: /minix3/minix/lib/libmthread/condition.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include <minix/mthread.h>
2*433d6423SLionel Sambuc #include "global.h"
3*433d6423SLionel Sambuc #include "proto.h"
4*433d6423SLionel Sambuc 
5*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
6*433d6423SLionel Sambuc static struct __mthread_cond *vc_front, *vc_rear;
7*433d6423SLionel Sambuc static void mthread_cond_add(mthread_cond_t *c);
8*433d6423SLionel Sambuc static void mthread_cond_remove(mthread_cond_t *c);
9*433d6423SLionel Sambuc static int mthread_cond_valid(mthread_cond_t *c);
10*433d6423SLionel Sambuc #else
11*433d6423SLionel Sambuc # define mthread_cond_add(c)		((*c)->mc_magic = MTHREAD_INIT_MAGIC)
12*433d6423SLionel Sambuc # define mthread_cond_remove(c)		((*c)->mc_magic = MTHREAD_NOT_INUSE)
13*433d6423SLionel Sambuc # define mthread_cond_valid(c)		((*c)->mc_magic == MTHREAD_INIT_MAGIC)
14*433d6423SLionel Sambuc #endif
15*433d6423SLionel Sambuc #define MAIN_COND mainthread.m_cond
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc /*===========================================================================*
18*433d6423SLionel Sambuc  *				mthread_init_valid_conditions		     *
19*433d6423SLionel Sambuc  *===========================================================================*/
mthread_init_valid_conditions(void)20*433d6423SLionel Sambuc void mthread_init_valid_conditions(void)
21*433d6423SLionel Sambuc {
22*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
23*433d6423SLionel Sambuc /* Initialize condition variable list */
24*433d6423SLionel Sambuc   vc_front = vc_rear = NULL;
25*433d6423SLionel Sambuc #endif
26*433d6423SLionel Sambuc }
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc 
29*433d6423SLionel Sambuc /*===========================================================================*
30*433d6423SLionel Sambuc  *				mthread_cond_add			     *
31*433d6423SLionel Sambuc  *===========================================================================*/
32*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
mthread_cond_add(c)33*433d6423SLionel Sambuc static void mthread_cond_add(c)
34*433d6423SLionel Sambuc mthread_cond_t *c;
35*433d6423SLionel Sambuc {
36*433d6423SLionel Sambuc /* Add condition to list of valid, initialized conditions */
37*433d6423SLionel Sambuc 
38*433d6423SLionel Sambuc   if (vc_front == NULL) {	/* Empty list */
39*433d6423SLionel Sambuc   	vc_front = *c;
40*433d6423SLionel Sambuc   	(*c)->mc_prev = NULL;
41*433d6423SLionel Sambuc   } else {
42*433d6423SLionel Sambuc   	vc_rear->mc_next = *c;
43*433d6423SLionel Sambuc   	(*c)->mc_prev = vc_rear;
44*433d6423SLionel Sambuc   }
45*433d6423SLionel Sambuc 
46*433d6423SLionel Sambuc   (*c)->mc_next = NULL;
47*433d6423SLionel Sambuc   vc_rear = *c;
48*433d6423SLionel Sambuc }
49*433d6423SLionel Sambuc #endif
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc /*===========================================================================*
52*433d6423SLionel Sambuc  *				mthread_cond_broadcast			     *
53*433d6423SLionel Sambuc  *===========================================================================*/
mthread_cond_broadcast(cond)54*433d6423SLionel Sambuc int mthread_cond_broadcast(cond)
55*433d6423SLionel Sambuc mthread_cond_t *cond;
56*433d6423SLionel Sambuc {
57*433d6423SLionel Sambuc /* Signal all threads waiting for condition 'cond'. */
58*433d6423SLionel Sambuc   mthread_thread_t t;
59*433d6423SLionel Sambuc   mthread_tcb_t *tcb;
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc   if (cond == NULL)
62*433d6423SLionel Sambuc   	return(EINVAL);
63*433d6423SLionel Sambuc   else if (!mthread_cond_valid(cond))
64*433d6423SLionel Sambuc   	return(EINVAL);
65*433d6423SLionel Sambuc 
66*433d6423SLionel Sambuc   tcb = mthread_find_tcb(MAIN_THREAD);
67*433d6423SLionel Sambuc   if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
68*433d6423SLionel Sambuc   	mthread_unsuspend(MAIN_THREAD);
69*433d6423SLionel Sambuc 
70*433d6423SLionel Sambuc   for (t = (mthread_thread_t) 0; t < no_threads; t++) {
71*433d6423SLionel Sambuc   	tcb = mthread_find_tcb(t);
72*433d6423SLionel Sambuc 	if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
73*433d6423SLionel Sambuc 		mthread_unsuspend(t);
74*433d6423SLionel Sambuc   }
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc   return(0);
77*433d6423SLionel Sambuc }
78*433d6423SLionel Sambuc 
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc /*===========================================================================*
81*433d6423SLionel Sambuc  *				mthread_cond_destroy			     *
82*433d6423SLionel Sambuc  *===========================================================================*/
mthread_cond_destroy(cond)83*433d6423SLionel Sambuc int mthread_cond_destroy(cond)
84*433d6423SLionel Sambuc mthread_cond_t *cond;
85*433d6423SLionel Sambuc {
86*433d6423SLionel Sambuc /* Destroy a condition variable. Make sure it's not in use */
87*433d6423SLionel Sambuc   mthread_thread_t t;
88*433d6423SLionel Sambuc   mthread_tcb_t *tcb;
89*433d6423SLionel Sambuc 
90*433d6423SLionel Sambuc   if (cond == NULL)
91*433d6423SLionel Sambuc   	return(EINVAL);
92*433d6423SLionel Sambuc   else if (!mthread_cond_valid(cond))
93*433d6423SLionel Sambuc   	return(EINVAL);
94*433d6423SLionel Sambuc 
95*433d6423SLionel Sambuc   /* Is another thread currently using this condition variable? */
96*433d6423SLionel Sambuc   tcb = mthread_find_tcb(MAIN_THREAD);
97*433d6423SLionel Sambuc   if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
98*433d6423SLionel Sambuc   	return(EBUSY);
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc   for (t = (mthread_thread_t) 0; t < no_threads; t++) {
101*433d6423SLionel Sambuc   	tcb = mthread_find_tcb(t);
102*433d6423SLionel Sambuc 	if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
103*433d6423SLionel Sambuc 		return(EBUSY);
104*433d6423SLionel Sambuc   }
105*433d6423SLionel Sambuc 
106*433d6423SLionel Sambuc   /* Not in use; invalidate it. */
107*433d6423SLionel Sambuc   mthread_cond_remove(cond);
108*433d6423SLionel Sambuc   free(*cond);
109*433d6423SLionel Sambuc   *cond = NULL;
110*433d6423SLionel Sambuc 
111*433d6423SLionel Sambuc   return(0);
112*433d6423SLionel Sambuc }
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc /*===========================================================================*
116*433d6423SLionel Sambuc  *				mthread_cond_init			     *
117*433d6423SLionel Sambuc  *===========================================================================*/
mthread_cond_init(cond,cattr)118*433d6423SLionel Sambuc int mthread_cond_init(cond, cattr)
119*433d6423SLionel Sambuc mthread_cond_t *cond;
120*433d6423SLionel Sambuc mthread_condattr_t *cattr;
121*433d6423SLionel Sambuc {
122*433d6423SLionel Sambuc /* Initialize condition variable to a known state. cattr is ignored */
123*433d6423SLionel Sambuc   struct __mthread_cond *c;
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc   if (cond == NULL)
126*433d6423SLionel Sambuc 	return(EINVAL);
127*433d6423SLionel Sambuc   else if (cattr != NULL)
128*433d6423SLionel Sambuc   	return(ENOSYS);
129*433d6423SLionel Sambuc 
130*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
131*433d6423SLionel Sambuc   else if (mthread_cond_valid(cond))
132*433d6423SLionel Sambuc 	/* Already initialized */
133*433d6423SLionel Sambuc   	return(EBUSY);
134*433d6423SLionel Sambuc #endif
135*433d6423SLionel Sambuc   else if ((c = malloc(sizeof(struct __mthread_cond))) == NULL)
136*433d6423SLionel Sambuc   	return(ENOMEM);
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc   c->mc_mutex = NULL;
139*433d6423SLionel Sambuc   *cond = (mthread_cond_t) c;
140*433d6423SLionel Sambuc   mthread_cond_add(cond);
141*433d6423SLionel Sambuc 
142*433d6423SLionel Sambuc   return(0);
143*433d6423SLionel Sambuc }
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc 
146*433d6423SLionel Sambuc /*===========================================================================*
147*433d6423SLionel Sambuc  *				mthread_cond_remove			     *
148*433d6423SLionel Sambuc  *===========================================================================*/
149*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
mthread_cond_remove(c)150*433d6423SLionel Sambuc static void mthread_cond_remove(c)
151*433d6423SLionel Sambuc mthread_cond_t *c;
152*433d6423SLionel Sambuc {
153*433d6423SLionel Sambuc /* Remove condition from list of valid, initialized conditions */
154*433d6423SLionel Sambuc 
155*433d6423SLionel Sambuc   if ((*c)->mc_prev == NULL)
156*433d6423SLionel Sambuc   	vc_front = (*c)->mc_next;
157*433d6423SLionel Sambuc   else
158*433d6423SLionel Sambuc   	(*c)->mc_prev->mc_next = (*c)->mc_next;
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc   if ((*c)->mc_next == NULL)
161*433d6423SLionel Sambuc   	vc_rear = (*c)->mc_prev;
162*433d6423SLionel Sambuc   else
163*433d6423SLionel Sambuc   	(*c)->mc_next->mc_prev = (*c)->mc_prev;
164*433d6423SLionel Sambuc 
165*433d6423SLionel Sambuc }
166*433d6423SLionel Sambuc #endif
167*433d6423SLionel Sambuc 
168*433d6423SLionel Sambuc /*===========================================================================*
169*433d6423SLionel Sambuc  *				mthread_cond_signal			     *
170*433d6423SLionel Sambuc  *===========================================================================*/
mthread_cond_signal(cond)171*433d6423SLionel Sambuc int mthread_cond_signal(cond)
172*433d6423SLionel Sambuc mthread_cond_t *cond;
173*433d6423SLionel Sambuc {
174*433d6423SLionel Sambuc /* Signal a thread that condition 'cond' was met. Just a single thread. */
175*433d6423SLionel Sambuc   mthread_thread_t t;
176*433d6423SLionel Sambuc   mthread_tcb_t *tcb;
177*433d6423SLionel Sambuc 
178*433d6423SLionel Sambuc   if (cond == NULL)
179*433d6423SLionel Sambuc 	return(EINVAL);
180*433d6423SLionel Sambuc   else if (!mthread_cond_valid(cond))
181*433d6423SLionel Sambuc 	return(EINVAL);
182*433d6423SLionel Sambuc 
183*433d6423SLionel Sambuc   tcb = mthread_find_tcb(MAIN_THREAD);
184*433d6423SLionel Sambuc   if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
185*433d6423SLionel Sambuc   	mthread_unsuspend(MAIN_THREAD);
186*433d6423SLionel Sambuc 
187*433d6423SLionel Sambuc   for (t = (mthread_thread_t) 0; t < no_threads; t++) {
188*433d6423SLionel Sambuc   	tcb = mthread_find_tcb(t);
189*433d6423SLionel Sambuc 	if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){
190*433d6423SLionel Sambuc 		mthread_unsuspend(t);
191*433d6423SLionel Sambuc 		break;
192*433d6423SLionel Sambuc 	}
193*433d6423SLionel Sambuc   }
194*433d6423SLionel Sambuc 
195*433d6423SLionel Sambuc   return(0);
196*433d6423SLionel Sambuc }
197*433d6423SLionel Sambuc 
198*433d6423SLionel Sambuc 
199*433d6423SLionel Sambuc /*===========================================================================*
200*433d6423SLionel Sambuc  *				mthread_cond_valid			     *
201*433d6423SLionel Sambuc  *===========================================================================*/
202*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
mthread_cond_valid(c)203*433d6423SLionel Sambuc static int mthread_cond_valid(c)
204*433d6423SLionel Sambuc mthread_cond_t *c;
205*433d6423SLionel Sambuc {
206*433d6423SLionel Sambuc /* Check to see if cond is on the list of valid conditions */
207*433d6423SLionel Sambuc   struct __mthread_cond *loopitem;
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc   loopitem = vc_front;
210*433d6423SLionel Sambuc 
211*433d6423SLionel Sambuc   while (loopitem != NULL) {
212*433d6423SLionel Sambuc   	if (loopitem == *c)
213*433d6423SLionel Sambuc   		return(1);
214*433d6423SLionel Sambuc 
215*433d6423SLionel Sambuc   	loopitem = loopitem->mc_next;
216*433d6423SLionel Sambuc   }
217*433d6423SLionel Sambuc 
218*433d6423SLionel Sambuc   return(0);
219*433d6423SLionel Sambuc }
220*433d6423SLionel Sambuc #endif
221*433d6423SLionel Sambuc 
222*433d6423SLionel Sambuc /*===========================================================================*
223*433d6423SLionel Sambuc  *				mthread_cond_verify			     *
224*433d6423SLionel Sambuc  *===========================================================================*/
225*433d6423SLionel Sambuc #ifdef MDEBUG
mthread_cond_verify(void)226*433d6423SLionel Sambuc int mthread_cond_verify(void)
227*433d6423SLionel Sambuc {
228*433d6423SLionel Sambuc /* Return true in case no condition variables are in use. */
229*433d6423SLionel Sambuc 
230*433d6423SLionel Sambuc   return(vc_front == NULL);
231*433d6423SLionel Sambuc }
232*433d6423SLionel Sambuc #endif
233*433d6423SLionel Sambuc 
234*433d6423SLionel Sambuc 
235*433d6423SLionel Sambuc /*===========================================================================*
236*433d6423SLionel Sambuc  *				mthread_cond_wait			     *
237*433d6423SLionel Sambuc  *===========================================================================*/
mthread_cond_wait(cond,mutex)238*433d6423SLionel Sambuc int mthread_cond_wait(cond, mutex)
239*433d6423SLionel Sambuc mthread_cond_t *cond;
240*433d6423SLionel Sambuc mthread_mutex_t *mutex;
241*433d6423SLionel Sambuc {
242*433d6423SLionel Sambuc /* Wait for a condition to be signaled */
243*433d6423SLionel Sambuc   mthread_tcb_t *tcb;
244*433d6423SLionel Sambuc   struct __mthread_cond *c;
245*433d6423SLionel Sambuc   struct __mthread_mutex *m;
246*433d6423SLionel Sambuc 
247*433d6423SLionel Sambuc   if (cond == NULL || mutex == NULL)
248*433d6423SLionel Sambuc 	return(EINVAL);
249*433d6423SLionel Sambuc 
250*433d6423SLionel Sambuc   c = (struct __mthread_cond *) *cond;
251*433d6423SLionel Sambuc   m = (struct __mthread_mutex *) *mutex;
252*433d6423SLionel Sambuc 
253*433d6423SLionel Sambuc   if (!mthread_cond_valid(cond) || !mthread_mutex_valid(mutex))
254*433d6423SLionel Sambuc 	return(EINVAL);
255*433d6423SLionel Sambuc 
256*433d6423SLionel Sambuc   c->mc_mutex = m;	/* Remember we're using this mutex in a cond_wait */
257*433d6423SLionel Sambuc   if (mthread_mutex_unlock(mutex) != 0) /* Fails when we're not the owner */
258*433d6423SLionel Sambuc   	return(-1);
259*433d6423SLionel Sambuc 
260*433d6423SLionel Sambuc   tcb = mthread_find_tcb(current_thread);
261*433d6423SLionel Sambuc   tcb->m_cond = c; /* Register condition variable. */
262*433d6423SLionel Sambuc   mthread_suspend(MS_CONDITION);
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc   /* When execution returns here, the condition was met. Lock mutex again. */
265*433d6423SLionel Sambuc   c->mc_mutex = NULL;				/* Forget about this mutex */
266*433d6423SLionel Sambuc   tcb->m_cond = NULL;				/* ... and condition var */
267*433d6423SLionel Sambuc   if (mthread_mutex_lock(mutex) != 0)
268*433d6423SLionel Sambuc   	return(-1);
269*433d6423SLionel Sambuc 
270*433d6423SLionel Sambuc   return(0);
271*433d6423SLionel Sambuc }
272*433d6423SLionel Sambuc 
273*433d6423SLionel Sambuc /* pthread compatibility layer. */
274*433d6423SLionel Sambuc __weak_alias(pthread_cond_init, mthread_cond_init)
275*433d6423SLionel Sambuc 
276