]> git.saurik.com Git - apple/libc.git/blob - pthreads/pthread_mutex.c
c82a6925eca564fdea1d98f117792151fa91ba57
[apple/libc.git] / pthreads / 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 mutex->type = attr->type;
63 if ((mutex->type == PTHREAD_MUTEX_DEFAULT) || (mutex->type == PTHREAD_MUTEX_NORMAL))
64 mutex->def = 1;
65 else
66 mutex->def = 0;
67 } else {
68 mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
69 mutex->protocol = _PTHREAD_DEFAULT_PROTOCOL;
70 mutex->type = PTHREAD_MUTEX_DEFAULT;
71 mutex->def = 1;
72 }
73 mutex->lock_count = 0;
74 mutex->owner = (pthread_t)NULL;
75 mutex->next = (pthread_mutex_t *)NULL;
76 mutex->prev = (pthread_mutex_t *)NULL;
77 mutex->busy = (pthread_cond_t *)NULL;
78 mutex->waiters = 0;
79 mutex->cond_lock = 0;
80 mutex->sem = MACH_PORT_NULL;
81 return (ESUCCESS);
82 }
83
84 /*
85 * Manage a list of mutex variables owned by a thread
86 */
87 #if defined(DEBUG)
88 static void
89 _pthread_mutex_add(pthread_mutex_t *mutex, pthread_t self)
90 {
91 pthread_mutex_t *m;
92 if (self != (pthread_t)0) {
93 if ((m = self->mutexes) != (pthread_mutex_t *)NULL)
94 { /* Add to list */
95 m->prev = mutex;
96 }
97 mutex->next = m;
98 mutex->prev = (pthread_mutex_t *)NULL;
99 self->mutexes = mutex;
100 }
101 }
102
103 static void
104 _pthread_mutex_remove(pthread_mutex_t *mutex, pthread_t self)
105 {
106 pthread_mutex_t *n, *prev;
107 if ((n = mutex->next) != (pthread_mutex_t *)NULL)
108 {
109 n->prev = mutex->prev;
110 }
111 if ((prev = mutex->prev) != (pthread_mutex_t *)NULL)
112 {
113 prev->next = mutex->next;
114 } else
115 { /* This is the first in the list */
116 if (self != (pthread_t)0) {
117 self->mutexes = n;
118 }
119 }
120 }
121 #endif
122
123 /*
124 * Lock a mutex.
125 * TODO: Priority inheritance stuff
126 */
127 int
128 pthread_mutex_lock(pthread_mutex_t *mutex)
129 {
130 kern_return_t kern_res;
131 pthread_t self;
132 int slowpath;
133
134 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
135 {
136 int res;
137 if (res = pthread_mutex_init(mutex, NULL))
138 return (res);
139 }
140 if (mutex->sig != _PTHREAD_MUTEX_SIG)
141 return (EINVAL); /* Not a mutex variable */
142
143 #if !defined(DEBUG)
144 if (mutex->def) {
145 slowpath = 0;
146 self = (pthread_t)0x12141968;
147 } else
148 #endif /* DEBUG */
149 {
150 slowpath = 1;
151 self = pthread_self();
152 }
153
154 LOCK(mutex->lock);
155
156 if (mutex->waiters || (mutex->owner != (pthread_t)NULL))
157 {
158 if(slowpath && (mutex->owner == self)) {
159 if(mutex->type == PTHREAD_MUTEX_ERRORCHECK ) {
160 UNLOCK(mutex->lock);
161 return(EDEADLK);
162 } else if (mutex->type == PTHREAD_MUTEX_RECURSIVE ) {
163 if (mutex->lock_count >= USHRT_MAX){
164 UNLOCK(mutex->lock);
165 return(EAGAIN);
166 }
167 mutex->lock_count++;
168 UNLOCK(mutex->lock);
169 return(ESUCCESS);
170 }
171 }
172 mutex->waiters++;
173 if (mutex->sem == MACH_PORT_NULL) {
174 mutex->sem = new_sem_from_pool();
175 }
176 UNLOCK(mutex->lock);
177 do {
178 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
179 } while (kern_res == KERN_ABORTED);
180 LOCK(mutex->lock);
181 mutex->waiters--;
182 if (mutex->waiters == 0) {
183 restore_sem_to_pool(mutex->sem);
184 mutex->sem = MACH_PORT_NULL;
185 }
186 if (mutex->cond_lock) {
187 mutex->cond_lock = 0;
188 }
189 }
190 #if defined(DEBUG)
191 _pthread_mutex_add(mutex, self);
192 #endif
193 mutex->owner = self;
194 if (slowpath && (mutex->type == PTHREAD_MUTEX_RECURSIVE))
195 mutex->lock_count = 1;
196 UNLOCK(mutex->lock);
197 return (ESUCCESS);
198 }
199
200 /*
201 * Attempt to lock a mutex, but don't block if this isn't possible.
202 */
203 int
204 pthread_mutex_trylock(pthread_mutex_t *mutex)
205 {
206 kern_return_t kern_res;
207 pthread_t self;
208 int slowpath;
209
210 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
211 {
212 int res;
213 if (res = pthread_mutex_init(mutex, NULL))
214 return (res);
215 }
216 if (mutex->sig != _PTHREAD_MUTEX_SIG)
217 return (EINVAL); /* Not a mutex variable */
218
219 #if !defined(DEBUG)
220 if (mutex->def) {
221 slowpath = 0;
222 self = (pthread_t)0x12141968;
223 } else
224 #endif /* DEBUG */
225 {
226 slowpath = 1;
227 self = pthread_self();
228 }
229
230 if (!TRY_LOCK(mutex->lock)) {
231 return (EBUSY);
232 }
233
234 if(slowpath && (mutex->owner == self) && (mutex->type == PTHREAD_MUTEX_RECURSIVE )) {
235 if (mutex->lock_count >= USHRT_MAX) {
236 UNLOCK(mutex->lock);
237 return(EAGAIN);
238 }
239 mutex->lock_count++;
240 UNLOCK(mutex->lock);
241 return(ESUCCESS);
242 }
243
244 if (mutex->waiters ||
245 ((mutex->owner != (pthread_t)NULL) && (mutex->cond_lock == 0)))
246 {
247 UNLOCK(mutex->lock);
248 return (EBUSY);
249 } else {
250 #if defined(DEBUG)
251 _pthread_mutex_add(mutex, self);
252 #endif
253 mutex->owner = (pthread_t)self;
254 if (mutex->cond_lock) {
255 PTHREAD_MACH_CALL(semaphore_wait(mutex->sem), kern_res);
256 mutex->cond_lock = 0;
257 restore_sem_to_pool(mutex->sem);
258 mutex->sem = MACH_PORT_NULL;
259 }
260 if (slowpath && (mutex->type == PTHREAD_MUTEX_RECURSIVE))
261 mutex->lock_count = 1;
262 UNLOCK(mutex->lock);
263 return (ESUCCESS);
264 }
265 }
266
267 /*
268 * Unlock a mutex.
269 * TODO: Priority inheritance stuff
270 */
271 int
272 pthread_mutex_unlock(pthread_mutex_t *mutex)
273 {
274 kern_return_t kern_res;
275 int waiters;
276 pthread_t self;
277 int slowpath;
278
279 if (mutex->sig == _PTHREAD_MUTEX_SIG_init)
280 {
281 int res;
282 if (res = pthread_mutex_init(mutex, NULL))
283 return (res);
284 }
285 if (mutex->sig != _PTHREAD_MUTEX_SIG)
286 return (EINVAL); /* Not a mutex variable */
287
288 #if !defined(DEBUG)
289 if (mutex->def) {
290 slowpath = 0;
291 self = (pthread_t)0x12141968;
292 } else
293 #endif /* DEBUG */
294 {
295 slowpath = 1;
296 self = pthread_self();
297 }
298
299 LOCK(mutex->lock);
300
301 #if defined(DEBUG)
302 if (mutex->owner != self)
303 #else
304 if (slowpath
305 && ((mutex->type == PTHREAD_MUTEX_ERRORCHECK )
306 || (mutex->type == PTHREAD_MUTEX_RECURSIVE ))
307 && (mutex->owner != self))
308 #endif /* DEBUG */
309 {
310 UNLOCK(mutex->lock);
311 #if defined(DEBUG)
312 abort();
313 #endif
314 return(EPERM);
315 }
316
317 if (slowpath && (mutex->type == PTHREAD_MUTEX_RECURSIVE) && --mutex->lock_count) {
318 UNLOCK(mutex->lock);
319 return (ESUCCESS);
320
321 } else {
322 #if defined(DEBUG)
323 _pthread_mutex_remove(mutex, mutex->owner);
324 #endif /* DEBUG */
325 waiters = mutex->waiters;
326 mutex->owner = (pthread_t)NULL;
327 UNLOCK(mutex->lock);
328 if (waiters)
329 {
330 PTHREAD_MACH_CALL(semaphore_signal(mutex->sem), kern_res);
331 }
332 return (ESUCCESS);
333
334 }
335 }
336
337 /*
338 * Fetch the priority ceiling value from a mutex variable.
339 * Note: written as a 'helper' function to hide implementation details.
340 */
341 int
342 pthread_mutex_getprioceiling(const pthread_mutex_t *mutex,
343 int *prioceiling)
344 {
345 if (mutex->sig == _PTHREAD_MUTEX_SIG)
346 {
347 *prioceiling = mutex->prioceiling;
348 return (ESUCCESS);
349 } else
350 {
351 return (EINVAL); /* Not an initialized 'attribute' structure */
352 }
353 }
354
355 /*
356 * Set the priority ceiling for a mutex.
357 * Note: written as a 'helper' function to hide implementation details.
358 */
359 int
360 pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
361 int prioceiling,
362 int *old_prioceiling)
363 {
364 if (mutex->sig == _PTHREAD_MUTEX_SIG)
365 {
366 if ((prioceiling >= -999) ||
367 (prioceiling <= 999))
368 {
369 *old_prioceiling = mutex->prioceiling;
370 mutex->prioceiling = prioceiling;
371 return (ESUCCESS);
372 } else
373 {
374 return (EINVAL); /* Invalid parameter */
375 }
376 } else
377 {
378 return (EINVAL); /* Not an initialized 'attribute' structure */
379 }
380 }
381
382 /*
383 * Destroy a mutex attribute structure.
384 */
385 int
386 pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
387 {
388 attr->sig = _PTHREAD_NO_SIG; /* Uninitialized */
389 return (ESUCCESS);
390 }
391
392 /*
393 * Get the priority ceiling value from a mutex attribute structure.
394 * Note: written as a 'helper' function to hide implementation details.
395 */
396 int
397 pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr,
398 int *prioceiling)
399 {
400 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
401 {
402 *prioceiling = attr->prioceiling;
403 return (ESUCCESS);
404 } else
405 {
406 return (EINVAL); /* Not an initialized 'attribute' structure */
407 }
408 }
409
410 /*
411 * Get the mutex 'protocol' value from a mutex attribute structure.
412 * Note: written as a 'helper' function to hide implementation details.
413 */
414 int
415 pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
416 int *protocol)
417 {
418 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
419 {
420 *protocol = attr->protocol;
421 return (ESUCCESS);
422 } else
423 {
424 return (EINVAL); /* Not an initialized 'attribute' structure */
425 }
426 }
427 /*
428 * Get the mutex 'type' value from a mutex attribute structure.
429 * Note: written as a 'helper' function to hide implementation details.
430 */
431 int
432 pthread_mutexattr_gettype(const pthread_mutexattr_t *attr,
433 int *type)
434 {
435 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
436 {
437 *type = attr->type;
438 return (ESUCCESS);
439 } else
440 {
441 return (EINVAL); /* Not an initialized 'attribute' structure */
442 }
443 }
444
445 /*
446 *
447 */
448 int
449 pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
450 {
451 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
452 {
453 *pshared = (int)PTHREAD_PROCESS_PRIVATE;
454 return (ESUCCESS);
455 } else
456 {
457 return (EINVAL); /* Not an initialized 'attribute' structure */
458 }
459 }
460
461 /*
462 * Initialize a mutex attribute structure to system defaults.
463 */
464 int
465 pthread_mutexattr_init(pthread_mutexattr_t *attr)
466 {
467 attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
468 attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
469 attr->type = PTHREAD_MUTEX_DEFAULT;
470 attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
471 return (ESUCCESS);
472 }
473
474 /*
475 * Set the priority ceiling value in a mutex attribute structure.
476 * Note: written as a 'helper' function to hide implementation details.
477 */
478 int
479 pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
480 int prioceiling)
481 {
482 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
483 {
484 if ((prioceiling >= -999) ||
485 (prioceiling <= 999))
486 {
487 attr->prioceiling = prioceiling;
488 return (ESUCCESS);
489 } else
490 {
491 return (EINVAL); /* Invalid parameter */
492 }
493 } else
494 {
495 return (EINVAL); /* Not an initialized 'attribute' structure */
496 }
497 }
498
499 /*
500 * Set the mutex 'protocol' value in a mutex attribute structure.
501 * Note: written as a 'helper' function to hide implementation details.
502 */
503 int
504 pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr,
505 int protocol)
506 {
507 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
508 {
509 if ((protocol == PTHREAD_PRIO_NONE) ||
510 (protocol == PTHREAD_PRIO_INHERIT) ||
511 (protocol == PTHREAD_PRIO_PROTECT))
512 {
513 attr->protocol = protocol;
514 return (ESUCCESS);
515 } else
516 {
517 return (EINVAL); /* Invalid parameter */
518 }
519 } else
520 {
521 return (EINVAL); /* Not an initialized 'attribute' structure */
522 }
523 }
524 /*
525 * Set the mutex 'type' value in a mutex attribute structure.
526 * Note: written as a 'helper' function to hide implementation details.
527 */
528 int
529 pthread_mutexattr_settype(pthread_mutexattr_t *attr,
530 int type)
531 {
532 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
533 {
534 if ((type == PTHREAD_MUTEX_NORMAL) ||
535 (type == PTHREAD_MUTEX_ERRORCHECK) ||
536 (type == PTHREAD_MUTEX_RECURSIVE) ||
537 (type == PTHREAD_MUTEX_DEFAULT))
538 {
539 attr->type = type;
540 return (ESUCCESS);
541 } else
542 {
543 return (EINVAL); /* Invalid parameter */
544 }
545 } else
546 {
547 return (EINVAL); /* Not an initialized 'attribute' structure */
548 }
549 }
550
551 /*
552 *
553 */
554 int
555 pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
556 {
557 if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG)
558 {
559 if (pshared == PTHREAD_PROCESS_PRIVATE)
560 {
561 /* attr->pshared = protocol; */
562 return (ESUCCESS);
563 } else
564 {
565 return (EINVAL); /* Invalid parameter */
566 }
567 } else
568 {
569 return (EINVAL); /* Not an initialized 'attribute' structure */
570 }
571 }
572
573 int mutex_try_lock(int *x) {
574 return _spin_lock_try((pthread_lock_t *)x);
575 }
576
577 void mutex_wait_lock(int *x) {
578 for (;;) {
579 if( _spin_lock_try((pthread_lock_t *)x)) {
580 return;
581 }
582 swtch_pri(0);
583 }
584 }
585
586 void
587 cthread_yield(void)
588 {
589 sched_yield();
590 }
591
592 void
593 pthread_yield_np (void)
594 {
595 sched_yield();
596 }
597