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