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