]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_mutex.c
Libc-320.tar.gz
[apple/libc.git] / pthreads / pthread_mutex.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
27 * All Rights Reserved
28 *
29 * Permission to use, copy, modify, and distribute this software and
30 * its documentation for any purpose and without fee is hereby granted,
31 * provided that the above copyright notice appears in all copies and
32 * that both the copyright notice and this permission notice appear in
33 * supporting documentation.
34 *
35 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
36 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
37 * FOR A PARTICULAR PURPOSE.
38 *
39 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
40 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
42 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
43 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 *
45 */
46 /*
47 * MkLinux
48 */
49
50 /*
51 * POSIX Pthread Library
52 * -- Mutex variable support
53 */
54
55 #include "pthread_internals.h"
56
57 /*
58 * Destroy a mutex variable.
59 */
60 int
61 pthread_mutex_destroy(pthread_mutex_t *mutex)
62 {
63 int res;
64
65 LOCK(mutex->lock);
66 if (mutex->sig == _PTHREAD_MUTEX_SIG)
67 {
68 if (mutex->owner == (pthread_t)NULL &&
69 mutex->busy == (pthread_cond_t *)NULL)
70 {
71 mutex->sig = _PTHREAD_NO_SIG;
72 res = ESUCCESS;
73 }
74 else
75 res = EBUSY;
76 }
77 else
78 res = EINVAL;
79 UNLOCK(mutex->lock);
80 return (res);
81 }
82
83 /*
84 * Initialize a mutex variable, possibly with additional attributes.
85 */
86 static int
87 _pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
88 {
89 if (attr)
90 {
91 if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG)
92 return (EINVAL);
93 mutex->prioceiling = attr->prioceiling;
94 mutex->protocol = attr->protocol;
95 mutex->type = attr->type;
96 } else {
97 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
98 mutex->protocol = _PTHREAD_DEFAULT_PROTOCOL;
99 mutex->type = PTHREAD_MUTEX_DEFAULT;
100 }
101 mutex->lock_count = 0;
102 mutex->owner = (pthread_t)NULL;
103 mutex->next = (pthread_mutex_t *)NULL;
104 mutex->prev = (pthread_mutex_t *)NULL;
105 mutex->busy = (pthread_cond_t *)NULL;
106 mutex->waiters = 0;
107 mutex->sem = SEMAPHORE_NULL;
108 mutex->order = SEMAPHORE_NULL;
109 mutex->sig = _PTHREAD_MUTEX_SIG;
110 return (ESUCCESS);
111 }
112
113 /*
114 * Initialize a mutex variable, possibly with additional attributes.
115 * Public interface - so don't trust the lock - initialize it first.
116 */
117 int
118 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
119 {
120 LOCK_INIT(mutex->lock);
121 return (_pthread_mutex_init(mutex, attr));
122 }
123
124 /*
125 * Manage a list of mutex variables owned by a thread
126 */
127 #if defined(DEBUG)
128 static void
129 _pthread_mutex_add(pthread_mutex_t *mutex, pthread_t self)
130 {
131 pthread_mutex_t *m;
132 if (self != (pthread_t)0)
133 {
134 if ((m = self->mutexes) != (pthread_mutex_t *)NULL)
135 { /* Add to list */
136 m->prev = mutex;
137 }
138 mutex->next = m;
139 mutex->prev = (pthread_mutex_t *)NULL;
140 self->mutexes = mutex;
141 }
142 }
143
144 __private_extern__ void
145 _pthread_mutex_remove(pthread_mutex_t *mutex, pthread_t self)
146 {
147 pthread_mutex_t *n, *prev;
148 if ((n = mutex->next) != (pthread_mutex_t *)NULL)
149 {
150 n->prev = mutex->prev;
151 }
152 if ((prev = mutex->prev) != (pthread_mutex_t *)NULL)
153 {
154 prev->next = mutex->next;
155 } else
156 { /* This is the first in the list */
157 if (self != (pthread_t)0) {
158 self->mutexes = n;
159 }
160 }
161 }
162 #endif
163
164 /*
165 * Lock a mutex.
166 * TODO: Priority inheritance stuff
167 */
168 int
169 pthread_mutex_lock(pthread_mutex_t *mutex)
170 {
171 kern_return_t kern_res;
172 pthread_t self;
173 int sig = mutex->sig;
174
175 /* To provide backwards compat for apps using mutex incorrectly */
176 if ((sig != _PTHREAD_MUTEX_SIG) && (sig != _PTHREAD_MUTEX_SIG_init))
177 return(EINVAL);
178 LOCK(mutex->lock);
179 if (mutex->sig != _PTHREAD_MUTEX_SIG)
180 {
181 if (mutex->sig != _PTHREAD_MUTEX_SIG_init)
182 {
183 UNLOCK(mutex->lock);
184 return (EINVAL);
185 }
186 _pthread_mutex_init(mutex, NULL);
187 self = _PTHREAD_MUTEX_OWNER_SELF;
188 }
189 else if (mutex->type != PTHREAD_MUTEX_NORMAL)
190 {
191 self = pthread_self();
192 if (mutex->owner == self)
193 {
194 int res;
195
196 if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
197 {
198 if (mutex->lock_count < USHRT_MAX)
199 {
200 mutex->lock_count++;
201 res = ESUCCESS;
202 } else
203 res = EAGAIN;
204 } else /* PTHREAD_MUTEX_ERRORCHECK */
205 res = EDEADLK;
206 UNLOCK(mutex->lock);
207 return (res);
208 }
209 } else
210 self = _PTHREAD_MUTEX_OWNER_SELF;
211
212 if (mutex->owner != (pthread_t)NULL) {
213 if (mutex->waiters || mutex->owner != _PTHREAD_MUTEX_OWNER_SWITCHING)
214 {
215 semaphore_t sem, order;
216
217 if (++mutex->waiters == 1)
218 {
219 mutex->sem = sem = new_sem_from_pool();
220 mutex->order = order = new_sem_from_pool();
221 }
222 else
223 {
224 sem = mutex->sem;
225 order = mutex->order;
226 do {
227 PTHREAD_MACH_CALL(semaphore_wait(order), kern_res);
228 } while (kern_res == KERN_ABORTED);
229 }
230 UNLOCK(mutex->lock);
231
232 PTHREAD_MACH_CALL(semaphore_wait_signal(sem, order), kern_res);
233 while (kern_res == KERN_ABORTED)
234 {
235 PTHREAD_MACH_CALL(semaphore_wait(sem), kern_res);
236 }
237
238 LOCK(mutex->lock);
239 if (--mutex->waiters == 0)
240 {
241 PTHREAD_MACH_CALL(semaphore_wait(order), kern_res);
242 mutex->sem = mutex->order = SEMAPHORE_NULL;
243 restore_sem_to_pool(order);
244 restore_sem_to_pool(sem);
245 }
246 }
247 else if (mutex->owner == _PTHREAD_MUTEX_OWNER_SWITCHING)
248 {
249 semaphore_t sem = mutex->sem;
250 do {
251 PTHREAD_MACH_CALL(semaphore_wait(sem), kern_res);
252 } while (kern_res == KERN_ABORTED);
253 mutex->sem = SEMAPHORE_NULL;
254 restore_sem_to_pool(sem);
255 }
256 }
257
258 mutex->lock_count = 1;
259 mutex->owner = self;
260 #if defined(DEBUG)
261 _pthread_mutex_add(mutex, self);
262 #endif
263 UNLOCK(mutex->lock);
264 return (ESUCCESS);
265 }
266
267 /*
268 * Attempt to lock a mutex, but don't block if this isn't possible.
269 */
270 int
271 pthread_mutex_trylock(pthread_mutex_t *mutex)
272 {
273 kern_return_t kern_res;
274 pthread_t self;
275
276 LOCK(mutex->lock);
277 if (mutex->sig != _PTHREAD_MUTEX_SIG)
278 {
279 if (mutex->sig != _PTHREAD_MUTEX_SIG_init)
280 {
281 UNLOCK(mutex->lock);
282 return (EINVAL);
283 }
284 _pthread_mutex_init(mutex, NULL);
285 self = _PTHREAD_MUTEX_OWNER_SELF;
286 }
287 else if (mutex->type != PTHREAD_MUTEX_NORMAL)
288 {
289 self = pthread_self();
290 if (mutex->type == PTHREAD_MUTEX_RECURSIVE)
291 {
292 if (mutex->owner == self)
293 {
294 int res;
295
296 if (mutex->lock_count < USHRT_MAX)
297 {
298 mutex->lock_count++;
299 res = ESUCCESS;
300 } else
301 res = EAGAIN;
302 UNLOCK(mutex->lock);
303 return (res);
304 }
305 }
306 } else
307 self = _PTHREAD_MUTEX_OWNER_SELF;
308
309 if (mutex->owner != (pthread_t)NULL)
310 {
311 if (mutex->waiters || mutex->owner != _PTHREAD_MUTEX_OWNER_SWITCHING)
312 {
313 UNLOCK(mutex->lock);
314 return (EBUSY);
315 }
316 else if (mutex->owner == _PTHREAD_MUTEX_OWNER_SWITCHING)
317 {
318 semaphore_t sem = mutex->sem;
319
320 do {
321 PTHREAD_MACH_CALL(semaphore_wait(sem), kern_res);
322 } while (kern_res == KERN_ABORTED);
323 restore_sem_to_pool(sem);
324 mutex->sem = SEMAPHORE_NULL;
325 }
326 }
327
328 mutex->lock_count = 1;
329 mutex->owner = self;
330 #if defined(DEBUG)
331 _pthread_mutex_add(mutex, self);
332 #endif
333 UNLOCK(mutex->lock);
334 return (ESUCCESS);
335 }
336
337 /*
338 * Unlock a mutex.
339 * TODO: Priority inheritance stuff
340 */
341 int
342 pthread_mutex_unlock(pthread_mutex_t *mutex)
343 {
344 kern_return_t kern_res;
345 int waiters;
346 int sig = mutex->sig;
347
348 /* To provide backwards compat for apps using mutex incorrectly */
349
350 if ((sig != _PTHREAD_MUTEX_SIG) && (sig != _PTHREAD_MUTEX_SIG_init))
351 return(EINVAL);
352 LOCK(mutex->lock);
353 if (mutex->sig != _PTHREAD_MUTEX_SIG)
354 {
355 if (mutex->sig != _PTHREAD_MUTEX_SIG_init)
356 {
357 UNLOCK(mutex->lock);
358 return (EINVAL); /* Not a mutex variable */
359 }
360 _pthread_mutex_init(mutex, NULL);
361 } else
362
363 #if !defined(DEBUG)
364 if (mutex->type != PTHREAD_MUTEX_NORMAL)
365 #endif
366 {
367 pthread_t self = pthread_self();
368 if (mutex->owner != self)
369 {
370 #if defined(DEBUG)
371 abort();
372 #endif
373 UNLOCK(mutex->lock);
374 return EPERM;
375 } else if (mutex->type == PTHREAD_MUTEX_RECURSIVE &&
376 --mutex->lock_count)
377 {
378 UNLOCK(mutex->lock);
379 return ESUCCESS;
380 }
381 }
382
383 mutex->lock_count = 0;
384 #if defined(DEBUG)
385 _pthread_mutex_remove(mutex, mutex->owner);
386 #endif /* DEBUG */
387
388 waiters = mutex->waiters;
389 if (waiters)
390 {
391 mutex->owner = _PTHREAD_MUTEX_OWNER_SWITCHING;
392 UNLOCK(mutex->lock);
393 PTHREAD_MACH_CALL(semaphore_signal(mutex->sem), kern_res);
394 }
395 else
396 {
397 mutex->owner = (pthread_t)NULL;
398 UNLOCK(mutex->lock);
399 }
400 return (ESUCCESS);
401 }
402
403 /*
404 * Fetch the priority ceiling value from a mutex variable.
405 * Note: written as a 'helper' function to hide implementation details.
406 */
407 int
408 pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
409 int *prioceiling)
410 {
411 int res;
412
413 LOCK(mutex->lock);
414 if (mutex->sig == _PTHREAD_MUTEX_SIG)
415 {
416 *prioceiling = mutex->prioceiling;
417 res = ESUCCESS;
418 } else
419 res = EINVAL; /* Not an initialized 'attribute' structure */
420 UNLOCK(mutex->lock);
421 return (res);
422 }
423
424 /*
425 * Set the priority ceiling for a mutex.
426 * Note: written as a 'helper' function to hide implementation details.
427 */
428 int
429 pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
430 int prioceiling,
431 int *old_prioceiling)
432 {
433 int res;
434
435 LOCK(mutex->lock);
436 if (mutex->sig == _PTHREAD_MUTEX_SIG)
437 {
438 if ((prioceiling >= -999) ||
439 (prioceiling <= 999))
440 {
441 *old_prioceiling = mutex->prioceiling;
442 mutex->prioceiling = prioceiling;
443 res = ESUCCESS;
444 } else
445 res = EINVAL; /* Invalid parameter */
446 } else
447 res = EINVAL; /* Not an initialized 'attribute' structure */
448 UNLOCK(mutex->lock);
449 return (res);
450 }
451
452 /*
453 * Destroy a mutex attribute structure.
454 */
455 int
456 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
457 {
458 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
459 return (ESUCCESS);
460 }
461
462 /*
463 * Get the priority ceiling value from a mutex attribute structure.
464 * Note: written as a 'helper' function to hide implementation details.
465 */
466 int
467 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
468 int *prioceiling)
469 {
470 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
471 {
472 *prioceiling = attr->prioceiling;
473 return (ESUCCESS);
474 } else
475 {
476 return (EINVAL); /* Not an initialized 'attribute' structure */
477 }
478 }
479
480 /*
481 * Get the mutex 'protocol' value from a mutex attribute structure.
482 * Note: written as a 'helper' function to hide implementation details.
483 */
484 int
485 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
486 int *protocol)
487 {
488 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
489 {
490 *protocol = attr->protocol;
491 return (ESUCCESS);
492 } else
493 {
494 return (EINVAL); /* Not an initialized 'attribute' structure */
495 }
496 }
497 /*
498 * Get the mutex 'type' value from a mutex attribute structure.
499 * Note: written as a 'helper' function to hide implementation details.
500 */
501 int
502 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr,
503 int *type)
504 {
505 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
506 {
507 *type = attr->type;
508 return (ESUCCESS);
509 } else
510 {
511 return (EINVAL); /* Not an initialized 'attribute' structure */
512 }
513 }
514
515 /*
516 *
517 */
518 int
519 pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
520 {
521 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
522 {
523 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
524 return (ESUCCESS);
525 } else
526 {
527 return (EINVAL); /* Not an initialized 'attribute' structure */
528 }
529 }
530
531 /*
532 * Initialize a mutex attribute structure to system defaults.
533 */
534 int
535 pthread_mutexattr_init(pthread_mutexattr_t *attr)
536 {
537 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
538 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
539 attr->type = PTHREAD_MUTEX_DEFAULT;
540 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
541 return (ESUCCESS);
542 }
543
544 /*
545 * Set the priority ceiling value in a mutex attribute structure.
546 * Note: written as a 'helper' function to hide implementation details.
547 */
548 int
549 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
550 int prioceiling)
551 {
552 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
553 {
554 if ((prioceiling >= -999) ||
555 (prioceiling <= 999))
556 {
557 attr->prioceiling = prioceiling;
558 return (ESUCCESS);
559 } else
560 {
561 return (EINVAL); /* Invalid parameter */
562 }
563 } else
564 {
565 return (EINVAL); /* Not an initialized 'attribute' structure */
566 }
567 }
568
569 /*
570 * Set the mutex 'protocol' value in a mutex attribute structure.
571 * Note: written as a 'helper' function to hide implementation details.
572 */
573 int
574 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
575 int protocol)
576 {
577 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
578 {
579 if ((protocol == PTHREAD_PRIO_NONE) ||
580 (protocol == PTHREAD_PRIO_INHERIT) ||
581 (protocol == PTHREAD_PRIO_PROTECT))
582 {
583 attr->protocol = protocol;
584 return (ESUCCESS);
585 } else
586 {
587 return (EINVAL); /* Invalid parameter */
588 }
589 } else
590 {
591 return (EINVAL); /* Not an initialized 'attribute' structure */
592 }
593 }
594 /*
595 * Set the mutex 'type' value in a mutex attribute structure.
596 * Note: written as a 'helper' function to hide implementation details.
597 */
598 int
599 pthread_mutexattr_settype(pthread_mutexattr_t *attr,
600 int type)
601 {
602 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
603 {
604 if ((type == PTHREAD_MUTEX_NORMAL) ||
605 (type == PTHREAD_MUTEX_ERRORCHECK) ||
606 (type == PTHREAD_MUTEX_RECURSIVE) ||
607 (type == PTHREAD_MUTEX_DEFAULT))
608 {
609 attr->type = type;
610 return (ESUCCESS);
611 } else
612 {
613 return (EINVAL); /* Invalid parameter */
614 }
615 } else
616 {
617 return (EINVAL); /* Not an initialized 'attribute' structure */
618 }
619 }
620
621 /*
622 *
623 */
624 int
625 pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
626 {
627 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
628 {
629 if (pshared == PTHREAD_PROCESS_PRIVATE)
630 {
631 /* attr->pshared = protocol; */
632 return (ESUCCESS);
633 } else
634 {
635 return (EINVAL); /* Invalid parameter */
636 }
637 } else
638 {
639 return (EINVAL); /* Not an initialized 'attribute' structure */
640 }
641 }
642
643 int mutex_try_lock(int *x) {
644 return _spin_lock_try((pthread_lock_t *)x);
645 }
646
647 void mutex_wait_lock(int *x) {
648 for (;;) {
649 if( _spin_lock_try((pthread_lock_t *)x)) {
650 return;
651 }
652 swtch_pri(0);
653 }
654 }
655
656 void
657 cthread_yield(void)
658 {
659 sched_yield();
660 }
661
662 void
663 pthread_yield_np (void)
664 {
665 sched_yield();
666 }
667