]> git.saurik.com Git - apple/libc.git/blob - pthreads.subproj/pthread_mutex.c
1276e60f8572fa62d713c16415130dbe86035e9c
[apple/libc.git] / pthreads.subproj / pthread_mutex.c
1 /*
2 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 *
21 */
22 /*
23 * MkLinux
24 */
25
26 /*
27 * POSIX Pthread Library
28 * -- Mutex variable support
29 */
30
31 #include "pthread_internals.h"
32
33 /*
34 * Destroy a mutex variable.
35 */
36 int
37 pthread_mutex_destroy(pthread_mutex_t *mutex)
38 {
39 if (mutex->sig != _PTHREAD_MUTEX_SIG)
40 return (EINVAL);
41 if ((mutex->owner != (pthread_t)NULL) ||
42 (mutex->busy != (pthread_cond_t *)NULL))
43 return (EBUSY);
44 mutex->sig = _PTHREAD_NO_SIG;
45 return (ESUCCESS);
46 }
47
48 /*
49 * Initialize a mutex variable, possibly with additional attributes.
50 */
51 int
52 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
53 {
54 LOCK_INIT(mutex->lock);
55 mutex->sig = _PTHREAD_MUTEX_SIG;
56 if (attr)
57 {
58 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG)
59 return (EINVAL);
60 mutex->prioceiling = attr->prioceiling;
61 mutex->protocol = attr->protocol;
62 } else
63 {
64 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
65 mutex->protocol = _PTHREAD_DEFAULT_PROTOCOL;
66 }
67 mutex->owner = (pthread_t)NULL;
68 mutex->next = (pthread_mutex_t *)NULL;
69 mutex->prev = (pthread_mutex_t *)NULL;
70 mutex->busy = (pthread_cond_t *)NULL;
71 mutex->waiters = 0;
72 mutex->cond_lock = 0;
73 mutex->sem = MACH_PORT_NULL;
74 return (ESUCCESS);
75 }
76
77 /*
78 * Manage a list of mutex variables owned by a thread
79 */
80 #if defined(DEBUG)
81 static void
82 _pthread_mutex_add(pthread_mutex_t *mutex)
83 {
84 pthread_mutex_t *m;
85 pthread_t self = pthread_self();
86 if (self != (pthread_t)0) {
87 mutex->owner = self;
88 if ((m = self->mutexes) != (pthread_mutex_t *)NULL)
89 { /* Add to list */
90 m->prev = mutex;
91 }
92 mutex->next = m;
93 mutex->prev = (pthread_mutex_t *)NULL;
94 self->mutexes = mutex;
95 }
96 }
97
98 static void
99 _pthread_mutex_remove(pthread_mutex_t *mutex, pthread_t self)
100 {
101 pthread_mutex_t *n, *prev;
102 if ((n = mutex->next) != (pthread_mutex_t *)NULL)
103 {
104 n->prev = mutex->prev;
105 }
106 if ((prev = mutex->prev) != (pthread_mutex_t *)NULL)
107 {
108 prev->next = mutex->next;
109 } else
110 { /* This is the first in the list */
111 if (self != (pthread_t)0) {
112 self->mutexes = n;
113 }
114 }
115 mutex->owner = (pthread_t)NULL;
116 }
117 #endif
118
119 /*
120 * Lock a mutex.
121 * TODO: Priority inheritance stuff
122 */
123 int
124 pthread_mutex_lock(pthread_mutex_t *mutex)
125 {
126 kern_return_t kern_res;
127
128 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
129 {
130 int res;
131 if (res = pthread_mutex_init(mutex, NULL))
132 return (res);
133 }
134 if (mutex->sig != _PTHREAD_MUTEX_SIG)
135 return (EINVAL); /* Not a mutex variable */
136 LOCK(mutex->lock);
137 if (mutex->waiters || (mutex->owner != (pthread_t)NULL))
138 {
139 mutex->waiters++;
140 if (mutex->sem == MACH_PORT_NULL) {
141 mutex->sem = new_sem_from_pool();
142 }
143 UNLOCK(mutex->lock);
144 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
145 LOCK(mutex->lock);
146 mutex->waiters--;
147 if (mutex->waiters == 0) {
148 restore_sem_to_pool(mutex->sem);
149 mutex->sem = MACH_PORT_NULL;
150 }
151 if (mutex->cond_lock) {
152 mutex->cond_lock = 0;
153 }
154 }
155 #if defined(DEBUG)
156 _pthread_mutex_add(mutex);
157 #else
158 mutex->owner = (pthread_t)0x12141968;
159 #endif
160 UNLOCK(mutex->lock);
161 return (ESUCCESS);
162 }
163
164 /*
165 * Attempt to lock a mutex, but don't block if this isn't possible.
166 */
167 int
168 pthread_mutex_trylock(pthread_mutex_t *mutex)
169 {
170 kern_return_t kern_res;
171
172 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
173 {
174 int res;
175 if (res = pthread_mutex_init(mutex, NULL))
176 return (res);
177 }
178 if (mutex->sig != _PTHREAD_MUTEX_SIG)
179 return (EINVAL); /* Not a mutex variable */
180 if (!TRY_LOCK(mutex->lock)) {
181 return (EBUSY);
182 }
183 if (mutex->waiters ||
184 ((mutex->owner != (pthread_t)NULL) && (mutex->cond_lock == 0)))
185 {
186 UNLOCK(mutex->lock);
187 return (EBUSY);
188 } else
189 {
190 #if defined(DEBUG)
191 _pthread_mutex_add(mutex);
192 #else
193 mutex->owner = (pthread_t)0x12141968;
194 #endif
195 if (mutex->cond_lock) {
196 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
197 mutex->cond_lock = 0;
198 restore_sem_to_pool(mutex->sem);
199 mutex->sem = MACH_PORT_NULL;
200 }
201 UNLOCK(mutex->lock);
202 return (ESUCCESS);
203 }
204 }
205
206 /*
207 * Unlock a mutex.
208 * TODO: Priority inheritance stuff
209 */
210 int
211 pthread_mutex_unlock(pthread_mutex_t *mutex)
212 {
213 kern_return_t kern_res;
214 int waiters;
215 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
216 {
217 int res;
218 if (res = pthread_mutex_init(mutex, NULL))
219 return (res);
220 }
221 if (mutex->sig != _PTHREAD_MUTEX_SIG)
222 return (EINVAL); /* Not a mutex variable */
223 LOCK(mutex->lock);
224 #if defined(DEBUG)
225 if (mutex->owner != pthread_self())
226 {
227 UNLOCK(mutex->lock);
228 abort();
229 return (EPERM);
230 } else
231 #endif
232 {
233 #if defined(DEBUG)
234 _pthread_mutex_remove(mutex, mutex->owner);
235 #else
236 mutex->owner = (pthread_t)NULL;
237 #endif
238 waiters = mutex->waiters;
239 UNLOCK(mutex->lock);
240 if (waiters)
241 {
242 PTHREAD_MACH_CALL(semaphore_signal(mutex->sem), kern_res);
243 }
244 return (ESUCCESS);
245 }
246 }
247
248 /*
249 * Fetch the priority ceiling value from a mutex variable.
250 * Note: written as a 'helper' function to hide implementation details.
251 */
252 int
253 pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
254 int *prioceiling)
255 {
256 if (mutex->sig == _PTHREAD_MUTEX_SIG)
257 {
258 *prioceiling = mutex->prioceiling;
259 return (ESUCCESS);
260 } else
261 {
262 return (EINVAL); /* Not an initialized 'attribute' structure */
263 }
264 }
265
266 /*
267 * Set the priority ceiling for a mutex.
268 * Note: written as a 'helper' function to hide implementation details.
269 */
270 int
271 pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
272 int prioceiling,
273 int *old_prioceiling)
274 {
275 if (mutex->sig == _PTHREAD_MUTEX_SIG)
276 {
277 if ((prioceiling >= -999) ||
278 (prioceiling <= 999))
279 {
280 *old_prioceiling = mutex->prioceiling;
281 mutex->prioceiling = prioceiling;
282 return (ESUCCESS);
283 } else
284 {
285 return (EINVAL); /* Invalid parameter */
286 }
287 } else
288 {
289 return (EINVAL); /* Not an initialized 'attribute' structure */
290 }
291 }
292
293 /*
294 * Destroy a mutex attribute structure.
295 */
296 int
297 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
298 {
299 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
300 return (ESUCCESS);
301 }
302
303 /*
304 * Get the priority ceiling value from a mutex attribute structure.
305 * Note: written as a 'helper' function to hide implementation details.
306 */
307 int
308 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
309 int *prioceiling)
310 {
311 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
312 {
313 *prioceiling = attr->prioceiling;
314 return (ESUCCESS);
315 } else
316 {
317 return (EINVAL); /* Not an initialized 'attribute' structure */
318 }
319 }
320
321 /*
322 * Get the mutex 'protocol' value from a mutex attribute structure.
323 * Note: written as a 'helper' function to hide implementation details.
324 */
325 int
326 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
327 int *protocol)
328 {
329 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
330 {
331 *protocol = attr->protocol;
332 return (ESUCCESS);
333 } else
334 {
335 return (EINVAL); /* Not an initialized 'attribute' structure */
336 }
337 }
338
339 /*
340 * Initialize a mutex attribute structure to system defaults.
341 */
342 int
343 pthread_mutexattr_init(pthread_mutexattr_t *attr)
344 {
345 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
346 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
347 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
348 return (ESUCCESS);
349 }
350
351 /*
352 * Set the priority ceiling value in a mutex attribute structure.
353 * Note: written as a 'helper' function to hide implementation details.
354 */
355 int
356 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
357 int prioceiling)
358 {
359 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
360 {
361 if ((prioceiling >= -999) ||
362 (prioceiling <= 999))
363 {
364 attr->prioceiling = prioceiling;
365 return (ESUCCESS);
366 } else
367 {
368 return (EINVAL); /* Invalid parameter */
369 }
370 } else
371 {
372 return (EINVAL); /* Not an initialized 'attribute' structure */
373 }
374 }
375
376 /*
377 * Set the mutex 'protocol' value in a mutex attribute structure.
378 * Note: written as a 'helper' function to hide implementation details.
379 */
380 int
381 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
382 int protocol)
383 {
384 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
385 {
386 if ((protocol == PTHREAD_PRIO_NONE) ||
387 (protocol == PTHREAD_PRIO_INHERIT) ||
388 (protocol == PTHREAD_PRIO_PROTECT))
389 {
390 attr->protocol = protocol;
391 return (ESUCCESS);
392 } else
393 {
394 return (EINVAL); /* Invalid parameter */
395 }
396 } else
397 {
398 return (EINVAL); /* Not an initialized 'attribute' structure */
399 }
400 }
401
402 int mutex_try_lock(int *x) {
403 return _spin_lock_try((pthread_lock_t *)x);
404 }
405
406 void mutex_wait_lock(int *x) {
407 for (;;) {
408 if( _spin_lock_try((pthread_lock_t *)x)) {
409 return;
410 }
411 swtch_pri(0);
412 }
413 }
414
415 void cthread_yield(void) {
416 sched_yield();
417 }
418