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