custom message type for VM_INFO
[minix3.git] / lib / libmthread / mutex.c
blob7f4683a6d34432ac06c368d707a1f5d6c4928be1
1 #include <minix/mthread.h>
2 #include "global.h"
3 #include "proto.h"
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
14 /*===========================================================================*
15 * mthread_init_valid_mutexes *
16 *===========================================================================*/
17 void mthread_init_valid_mutexes(void)
19 #ifdef MTHREAD_STRICT
20 /* Initialize list of valid mutexes */
21 vm_front = vm_rear = NULL;
22 #endif
26 /*===========================================================================*
27 * mthread_mutex_add *
28 *===========================================================================*/
29 #ifdef MTHREAD_STRICT
30 static void mthread_mutex_add(m)
31 mthread_mutex_t *m;
33 /* Add mutex to list of valid, initialized mutexes */
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;
43 (*m)->mm_next = NULL;
44 vm_rear = *m;
46 #endif
48 /*===========================================================================*
49 * mthread_mutex_destroy *
50 *===========================================================================*/
51 int mthread_mutex_destroy(mutex)
52 mthread_mutex_t *mutex;
54 /* Invalidate mutex and deallocate resources. */
56 mthread_thread_t t;
57 mthread_tcb_t *tcb;
59 if (mutex == NULL)
60 return(EINVAL);
62 if (!mthread_mutex_valid(mutex))
63 return(EINVAL);
64 else if ((*mutex)->mm_owner != NO_THREAD)
65 return(EBUSY);
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);
76 /* Not in use; invalidate it */
77 mthread_mutex_remove(mutex);
78 free(*mutex);
79 *mutex = NULL;
81 return(0);
85 /*===========================================================================*
86 * mthread_mutex_init *
87 *===========================================================================*/
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 */
92 /* Initialize the mutex to a known state. Attributes are not supported */
94 struct __mthread_mutex *m;
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);
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 */
112 return(0);
115 /*===========================================================================*
116 * mthread_mutex_lock *
117 *===========================================================================*/
118 int mthread_mutex_lock(mutex)
119 mthread_mutex_t *mutex; /* Mutex that is to be locked */
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. */
124 struct __mthread_mutex *m;
126 if (mutex == NULL)
127 return(EINVAL);
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);
141 /* When we get here we acquired the lock. */
142 return(0);
146 /*===========================================================================*
147 * mthread_mutex_remove *
148 *===========================================================================*/
149 #ifdef MTHREAD_STRICT
150 static void mthread_mutex_remove(m)
151 mthread_mutex_t *m;
153 /* Remove mutex from list of valid, initialized mutexes */
155 if ((*m)->mm_prev == NULL)
156 vm_front = (*m)->mm_next;
157 else
158 (*m)->mm_prev->mm_next = (*m)->mm_next;
160 if ((*m)->mm_next == NULL)
161 vm_rear = (*m)->mm_prev;
162 else
163 (*m)->mm_next->mm_prev = (*m)->mm_prev;
165 #endif
167 /*===========================================================================*
168 * mthread_mutex_trylock *
169 *===========================================================================*/
170 int mthread_mutex_trylock(mutex)
171 mthread_mutex_t *mutex; /* Mutex that is to be locked */
173 /* Try to lock this mutex and return OK. If already locked, return error. */
175 struct __mthread_mutex *m;
177 if (mutex == NULL)
178 return(EINVAL);
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);
190 return(EBUSY);
194 /*===========================================================================*
195 * mthread_mutex_unlock *
196 *===========================================================================*/
197 int mthread_mutex_unlock(mutex)
198 mthread_mutex_t *mutex; /* Mutex that is to be unlocked */
200 /* Unlock a previously locked mutex. If there is a pending lock for this mutex
201 * by another thread, mark that thread runnable. */
203 struct __mthread_mutex *m;
205 if (mutex == NULL)
206 return(EINVAL);
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. */
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);
220 /*===========================================================================*
221 * mthread_mutex_valid *
222 *===========================================================================*/
223 #ifdef MTHREAD_STRICT
224 int mthread_mutex_valid(m)
225 mthread_mutex_t *m;
227 /* Check to see if mutex is on the list of valid mutexes */
228 struct __mthread_mutex *loopitem;
230 loopitem = vm_front;
232 while (loopitem != NULL) {
233 if (loopitem == *m)
234 return(1);
236 loopitem = loopitem->mm_next;
239 return(0);
241 #endif
243 /*===========================================================================*
244 * mthread_mutex_verify *
245 *===========================================================================*/
246 #ifdef MDEBUG
247 int mthread_mutex_verify(void)
249 /* Return true when no mutexes are in use */
250 int r = 1;
251 struct __mthread_mutex *loopitem;
253 #ifdef MTHREAD_STRICT
254 loopitem = vm_front;
256 while (loopitem != NULL) {
257 printf("mutex corruption: owner: %d\n", loopitem->mm_owner);
258 loopitem = loopitem->mm_next;
259 r = 0;
261 #endif
263 return(r);
265 #endif