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