2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
27 * Permission to use, copy, modify, and distribute this software and
28 * its documentation for any purpose and without fee is hereby granted,
29 * provided that the above copyright notice appears in all copies and
30 * that both the copyright notice and this permission notice appear in
31 * supporting documentation.
33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 * POSIX Pthread Library
50 * -- Mutex variable support
53 #include "pthread_internals.h"
56 * Destroy a mutex variable.
59 pthread_mutex_destroy(pthread_mutex_t
*mutex
)
64 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
66 if (mutex
->owner
== (pthread_t
)NULL
&&
67 mutex
->busy
== (pthread_cond_t
*)NULL
)
69 mutex
->sig
= _PTHREAD_NO_SIG
;
82 * Initialize a mutex variable, possibly with additional attributes.
85 _pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
89 if (attr
->sig
!= _PTHREAD_MUTEX_ATTR_SIG
)
91 mutex
->prioceiling
= attr
->prioceiling
;
92 mutex
->protocol
= attr
->protocol
;
93 mutex
->type
= attr
->type
;
95 mutex
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
96 mutex
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
97 mutex
->type
= PTHREAD_MUTEX_DEFAULT
;
99 mutex
->lock_count
= 0;
100 mutex
->owner
= (pthread_t
)NULL
;
101 mutex
->next
= (pthread_mutex_t
*)NULL
;
102 mutex
->prev
= (pthread_mutex_t
*)NULL
;
103 mutex
->busy
= (pthread_cond_t
*)NULL
;
105 mutex
->sem
= SEMAPHORE_NULL
;
106 mutex
->order
= SEMAPHORE_NULL
;
107 mutex
->sig
= _PTHREAD_MUTEX_SIG
;
112 * Initialize a mutex variable, possibly with additional attributes.
113 * Public interface - so don't trust the lock - initialize it first.
116 pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*attr
)
118 LOCK_INIT(mutex
->lock
);
119 return (_pthread_mutex_init(mutex
, attr
));
123 * Manage a list of mutex variables owned by a thread
127 _pthread_mutex_add(pthread_mutex_t
*mutex
, pthread_t self
)
130 if (self
!= (pthread_t
)0)
132 if ((m
= self
->mutexes
) != (pthread_mutex_t
*)NULL
)
137 mutex
->prev
= (pthread_mutex_t
*)NULL
;
138 self
->mutexes
= mutex
;
142 __private_extern__
void
143 _pthread_mutex_remove(pthread_mutex_t
*mutex
, pthread_t self
)
145 pthread_mutex_t
*n
, *prev
;
146 if ((n
= mutex
->next
) != (pthread_mutex_t
*)NULL
)
148 n
->prev
= mutex
->prev
;
150 if ((prev
= mutex
->prev
) != (pthread_mutex_t
*)NULL
)
152 prev
->next
= mutex
->next
;
154 { /* This is the first in the list */
155 if (self
!= (pthread_t
)0) {
164 * TODO: Priority inheritance stuff
167 pthread_mutex_lock(pthread_mutex_t
*mutex
)
169 kern_return_t kern_res
;
171 int sig
= mutex
->sig
;
173 /* To provide backwards compat for apps using mutex incorrectly */
174 if ((sig
!= _PTHREAD_MUTEX_SIG
) && (sig
!= _PTHREAD_MUTEX_SIG_init
))
177 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
179 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
184 _pthread_mutex_init(mutex
, NULL
);
185 self
= _PTHREAD_MUTEX_OWNER_SELF
;
187 else if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
189 self
= pthread_self();
190 if (mutex
->owner
== self
)
194 if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)
196 if (mutex
->lock_count
< USHRT_MAX
)
202 } else /* PTHREAD_MUTEX_ERRORCHECK */
208 self
= _PTHREAD_MUTEX_OWNER_SELF
;
210 if (mutex
->owner
!= (pthread_t
)NULL
) {
211 if (mutex
->waiters
|| mutex
->owner
!= _PTHREAD_MUTEX_OWNER_SWITCHING
)
213 semaphore_t sem
, order
;
215 if (++mutex
->waiters
== 1)
217 mutex
->sem
= sem
= new_sem_from_pool();
218 mutex
->order
= order
= new_sem_from_pool();
223 order
= mutex
->order
;
225 PTHREAD_MACH_CALL(semaphore_wait(order
), kern_res
);
226 } while (kern_res
== KERN_ABORTED
);
230 PTHREAD_MACH_CALL(semaphore_wait_signal(sem
, order
), kern_res
);
231 while (kern_res
== KERN_ABORTED
)
233 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
237 if (--mutex
->waiters
== 0)
239 PTHREAD_MACH_CALL(semaphore_wait(order
), kern_res
);
240 mutex
->sem
= mutex
->order
= SEMAPHORE_NULL
;
241 restore_sem_to_pool(order
);
242 restore_sem_to_pool(sem
);
245 else if (mutex
->owner
== _PTHREAD_MUTEX_OWNER_SWITCHING
)
247 semaphore_t sem
= mutex
->sem
;
249 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
250 } while (kern_res
== KERN_ABORTED
);
251 mutex
->sem
= SEMAPHORE_NULL
;
252 restore_sem_to_pool(sem
);
256 mutex
->lock_count
= 1;
259 _pthread_mutex_add(mutex
, self
);
266 * Attempt to lock a mutex, but don't block if this isn't possible.
269 pthread_mutex_trylock(pthread_mutex_t
*mutex
)
271 kern_return_t kern_res
;
275 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
277 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
282 _pthread_mutex_init(mutex
, NULL
);
283 self
= _PTHREAD_MUTEX_OWNER_SELF
;
285 else if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
287 self
= pthread_self();
288 if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
)
290 if (mutex
->owner
== self
)
294 if (mutex
->lock_count
< USHRT_MAX
)
305 self
= _PTHREAD_MUTEX_OWNER_SELF
;
307 if (mutex
->owner
!= (pthread_t
)NULL
)
309 if (mutex
->waiters
|| mutex
->owner
!= _PTHREAD_MUTEX_OWNER_SWITCHING
)
314 else if (mutex
->owner
== _PTHREAD_MUTEX_OWNER_SWITCHING
)
316 semaphore_t sem
= mutex
->sem
;
319 PTHREAD_MACH_CALL(semaphore_wait(sem
), kern_res
);
320 } while (kern_res
== KERN_ABORTED
);
321 restore_sem_to_pool(sem
);
322 mutex
->sem
= SEMAPHORE_NULL
;
326 mutex
->lock_count
= 1;
329 _pthread_mutex_add(mutex
, self
);
337 * TODO: Priority inheritance stuff
340 pthread_mutex_unlock(pthread_mutex_t
*mutex
)
342 kern_return_t kern_res
;
344 int sig
= mutex
->sig
;
346 /* To provide backwards compat for apps using mutex incorrectly */
348 if ((sig
!= _PTHREAD_MUTEX_SIG
) && (sig
!= _PTHREAD_MUTEX_SIG_init
))
351 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG
)
353 if (mutex
->sig
!= _PTHREAD_MUTEX_SIG_init
)
356 return (EINVAL
); /* Not a mutex variable */
358 _pthread_mutex_init(mutex
, NULL
);
362 if (mutex
->type
!= PTHREAD_MUTEX_NORMAL
)
365 pthread_t self
= pthread_self();
366 if (mutex
->owner
!= self
)
373 } else if (mutex
->type
== PTHREAD_MUTEX_RECURSIVE
&&
381 mutex
->lock_count
= 0;
383 _pthread_mutex_remove(mutex
, mutex
->owner
);
386 waiters
= mutex
->waiters
;
389 mutex
->owner
= _PTHREAD_MUTEX_OWNER_SWITCHING
;
391 PTHREAD_MACH_CALL(semaphore_signal(mutex
->sem
), kern_res
);
395 mutex
->owner
= (pthread_t
)NULL
;
402 * Fetch the priority ceiling value from a mutex variable.
403 * Note: written as a 'helper' function to hide implementation details.
406 pthread_mutex_getprioceiling(const pthread_mutex_t
*mutex
,
412 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
414 *prioceiling
= mutex
->prioceiling
;
417 res
= EINVAL
; /* Not an initialized 'attribute' structure */
423 * Set the priority ceiling for a mutex.
424 * Note: written as a 'helper' function to hide implementation details.
427 pthread_mutex_setprioceiling(pthread_mutex_t
*mutex
,
429 int *old_prioceiling
)
434 if (mutex
->sig
== _PTHREAD_MUTEX_SIG
)
436 if ((prioceiling
>= -999) ||
437 (prioceiling
<= 999))
439 *old_prioceiling
= mutex
->prioceiling
;
440 mutex
->prioceiling
= prioceiling
;
443 res
= EINVAL
; /* Invalid parameter */
445 res
= EINVAL
; /* Not an initialized 'attribute' structure */
451 * Destroy a mutex attribute structure.
454 pthread_mutexattr_destroy(pthread_mutexattr_t
*attr
)
456 attr
->sig
= _PTHREAD_NO_SIG
; /* Uninitialized */
461 * Get the priority ceiling value from a mutex attribute structure.
462 * Note: written as a 'helper' function to hide implementation details.
465 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t
*attr
,
468 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
470 *prioceiling
= attr
->prioceiling
;
474 return (EINVAL
); /* Not an initialized 'attribute' structure */
479 * Get the mutex 'protocol' value from a mutex attribute structure.
480 * Note: written as a 'helper' function to hide implementation details.
483 pthread_mutexattr_getprotocol(const pthread_mutexattr_t
*attr
,
486 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
488 *protocol
= attr
->protocol
;
492 return (EINVAL
); /* Not an initialized 'attribute' structure */
496 * Get the mutex 'type' value from a mutex attribute structure.
497 * Note: written as a 'helper' function to hide implementation details.
500 pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
,
503 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
509 return (EINVAL
); /* Not an initialized 'attribute' structure */
517 pthread_mutexattr_getpshared(const pthread_mutexattr_t
*attr
, int *pshared
)
519 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
521 *pshared
= (int)PTHREAD_PROCESS_PRIVATE
;
525 return (EINVAL
); /* Not an initialized 'attribute' structure */
530 * Initialize a mutex attribute structure to system defaults.
533 pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
535 attr
->prioceiling
= _PTHREAD_DEFAULT_PRIOCEILING
;
536 attr
->protocol
= _PTHREAD_DEFAULT_PROTOCOL
;
537 attr
->type
= PTHREAD_MUTEX_DEFAULT
;
538 attr
->sig
= _PTHREAD_MUTEX_ATTR_SIG
;
543 * Set the priority ceiling value in a mutex attribute structure.
544 * Note: written as a 'helper' function to hide implementation details.
547 pthread_mutexattr_setprioceiling(pthread_mutexattr_t
*attr
,
550 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
552 if ((prioceiling
>= -999) ||
553 (prioceiling
<= 999))
555 attr
->prioceiling
= prioceiling
;
559 return (EINVAL
); /* Invalid parameter */
563 return (EINVAL
); /* Not an initialized 'attribute' structure */
568 * Set the mutex 'protocol' value in a mutex attribute structure.
569 * Note: written as a 'helper' function to hide implementation details.
572 pthread_mutexattr_setprotocol(pthread_mutexattr_t
*attr
,
575 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
577 if ((protocol
== PTHREAD_PRIO_NONE
) ||
578 (protocol
== PTHREAD_PRIO_INHERIT
) ||
579 (protocol
== PTHREAD_PRIO_PROTECT
))
581 attr
->protocol
= protocol
;
585 return (EINVAL
); /* Invalid parameter */
589 return (EINVAL
); /* Not an initialized 'attribute' structure */
593 * Set the mutex 'type' value in a mutex attribute structure.
594 * Note: written as a 'helper' function to hide implementation details.
597 pthread_mutexattr_settype(pthread_mutexattr_t
*attr
,
600 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
602 if ((type
== PTHREAD_MUTEX_NORMAL
) ||
603 (type
== PTHREAD_MUTEX_ERRORCHECK
) ||
604 (type
== PTHREAD_MUTEX_RECURSIVE
) ||
605 (type
== PTHREAD_MUTEX_DEFAULT
))
611 return (EINVAL
); /* Invalid parameter */
615 return (EINVAL
); /* Not an initialized 'attribute' structure */
623 pthread_mutexattr_setpshared(pthread_mutexattr_t
*attr
, int pshared
)
625 if (attr
->sig
== _PTHREAD_MUTEX_ATTR_SIG
)
627 if (pshared
== PTHREAD_PROCESS_PRIVATE
)
629 /* attr->pshared = protocol; */
633 return (EINVAL
); /* Invalid parameter */
637 return (EINVAL
); /* Not an initialized 'attribute' structure */
641 int mutex_try_lock(int *x
) {
642 return _spin_lock_try((pthread_lock_t
*)x
);
645 void mutex_wait_lock(int *x
) {
647 if( _spin_lock_try((pthread_lock_t
*)x
)) {
661 pthread_yield_np (void)