xref: /minix3/minix/lib/libmthread/mutex.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_mutex *vm_front, *vm_rear;
7*433d6423SLionel Sambuc static void mthread_mutex_add(mthread_mutex_t *m);
8*433d6423SLionel Sambuc static void mthread_mutex_remove(mthread_mutex_t *m);
9*433d6423SLionel Sambuc #else
10*433d6423SLionel Sambuc # define mthread_mutex_add(m)		((*m)->mm_magic = MTHREAD_INIT_MAGIC)
11*433d6423SLionel Sambuc # define mthread_mutex_remove(m)	((*m)->mm_magic = MTHREAD_NOT_INUSE)
12*433d6423SLionel Sambuc #endif
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc /*===========================================================================*
15*433d6423SLionel Sambuc  *				mthread_init_valid_mutexes		     *
16*433d6423SLionel Sambuc  *===========================================================================*/
mthread_init_valid_mutexes(void)17*433d6423SLionel Sambuc void mthread_init_valid_mutexes(void)
18*433d6423SLionel Sambuc {
19*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
20*433d6423SLionel Sambuc /* Initialize list of valid mutexes */
21*433d6423SLionel Sambuc   vm_front = vm_rear = NULL;
22*433d6423SLionel Sambuc #endif
23*433d6423SLionel Sambuc }
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc /*===========================================================================*
27*433d6423SLionel Sambuc  *				mthread_mutex_add			     *
28*433d6423SLionel Sambuc  *===========================================================================*/
29*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
mthread_mutex_add(m)30*433d6423SLionel Sambuc static void mthread_mutex_add(m)
31*433d6423SLionel Sambuc mthread_mutex_t *m;
32*433d6423SLionel Sambuc {
33*433d6423SLionel Sambuc /* Add mutex to list of valid, initialized mutexes */
34*433d6423SLionel Sambuc 
35*433d6423SLionel Sambuc   if (vm_front == NULL) {	/* Empty list */
36*433d6423SLionel Sambuc   	vm_front = *m;
37*433d6423SLionel Sambuc   	(*m)->mm_prev = NULL;
38*433d6423SLionel Sambuc   } else {
39*433d6423SLionel Sambuc   	vm_rear->mm_next = *m;
40*433d6423SLionel Sambuc   	(*m)->mm_prev = vm_rear;
41*433d6423SLionel Sambuc   }
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc   (*m)->mm_next = NULL;
44*433d6423SLionel Sambuc   vm_rear = *m;
45*433d6423SLionel Sambuc }
46*433d6423SLionel Sambuc #endif
47*433d6423SLionel Sambuc 
48*433d6423SLionel Sambuc /*===========================================================================*
49*433d6423SLionel Sambuc  *				mthread_mutex_destroy			     *
50*433d6423SLionel Sambuc  *===========================================================================*/
mthread_mutex_destroy(mutex)51*433d6423SLionel Sambuc int mthread_mutex_destroy(mutex)
52*433d6423SLionel Sambuc mthread_mutex_t *mutex;
53*433d6423SLionel Sambuc {
54*433d6423SLionel Sambuc /* Invalidate mutex and deallocate resources. */
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc   mthread_thread_t t;
57*433d6423SLionel Sambuc   mthread_tcb_t *tcb;
58*433d6423SLionel Sambuc 
59*433d6423SLionel Sambuc   if (mutex == NULL)
60*433d6423SLionel Sambuc   	return(EINVAL);
61*433d6423SLionel Sambuc 
62*433d6423SLionel Sambuc   if (!mthread_mutex_valid(mutex))
63*433d6423SLionel Sambuc   	return(EINVAL);
64*433d6423SLionel Sambuc   else if ((*mutex)->mm_owner != NO_THREAD)
65*433d6423SLionel Sambuc   	return(EBUSY);
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc   /* Check if this mutex is not associated with a condition */
68*433d6423SLionel Sambuc   for (t = (mthread_thread_t) 0; t < no_threads; t++) {
69*433d6423SLionel Sambuc   	tcb = mthread_find_tcb(t);
70*433d6423SLionel Sambuc 	if (tcb->m_state == MS_CONDITION) {
71*433d6423SLionel Sambuc 		if (tcb->m_cond != NULL && tcb->m_cond->mc_mutex == *mutex)
72*433d6423SLionel Sambuc 			return(EBUSY);
73*433d6423SLionel Sambuc 	}
74*433d6423SLionel Sambuc   }
75*433d6423SLionel Sambuc 
76*433d6423SLionel Sambuc   /* Not in use; invalidate it */
77*433d6423SLionel Sambuc   mthread_mutex_remove(mutex);
78*433d6423SLionel Sambuc   free(*mutex);
79*433d6423SLionel Sambuc   *mutex = NULL;
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc   return(0);
82*433d6423SLionel Sambuc }
83*433d6423SLionel Sambuc 
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc /*===========================================================================*
86*433d6423SLionel Sambuc  *				mthread_mutex_init			     *
87*433d6423SLionel Sambuc  *===========================================================================*/
mthread_mutex_init(mutex,mattr)88*433d6423SLionel Sambuc int mthread_mutex_init(mutex, mattr)
89*433d6423SLionel Sambuc mthread_mutex_t *mutex;	/* Mutex that is to be initialized */
90*433d6423SLionel Sambuc mthread_mutexattr_t *mattr;	/* Mutex attribute */
91*433d6423SLionel Sambuc {
92*433d6423SLionel Sambuc /* Initialize the mutex to a known state. Attributes are not supported */
93*433d6423SLionel Sambuc 
94*433d6423SLionel Sambuc   struct __mthread_mutex *m;
95*433d6423SLionel Sambuc 
96*433d6423SLionel Sambuc   if (mutex == NULL)
97*433d6423SLionel Sambuc   	return(EAGAIN);
98*433d6423SLionel Sambuc   else if (mattr != NULL)
99*433d6423SLionel Sambuc   	return(ENOSYS);
100*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
101*433d6423SLionel Sambuc   else if (mthread_mutex_valid(mutex))
102*433d6423SLionel Sambuc   	return(EBUSY);
103*433d6423SLionel Sambuc #endif
104*433d6423SLionel Sambuc   else if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL)
105*433d6423SLionel Sambuc   	return(ENOMEM);
106*433d6423SLionel Sambuc 
107*433d6423SLionel Sambuc   mthread_queue_init(&m->mm_queue);
108*433d6423SLionel Sambuc   m->mm_owner = NO_THREAD;
109*433d6423SLionel Sambuc   *mutex = (mthread_mutex_t) m;
110*433d6423SLionel Sambuc   mthread_mutex_add(mutex); /* Validate mutex; mutex now in use */
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc   return(0);
113*433d6423SLionel Sambuc }
114*433d6423SLionel Sambuc 
115*433d6423SLionel Sambuc /*===========================================================================*
116*433d6423SLionel Sambuc  *				mthread_mutex_lock			     *
117*433d6423SLionel Sambuc  *===========================================================================*/
mthread_mutex_lock(mutex)118*433d6423SLionel Sambuc int mthread_mutex_lock(mutex)
119*433d6423SLionel Sambuc mthread_mutex_t *mutex;	/* Mutex that is to be locked */
120*433d6423SLionel Sambuc {
121*433d6423SLionel Sambuc /* Try to lock this mutex. If already locked, append the current thread to
122*433d6423SLionel Sambuc  * FIFO queue associated with this mutex and suspend the thread. */
123*433d6423SLionel Sambuc 
124*433d6423SLionel Sambuc   struct __mthread_mutex *m;
125*433d6423SLionel Sambuc 
126*433d6423SLionel Sambuc   if (mutex == NULL)
127*433d6423SLionel Sambuc   	return(EINVAL);
128*433d6423SLionel Sambuc 
129*433d6423SLionel Sambuc   m = (struct __mthread_mutex *) *mutex;
130*433d6423SLionel Sambuc   if (!mthread_mutex_valid(&m))
131*433d6423SLionel Sambuc   	return(EINVAL);
132*433d6423SLionel Sambuc   else if (m->mm_owner == NO_THREAD) { /* Not locked */
133*433d6423SLionel Sambuc 	m->mm_owner = current_thread;
134*433d6423SLionel Sambuc   } else if (m->mm_owner == current_thread) {
135*433d6423SLionel Sambuc   	return(EDEADLK);
136*433d6423SLionel Sambuc   } else {
137*433d6423SLionel Sambuc 	mthread_queue_add(&m->mm_queue, current_thread);
138*433d6423SLionel Sambuc 	mthread_suspend(MS_MUTEX);
139*433d6423SLionel Sambuc   }
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc   /* When we get here we acquired the lock. */
142*433d6423SLionel Sambuc   return(0);
143*433d6423SLionel Sambuc }
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc 
146*433d6423SLionel Sambuc /*===========================================================================*
147*433d6423SLionel Sambuc  *				mthread_mutex_remove			     *
148*433d6423SLionel Sambuc  *===========================================================================*/
149*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
mthread_mutex_remove(m)150*433d6423SLionel Sambuc static void mthread_mutex_remove(m)
151*433d6423SLionel Sambuc mthread_mutex_t *m;
152*433d6423SLionel Sambuc {
153*433d6423SLionel Sambuc /* Remove mutex from list of valid, initialized mutexes */
154*433d6423SLionel Sambuc 
155*433d6423SLionel Sambuc   if ((*m)->mm_prev == NULL)
156*433d6423SLionel Sambuc   	vm_front = (*m)->mm_next;
157*433d6423SLionel Sambuc   else
158*433d6423SLionel Sambuc   	(*m)->mm_prev->mm_next = (*m)->mm_next;
159*433d6423SLionel Sambuc 
160*433d6423SLionel Sambuc   if ((*m)->mm_next == NULL)
161*433d6423SLionel Sambuc   	vm_rear = (*m)->mm_prev;
162*433d6423SLionel Sambuc   else
163*433d6423SLionel Sambuc   	(*m)->mm_next->mm_prev = (*m)->mm_prev;
164*433d6423SLionel Sambuc }
165*433d6423SLionel Sambuc #endif
166*433d6423SLionel Sambuc 
167*433d6423SLionel Sambuc /*===========================================================================*
168*433d6423SLionel Sambuc  *				mthread_mutex_trylock			     *
169*433d6423SLionel Sambuc  *===========================================================================*/
mthread_mutex_trylock(mutex)170*433d6423SLionel Sambuc int mthread_mutex_trylock(mutex)
171*433d6423SLionel Sambuc mthread_mutex_t *mutex;	/* Mutex that is to be locked */
172*433d6423SLionel Sambuc {
173*433d6423SLionel Sambuc /* Try to lock this mutex and return OK. If already locked, return error. */
174*433d6423SLionel Sambuc 
175*433d6423SLionel Sambuc   struct __mthread_mutex *m;
176*433d6423SLionel Sambuc 
177*433d6423SLionel Sambuc   if (mutex == NULL)
178*433d6423SLionel Sambuc   	return(EINVAL);
179*433d6423SLionel Sambuc 
180*433d6423SLionel Sambuc   m = (struct __mthread_mutex *) *mutex;
181*433d6423SLionel Sambuc   if (!mthread_mutex_valid(&m))
182*433d6423SLionel Sambuc   	return(EINVAL);
183*433d6423SLionel Sambuc   else if (m->mm_owner == current_thread)
184*433d6423SLionel Sambuc 	return(EDEADLK);
185*433d6423SLionel Sambuc   else if (m->mm_owner == NO_THREAD) {
186*433d6423SLionel Sambuc 	m->mm_owner = current_thread;
187*433d6423SLionel Sambuc 	return(0);
188*433d6423SLionel Sambuc   }
189*433d6423SLionel Sambuc 
190*433d6423SLionel Sambuc   return(EBUSY);
191*433d6423SLionel Sambuc }
192*433d6423SLionel Sambuc 
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc /*===========================================================================*
195*433d6423SLionel Sambuc  *				mthread_mutex_unlock			     *
196*433d6423SLionel Sambuc  *===========================================================================*/
mthread_mutex_unlock(mutex)197*433d6423SLionel Sambuc int mthread_mutex_unlock(mutex)
198*433d6423SLionel Sambuc mthread_mutex_t *mutex;	/* Mutex that is to be unlocked */
199*433d6423SLionel Sambuc {
200*433d6423SLionel Sambuc /* Unlock a previously locked mutex. If there is a pending lock for this mutex
201*433d6423SLionel Sambuc  * by another thread, mark that thread runnable. */
202*433d6423SLionel Sambuc 
203*433d6423SLionel Sambuc   struct __mthread_mutex *m;
204*433d6423SLionel Sambuc 
205*433d6423SLionel Sambuc   if (mutex == NULL)
206*433d6423SLionel Sambuc 	return(EINVAL);
207*433d6423SLionel Sambuc 
208*433d6423SLionel Sambuc   m = (struct __mthread_mutex *) *mutex;
209*433d6423SLionel Sambuc   if (!mthread_mutex_valid(&m))
210*433d6423SLionel Sambuc 	return(EINVAL);
211*433d6423SLionel Sambuc   else if (m->mm_owner != current_thread)
212*433d6423SLionel Sambuc   	return(EPERM);	/* Can't unlock a mutex locked by another thread. */
213*433d6423SLionel Sambuc 
214*433d6423SLionel Sambuc   m->mm_owner = mthread_queue_remove(&m->mm_queue);
215*433d6423SLionel Sambuc   if (m->mm_owner != NO_THREAD) mthread_unsuspend(m->mm_owner);
216*433d6423SLionel Sambuc   return(0);
217*433d6423SLionel Sambuc }
218*433d6423SLionel Sambuc 
219*433d6423SLionel Sambuc 
220*433d6423SLionel Sambuc /*===========================================================================*
221*433d6423SLionel Sambuc  *				mthread_mutex_valid			     *
222*433d6423SLionel Sambuc  *===========================================================================*/
223*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
mthread_mutex_valid(m)224*433d6423SLionel Sambuc int mthread_mutex_valid(m)
225*433d6423SLionel Sambuc mthread_mutex_t *m;
226*433d6423SLionel Sambuc {
227*433d6423SLionel Sambuc /* Check to see if mutex is on the list of valid mutexes */
228*433d6423SLionel Sambuc   struct __mthread_mutex *loopitem;
229*433d6423SLionel Sambuc 
230*433d6423SLionel Sambuc   loopitem = vm_front;
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc   while (loopitem != NULL) {
233*433d6423SLionel Sambuc 	if (loopitem == *m)
234*433d6423SLionel Sambuc 		return(1);
235*433d6423SLionel Sambuc 
236*433d6423SLionel Sambuc 	loopitem = loopitem->mm_next;
237*433d6423SLionel Sambuc   }
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc   return(0);
240*433d6423SLionel Sambuc }
241*433d6423SLionel Sambuc #endif
242*433d6423SLionel Sambuc 
243*433d6423SLionel Sambuc /*===========================================================================*
244*433d6423SLionel Sambuc  *				mthread_mutex_verify			     *
245*433d6423SLionel Sambuc  *===========================================================================*/
246*433d6423SLionel Sambuc #ifdef MDEBUG
mthread_mutex_verify(void)247*433d6423SLionel Sambuc int mthread_mutex_verify(void)
248*433d6423SLionel Sambuc {
249*433d6423SLionel Sambuc   /* Return true when no mutexes are in use */
250*433d6423SLionel Sambuc   int r = 1;
251*433d6423SLionel Sambuc   struct __mthread_mutex *loopitem;
252*433d6423SLionel Sambuc 
253*433d6423SLionel Sambuc #ifdef MTHREAD_STRICT
254*433d6423SLionel Sambuc   loopitem = vm_front;
255*433d6423SLionel Sambuc 
256*433d6423SLionel Sambuc   while (loopitem != NULL) {
257*433d6423SLionel Sambuc   	printf("mutex corruption: owner: %d\n", loopitem->mm_owner);
258*433d6423SLionel Sambuc 	loopitem = loopitem->mm_next;
259*433d6423SLionel Sambuc   	r = 0;
260*433d6423SLionel Sambuc   }
261*433d6423SLionel Sambuc #endif
262*433d6423SLionel Sambuc 
263*433d6423SLionel Sambuc   return(r);
264*433d6423SLionel Sambuc }
265*433d6423SLionel Sambuc #endif
266