Home | History | Annotate | Line # | Download | only in libpthread
pthread_mutex.c revision 1.1.2.19
      1  1.1.2.19  thorpej /*	$NetBSD: pthread_mutex.c,v 1.1.2.19 2003/01/13 22:50:10 thorpej Exp $	*/
      2   1.1.2.3  nathanw 
      3   1.1.2.3  nathanw /*-
      4  1.1.2.19  thorpej  * Copyright (c) 2001, 2003 The NetBSD Foundation, Inc.
      5   1.1.2.3  nathanw  * All rights reserved.
      6   1.1.2.3  nathanw  *
      7   1.1.2.3  nathanw  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1.2.19  thorpej  * by Nathan J. Williams, and by Jason R. Thorpe.
      9   1.1.2.3  nathanw  *
     10   1.1.2.3  nathanw  * Redistribution and use in source and binary forms, with or without
     11   1.1.2.3  nathanw  * modification, are permitted provided that the following conditions
     12   1.1.2.3  nathanw  * are met:
     13   1.1.2.3  nathanw  * 1. Redistributions of source code must retain the above copyright
     14   1.1.2.3  nathanw  *    notice, this list of conditions and the following disclaimer.
     15   1.1.2.3  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1.2.3  nathanw  *    notice, this list of conditions and the following disclaimer in the
     17   1.1.2.3  nathanw  *    documentation and/or other materials provided with the distribution.
     18   1.1.2.3  nathanw  * 3. All advertising materials mentioning features or use of this software
     19   1.1.2.3  nathanw  *    must display the following acknowledgement:
     20   1.1.2.3  nathanw  *        This product includes software developed by the NetBSD
     21   1.1.2.3  nathanw  *        Foundation, Inc. and its contributors.
     22   1.1.2.3  nathanw  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23   1.1.2.3  nathanw  *    contributors may be used to endorse or promote products derived
     24   1.1.2.3  nathanw  *    from this software without specific prior written permission.
     25   1.1.2.3  nathanw  *
     26   1.1.2.3  nathanw  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27   1.1.2.3  nathanw  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28   1.1.2.3  nathanw  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29   1.1.2.3  nathanw  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30   1.1.2.3  nathanw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31   1.1.2.3  nathanw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32   1.1.2.3  nathanw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33   1.1.2.3  nathanw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34   1.1.2.3  nathanw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35   1.1.2.3  nathanw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36   1.1.2.3  nathanw  * POSSIBILITY OF SUCH DAMAGE.
     37   1.1.2.3  nathanw  */
     38   1.1.2.1  nathanw 
     39  1.1.2.19  thorpej #include <sys/cdefs.h>
     40   1.1.2.1  nathanw #include <assert.h>
     41   1.1.2.1  nathanw #include <errno.h>
     42  1.1.2.19  thorpej #include <limits.h>
     43  1.1.2.19  thorpej #include <stdlib.h>
     44   1.1.2.1  nathanw 
     45   1.1.2.1  nathanw #include "pthread.h"
     46   1.1.2.1  nathanw #include "pthread_int.h"
     47   1.1.2.1  nathanw 
     48  1.1.2.19  thorpej static int pthread_mutex_lock_slow(pthread_mutex_t *);
     49  1.1.2.17  thorpej 
     50  1.1.2.18  thorpej __strong_alias(__libc_mutex_init,pthread_mutex_init)
     51  1.1.2.18  thorpej __strong_alias(__libc_mutex_lock,pthread_mutex_lock)
     52  1.1.2.18  thorpej __strong_alias(__libc_mutex_trylock,pthread_mutex_trylock)
     53  1.1.2.18  thorpej __strong_alias(__libc_mutex_unlock,pthread_mutex_unlock)
     54  1.1.2.18  thorpej __strong_alias(__libc_mutex_destroy,pthread_mutex_destroy)
     55  1.1.2.17  thorpej 
     56  1.1.2.18  thorpej __strong_alias(__libc_thr_once,pthread_once)
     57   1.1.2.1  nathanw 
     58  1.1.2.19  thorpej struct mutex_private {
     59  1.1.2.19  thorpej 	int	type;
     60  1.1.2.19  thorpej 	int	recursecount;
     61  1.1.2.19  thorpej };
     62  1.1.2.19  thorpej 
     63  1.1.2.19  thorpej static const struct mutex_private mutex_private_default = {
     64  1.1.2.19  thorpej 	PTHREAD_MUTEX_DEFAULT,
     65  1.1.2.19  thorpej 	0,
     66  1.1.2.19  thorpej };
     67  1.1.2.19  thorpej 
     68  1.1.2.19  thorpej struct mutexattr_private {
     69  1.1.2.19  thorpej 	int	type;
     70  1.1.2.19  thorpej };
     71  1.1.2.19  thorpej 
     72  1.1.2.19  thorpej static const struct mutexattr_private mutexattr_private_default = {
     73  1.1.2.19  thorpej 	PTHREAD_MUTEX_DEFAULT,
     74  1.1.2.19  thorpej };
     75  1.1.2.19  thorpej 
     76  1.1.2.19  thorpej /*
     77  1.1.2.19  thorpej  * If the mutex does not already have private data (i.e. was statically
     78  1.1.2.19  thorpej  * initialized), then give it the default.
     79  1.1.2.19  thorpej  */
     80  1.1.2.19  thorpej #define	GET_MUTEX_PRIVATE(mutex, mp)					\
     81  1.1.2.19  thorpej do {									\
     82  1.1.2.19  thorpej 	if (__predict_false((mp = (mutex)->ptm_private) == NULL)) {	\
     83  1.1.2.19  thorpej 		/* LINTED cast away const */				\
     84  1.1.2.19  thorpej 		mp = ((mutex)->ptm_private =				\
     85  1.1.2.19  thorpej 		    (void *)&mutex_private_default);			\
     86  1.1.2.19  thorpej 	}								\
     87  1.1.2.19  thorpej } while (/*CONSTCOND*/0)
     88  1.1.2.19  thorpej 
     89   1.1.2.1  nathanw int
     90   1.1.2.1  nathanw pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
     91   1.1.2.1  nathanw {
     92  1.1.2.19  thorpej 	struct mutexattr_private *map;
     93  1.1.2.19  thorpej 	struct mutex_private *mp;
     94   1.1.2.1  nathanw 
     95   1.1.2.5  nathanw #ifdef ERRORCHECK
     96   1.1.2.5  nathanw 	if ((mutex == NULL) ||
     97   1.1.2.5  nathanw 	    (attr && (attr->ptma_magic != _PT_MUTEXATTR_MAGIC)))
     98   1.1.2.1  nathanw 		return EINVAL;
     99   1.1.2.5  nathanw #endif
    100   1.1.2.1  nathanw 
    101  1.1.2.19  thorpej 	if (attr != NULL && (map = attr->ptma_private) != NULL &&
    102  1.1.2.19  thorpej 	    memcmp(map, &mutexattr_private_default, sizeof(*map)) != 0) {
    103  1.1.2.19  thorpej 		mp = malloc(sizeof(*mp));
    104  1.1.2.19  thorpej 		if (mp == NULL)
    105  1.1.2.19  thorpej 			return ENOMEM;
    106  1.1.2.19  thorpej 
    107  1.1.2.19  thorpej 		mp->type = map->type;
    108  1.1.2.19  thorpej 		mp->recursecount = 0;
    109  1.1.2.19  thorpej 	} else {
    110  1.1.2.19  thorpej 		/* LINTED cast away const */
    111  1.1.2.19  thorpej 		mp = (struct mutex_private *) &mutex_private_default;
    112  1.1.2.19  thorpej 	}
    113  1.1.2.19  thorpej 
    114   1.1.2.4  nathanw 	mutex->ptm_magic = _PT_MUTEX_MAGIC;
    115   1.1.2.2  nathanw 	mutex->ptm_owner = NULL;
    116   1.1.2.2  nathanw 	pthread_lockinit(&mutex->ptm_lock);
    117   1.1.2.2  nathanw 	pthread_lockinit(&mutex->ptm_interlock);
    118   1.1.2.2  nathanw 	PTQ_INIT(&mutex->ptm_blocked);
    119  1.1.2.19  thorpej 	mutex->ptm_private = mp;
    120   1.1.2.1  nathanw 
    121   1.1.2.1  nathanw 	return 0;
    122   1.1.2.1  nathanw }
    123   1.1.2.1  nathanw 
    124   1.1.2.1  nathanw 
    125   1.1.2.1  nathanw int
    126   1.1.2.1  nathanw pthread_mutex_destroy(pthread_mutex_t *mutex)
    127   1.1.2.1  nathanw {
    128   1.1.2.1  nathanw 
    129   1.1.2.5  nathanw #ifdef ERRORCHECK
    130   1.1.2.5  nathanw 	if ((mutex == NULL) ||
    131   1.1.2.5  nathanw 	    (mutex->ptm_magic != _PT_MUTEX_MAGIC) ||
    132   1.1.2.5  nathanw 	    (mutex->ptm_lock != __SIMPLELOCK_UNLOCKED))
    133   1.1.2.5  nathanw 		return EINVAL;
    134   1.1.2.5  nathanw #endif
    135   1.1.2.1  nathanw 
    136   1.1.2.4  nathanw 	mutex->ptm_magic = _PT_MUTEX_DEAD;
    137  1.1.2.19  thorpej 	if (mutex->ptm_private != NULL &&
    138  1.1.2.19  thorpej 	    mutex->ptm_private != (void *)&mutex_private_default)
    139  1.1.2.19  thorpej 		free(mutex->ptm_private);
    140   1.1.2.1  nathanw 
    141   1.1.2.1  nathanw 	return 0;
    142   1.1.2.1  nathanw }
    143   1.1.2.1  nathanw 
    144   1.1.2.1  nathanw 
    145   1.1.2.2  nathanw /*
    146   1.1.2.2  nathanw  * Note regarding memory visibility: Pthreads has rules about memory
    147   1.1.2.2  nathanw  * visibility and mutexes. Very roughly: Memory a thread can see when
    148   1.1.2.2  nathanw  * it unlocks a mutex can be seen by another thread that locks the
    149   1.1.2.2  nathanw  * same mutex.
    150   1.1.2.2  nathanw  *
    151   1.1.2.2  nathanw  * A memory barrier after a lock and before an unlock will provide
    152  1.1.2.16  thorpej  * this behavior. This code relies on pthread__simple_lock_try() to issue
    153  1.1.2.16  thorpej  * a barrier after obtaining a lock, and on pthread__simple_unlock() to
    154   1.1.2.2  nathanw  * issue a barrier before releasing a lock.
    155   1.1.2.2  nathanw  */
    156   1.1.2.2  nathanw 
    157   1.1.2.1  nathanw int
    158   1.1.2.1  nathanw pthread_mutex_lock(pthread_mutex_t *mutex)
    159   1.1.2.1  nathanw {
    160  1.1.2.19  thorpej 	int error;
    161   1.1.2.5  nathanw 
    162   1.1.2.2  nathanw #ifdef ERRORCHECK
    163   1.1.2.4  nathanw 	if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
    164   1.1.2.1  nathanw 		return EINVAL;
    165   1.1.2.2  nathanw #endif
    166  1.1.2.12  nathanw 
    167  1.1.2.19  thorpej 	/*
    168  1.1.2.19  thorpej 	 * Note that if we get the lock, we don't have to deal with any
    169  1.1.2.19  thorpej 	 * non-default lock type handling.
    170  1.1.2.19  thorpej 	 */
    171  1.1.2.19  thorpej 	if (__predict_false(pthread__simple_lock_try(&mutex->ptm_lock) == 0)) {
    172  1.1.2.19  thorpej 		error = pthread_mutex_lock_slow(mutex);
    173  1.1.2.19  thorpej 		if (error)
    174  1.1.2.19  thorpej 			return error;
    175  1.1.2.19  thorpej 	}
    176  1.1.2.12  nathanw 
    177  1.1.2.12  nathanw 	/* We have the lock! */
    178  1.1.2.19  thorpej 	mutex->ptm_owner = pthread__self();
    179  1.1.2.19  thorpej 
    180  1.1.2.12  nathanw 	return 0;
    181  1.1.2.12  nathanw }
    182  1.1.2.12  nathanw 
    183  1.1.2.19  thorpej 
    184  1.1.2.19  thorpej static int
    185  1.1.2.12  nathanw pthread_mutex_lock_slow(pthread_mutex_t *mutex)
    186  1.1.2.12  nathanw {
    187  1.1.2.12  nathanw 	pthread_t self;
    188  1.1.2.12  nathanw 
    189   1.1.2.5  nathanw 	self = pthread__self();
    190   1.1.2.1  nathanw 
    191   1.1.2.2  nathanw 	while (/*CONSTCOND*/1) {
    192  1.1.2.16  thorpej 		if (pthread__simple_lock_try(&mutex->ptm_lock))
    193  1.1.2.19  thorpej 			break; /* got it! */
    194   1.1.2.1  nathanw 
    195   1.1.2.2  nathanw 		/* Okay, didn't look free. Get the interlock... */
    196   1.1.2.2  nathanw 		pthread_spinlock(self, &mutex->ptm_interlock);
    197  1.1.2.15  nathanw 		/*
    198  1.1.2.15  nathanw 		 * The mutex_unlock routine will get the interlock
    199   1.1.2.2  nathanw 		 * before looking at the list of sleepers, so if the
    200   1.1.2.2  nathanw 		 * lock is held we can safely put ourselves on the
    201   1.1.2.2  nathanw 		 * sleep queue. If it's not held, we can try taking it
    202   1.1.2.2  nathanw 		 * again.
    203   1.1.2.2  nathanw 		 */
    204   1.1.2.2  nathanw 		if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) {
    205  1.1.2.19  thorpej 			struct mutex_private *mp;
    206  1.1.2.19  thorpej 
    207  1.1.2.19  thorpej 			GET_MUTEX_PRIVATE(mutex, mp);
    208  1.1.2.19  thorpej 
    209  1.1.2.19  thorpej 			if (mutex->ptm_owner == self) {
    210  1.1.2.19  thorpej 				/*
    211  1.1.2.19  thorpej 				 * It's safe to do this without holding the
    212  1.1.2.19  thorpej 				 * interlock, because we only modify it if
    213  1.1.2.19  thorpej 				 * we know we own the mutex.
    214  1.1.2.19  thorpej 				 */
    215  1.1.2.19  thorpej 				switch (mp->type) {
    216  1.1.2.19  thorpej 				case PTHREAD_MUTEX_ERRORCHECK:
    217  1.1.2.19  thorpej 					pthread_spinunlock(self,
    218  1.1.2.19  thorpej 					    &mutex->ptm_interlock);
    219  1.1.2.19  thorpej 					return EDEADLK;
    220  1.1.2.19  thorpej 
    221  1.1.2.19  thorpej 				case PTHREAD_MUTEX_RECURSIVE:
    222  1.1.2.19  thorpej 					pthread_spinunlock(self,
    223  1.1.2.19  thorpej 					    &mutex->ptm_interlock);
    224  1.1.2.19  thorpej 					if (mp->recursecount == INT_MAX)
    225  1.1.2.19  thorpej 						return EAGAIN;
    226  1.1.2.19  thorpej 					mp->recursecount++;
    227  1.1.2.19  thorpej 					return 0;
    228  1.1.2.19  thorpej 				}
    229  1.1.2.19  thorpej 			}
    230  1.1.2.19  thorpej 
    231   1.1.2.2  nathanw 			PTQ_INSERT_TAIL(&mutex->ptm_blocked, self, pt_sleep);
    232  1.1.2.15  nathanw 			/*
    233  1.1.2.15  nathanw 			 * Locking a mutex is not a cancellation
    234   1.1.2.7  nathanw 			 * point, so we don't need to do the
    235   1.1.2.7  nathanw 			 * test-cancellation dance. We may get woken
    236   1.1.2.7  nathanw 			 * up spuriously by pthread_cancel, though,
    237   1.1.2.7  nathanw 			 * but it's okay since we're just going to
    238   1.1.2.7  nathanw 			 * retry.
    239   1.1.2.7  nathanw 			 */
    240   1.1.2.7  nathanw 			pthread_spinlock(self, &self->pt_statelock);
    241   1.1.2.7  nathanw 			self->pt_state = PT_STATE_BLOCKED_QUEUE;
    242  1.1.2.11  nathanw 			self->pt_sleepobj = mutex;
    243   1.1.2.7  nathanw 			self->pt_sleepq = &mutex->ptm_blocked;
    244   1.1.2.7  nathanw 			self->pt_sleeplock = &mutex->ptm_interlock;
    245   1.1.2.7  nathanw 			pthread_spinunlock(self, &self->pt_statelock);
    246   1.1.2.7  nathanw 
    247   1.1.2.2  nathanw 			pthread__block(self, &mutex->ptm_interlock);
    248   1.1.2.2  nathanw 			/* interlock is not held when we return */
    249   1.1.2.2  nathanw 		} else {
    250   1.1.2.2  nathanw 			pthread_spinunlock(self, &mutex->ptm_interlock);
    251   1.1.2.2  nathanw 		}
    252   1.1.2.2  nathanw 		/* Go around for another try. */
    253   1.1.2.1  nathanw 	}
    254  1.1.2.19  thorpej 
    255  1.1.2.19  thorpej 	return 0;
    256   1.1.2.1  nathanw }
    257   1.1.2.1  nathanw 
    258   1.1.2.1  nathanw 
    259   1.1.2.1  nathanw int
    260   1.1.2.1  nathanw pthread_mutex_trylock(pthread_mutex_t *mutex)
    261   1.1.2.1  nathanw {
    262  1.1.2.19  thorpej 	pthread_t self = pthread__self();
    263   1.1.2.1  nathanw 
    264   1.1.2.2  nathanw #ifdef ERRORCHECK
    265   1.1.2.4  nathanw 	if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
    266   1.1.2.1  nathanw 		return EINVAL;
    267   1.1.2.2  nathanw #endif
    268   1.1.2.1  nathanw 
    269  1.1.2.19  thorpej 	if (pthread__simple_lock_try(&mutex->ptm_lock) == 0) {
    270  1.1.2.19  thorpej 		struct mutex_private *mp;
    271  1.1.2.19  thorpej 
    272  1.1.2.19  thorpej 		GET_MUTEX_PRIVATE(mutex, mp);
    273  1.1.2.19  thorpej 
    274  1.1.2.19  thorpej 		/*
    275  1.1.2.19  thorpej 		 * These tests can be performed without holding the
    276  1.1.2.19  thorpej 		 * interlock because these fields are only modified
    277  1.1.2.19  thorpej 		 * if we know we own the mutex.
    278  1.1.2.19  thorpej 		 */
    279  1.1.2.19  thorpej 		if (mutex->ptm_owner == self) {
    280  1.1.2.19  thorpej 			switch (mp->type) {
    281  1.1.2.19  thorpej 			case PTHREAD_MUTEX_ERRORCHECK:
    282  1.1.2.19  thorpej 				return EDEADLK;
    283  1.1.2.19  thorpej 
    284  1.1.2.19  thorpej 			case PTHREAD_MUTEX_RECURSIVE:
    285  1.1.2.19  thorpej 				if (mp->recursecount == INT_MAX)
    286  1.1.2.19  thorpej 					return EAGAIN;
    287  1.1.2.19  thorpej 				mp->recursecount++;
    288  1.1.2.19  thorpej 				return 0;
    289  1.1.2.19  thorpej 			}
    290  1.1.2.19  thorpej 		}
    291  1.1.2.19  thorpej 
    292   1.1.2.1  nathanw 		return EBUSY;
    293  1.1.2.19  thorpej 	}
    294  1.1.2.19  thorpej 
    295  1.1.2.19  thorpej 	mutex->ptm_owner = self;
    296   1.1.2.1  nathanw 
    297   1.1.2.1  nathanw 	return 0;
    298   1.1.2.1  nathanw }
    299   1.1.2.1  nathanw 
    300   1.1.2.1  nathanw 
    301   1.1.2.1  nathanw int
    302   1.1.2.1  nathanw pthread_mutex_unlock(pthread_mutex_t *mutex)
    303   1.1.2.1  nathanw {
    304  1.1.2.19  thorpej 	struct mutex_private *mp;
    305  1.1.2.14  nathanw 	pthread_t self, blocked;
    306  1.1.2.14  nathanw 
    307  1.1.2.14  nathanw 	self = pthread__self();
    308   1.1.2.5  nathanw 
    309   1.1.2.2  nathanw #ifdef ERRORCHECK
    310   1.1.2.4  nathanw 	if ((mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
    311   1.1.2.1  nathanw 		return EINVAL;
    312   1.1.2.1  nathanw 
    313   1.1.2.2  nathanw 	if (mutex->ptm_lock != __SIMPLELOCK_LOCKED)
    314   1.1.2.1  nathanw 		return EPERM; /* Not exactly the right error. */
    315   1.1.2.2  nathanw #endif
    316   1.1.2.1  nathanw 
    317  1.1.2.19  thorpej 	GET_MUTEX_PRIVATE(mutex, mp);
    318  1.1.2.19  thorpej 
    319  1.1.2.19  thorpej 	/*
    320  1.1.2.19  thorpej 	 * These tests can be performed without holding the
    321  1.1.2.19  thorpej 	 * interlock because these fields are only modified
    322  1.1.2.19  thorpej 	 * if we know we own the mutex.
    323  1.1.2.19  thorpej 	 */
    324  1.1.2.19  thorpej 	switch (mp->type) {
    325  1.1.2.19  thorpej 	case PTHREAD_MUTEX_ERRORCHECK:
    326  1.1.2.19  thorpej 		if (mutex->ptm_owner != self)
    327  1.1.2.19  thorpej 			return EPERM;
    328  1.1.2.19  thorpej 		break;
    329  1.1.2.19  thorpej 
    330  1.1.2.19  thorpej 	case PTHREAD_MUTEX_RECURSIVE:
    331  1.1.2.19  thorpej 		if (mutex->ptm_owner != self)
    332  1.1.2.19  thorpej 			return EPERM;
    333  1.1.2.19  thorpej 		if (mp->recursecount != 0) {
    334  1.1.2.19  thorpej 			mp->recursecount--;
    335  1.1.2.19  thorpej 			return 0;
    336  1.1.2.19  thorpej 		}
    337  1.1.2.19  thorpej 		break;
    338  1.1.2.19  thorpej 	}
    339  1.1.2.19  thorpej 
    340   1.1.2.2  nathanw 	pthread_spinlock(self, &mutex->ptm_interlock);
    341   1.1.2.4  nathanw 	blocked = PTQ_FIRST(&mutex->ptm_blocked);
    342   1.1.2.4  nathanw 	if (blocked)
    343   1.1.2.4  nathanw 		PTQ_REMOVE(&mutex->ptm_blocked, blocked, pt_sleep);
    344  1.1.2.14  nathanw 	mutex->ptm_owner = NULL;
    345  1.1.2.16  thorpej 	pthread__simple_unlock(&mutex->ptm_lock);
    346   1.1.2.2  nathanw 	pthread_spinunlock(self, &mutex->ptm_interlock);
    347   1.1.2.1  nathanw 
    348   1.1.2.4  nathanw 	/* Give the head of the blocked queue another try. */
    349   1.1.2.4  nathanw 	if (blocked)
    350   1.1.2.1  nathanw 		pthread__sched(self, blocked);
    351  1.1.2.14  nathanw 
    352  1.1.2.14  nathanw 	return 0;
    353   1.1.2.5  nathanw }
    354   1.1.2.5  nathanw 
    355   1.1.2.5  nathanw int
    356   1.1.2.5  nathanw pthread_mutexattr_init(pthread_mutexattr_t *attr)
    357   1.1.2.5  nathanw {
    358  1.1.2.19  thorpej 	struct mutexattr_private *map;
    359   1.1.2.5  nathanw 
    360   1.1.2.5  nathanw #ifdef ERRORCHECK
    361   1.1.2.5  nathanw 	if (attr == NULL)
    362   1.1.2.5  nathanw 		return EINVAL;
    363   1.1.2.5  nathanw #endif
    364   1.1.2.5  nathanw 
    365  1.1.2.19  thorpej 	map = malloc(sizeof(*map));
    366  1.1.2.19  thorpej 	if (map == NULL)
    367  1.1.2.19  thorpej 		return ENOMEM;
    368  1.1.2.19  thorpej 
    369  1.1.2.19  thorpej 	*map = mutexattr_private_default;
    370  1.1.2.19  thorpej 
    371   1.1.2.5  nathanw 	attr->ptma_magic = _PT_MUTEXATTR_MAGIC;
    372  1.1.2.19  thorpej 	attr->ptma_private = map;
    373   1.1.2.5  nathanw 
    374   1.1.2.5  nathanw 	return 0;
    375   1.1.2.5  nathanw }
    376   1.1.2.5  nathanw 
    377   1.1.2.5  nathanw 
    378   1.1.2.5  nathanw int
    379   1.1.2.5  nathanw pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
    380   1.1.2.5  nathanw {
    381   1.1.2.5  nathanw 
    382   1.1.2.5  nathanw #ifdef ERRORCHECK
    383   1.1.2.5  nathanw 	if ((attr == NULL) ||
    384   1.1.2.5  nathanw 	    (attr->ptma_magic != _PT_MUTEXATTR_MAGIC))
    385   1.1.2.5  nathanw 		return EINVAL;
    386   1.1.2.5  nathanw #endif
    387   1.1.2.5  nathanw 
    388   1.1.2.5  nathanw 	attr->ptma_magic = _PT_MUTEXATTR_DEAD;
    389  1.1.2.19  thorpej 	if (attr->ptma_private != NULL)
    390  1.1.2.19  thorpej 		free(attr->ptma_private);
    391  1.1.2.19  thorpej 
    392  1.1.2.19  thorpej 	return 0;
    393  1.1.2.19  thorpej }
    394  1.1.2.19  thorpej 
    395  1.1.2.19  thorpej 
    396  1.1.2.19  thorpej int
    397  1.1.2.19  thorpej pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *typep)
    398  1.1.2.19  thorpej {
    399  1.1.2.19  thorpej 	struct mutexattr_private *map;
    400  1.1.2.19  thorpej 
    401  1.1.2.19  thorpej #ifdef ERRORCHECK
    402  1.1.2.19  thorpej 	if ((attr == NULL) ||
    403  1.1.2.19  thorpej 	    (attr->ptma_magic != _PT_MUTEXATTR_MAGIC) ||
    404  1.1.2.19  thorpej 	    (typep == NULL))
    405  1.1.2.19  thorpej 		return EINVAL;
    406  1.1.2.19  thorpej #endif
    407  1.1.2.19  thorpej 
    408  1.1.2.19  thorpej 	map = attr->ptma_private;
    409  1.1.2.19  thorpej 
    410  1.1.2.19  thorpej 	*typep = map->type;
    411  1.1.2.19  thorpej 
    412  1.1.2.19  thorpej 	return 0;
    413  1.1.2.19  thorpej }
    414  1.1.2.19  thorpej 
    415  1.1.2.19  thorpej 
    416  1.1.2.19  thorpej int
    417  1.1.2.19  thorpej pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
    418  1.1.2.19  thorpej {
    419  1.1.2.19  thorpej 	struct mutexattr_private *map;
    420  1.1.2.19  thorpej 
    421  1.1.2.19  thorpej #ifdef ERRORCHECK
    422  1.1.2.19  thorpej 	if ((attr == NULL) ||
    423  1.1.2.19  thorpej 	    (attr->ptma_magic != _PT_MUTEXATTR_MAGIC))
    424  1.1.2.19  thorpej 		return EINVAL;
    425  1.1.2.19  thorpej #endif
    426  1.1.2.19  thorpej 	map = attr->ptma_private;
    427  1.1.2.19  thorpej 
    428  1.1.2.19  thorpej 	switch (type) {
    429  1.1.2.19  thorpej 	case PTHREAD_MUTEX_NORMAL:
    430  1.1.2.19  thorpej 	case PTHREAD_MUTEX_ERRORCHECK:
    431  1.1.2.19  thorpej 	case PTHREAD_MUTEX_RECURSIVE:
    432  1.1.2.19  thorpej 		map->type = type;
    433  1.1.2.19  thorpej 		break;
    434  1.1.2.19  thorpej 
    435  1.1.2.19  thorpej 	default:
    436  1.1.2.19  thorpej 		return EINVAL;
    437  1.1.2.19  thorpej 	}
    438   1.1.2.6  nathanw 
    439   1.1.2.6  nathanw 	return 0;
    440   1.1.2.6  nathanw }
    441   1.1.2.6  nathanw 
    442   1.1.2.6  nathanw 
    443   1.1.2.6  nathanw int
    444   1.1.2.6  nathanw pthread_once(pthread_once_t *once_control, void (*routine)(void))
    445   1.1.2.6  nathanw {
    446   1.1.2.6  nathanw 
    447   1.1.2.6  nathanw 	if (once_control->pto_done == 0) {
    448   1.1.2.6  nathanw 		pthread_mutex_lock(&once_control->pto_mutex);
    449   1.1.2.6  nathanw 		if (once_control->pto_done == 0) {
    450   1.1.2.6  nathanw 			routine();
    451   1.1.2.6  nathanw 			once_control->pto_done = 1;
    452   1.1.2.6  nathanw 		}
    453   1.1.2.6  nathanw 		pthread_mutex_unlock(&once_control->pto_mutex);
    454   1.1.2.6  nathanw 	}
    455   1.1.2.1  nathanw 
    456   1.1.2.1  nathanw 	return 0;
    457   1.1.2.1  nathanw }
    458