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