FreeBSD/sys/kern/kern_umtx.c
/*
 * Lock PTHREAD_PRIO_NONE protocol POSIX mutex.
 */
Lock PTHREAD_PRIO_NONE protocol POSIX mutex.
Lock PTHREAD_PRIO_NONE protocol POSIX mutex .
static int
do_lock_normal(struct thread *td, struct umutex *m, uint32_t flags,
    struct _umtx_time *timeout, int mode)
{
	struct abs_timeout timo;
	struct umtx_q *uq;
	uint32_t owner, old, id;
	int error, rv;
	id = td->td_tid;
	uq = td->td_umtxq;
	error = 0;
	if (timeout != NULL)
		abs_timeout_init2(&timo, timeout);
	for (;;) {
		rv = fueword32(&m->m_owner, &owner);
		if (rv == -1)
			return (EFAULT);
		if (mode == _UMUTEX_WAIT) {
			if (owner == UMUTEX_UNOWNED ||
			    owner == UMUTEX_CONTESTED ||
			    owner == UMUTEX_RB_OWNERDEAD ||
			    owner == UMUTEX_RB_NOTRECOV)
				return (0);
		} else {
			if (owner == UMUTEX_RB_OWNERDEAD) {
				rv = casueword32(&m->m_owner,
				    UMUTEX_RB_OWNERDEAD, &owner,
				    id | UMUTEX_CONTESTED);
				if (rv == -1)
					return (EFAULT);
				if (owner == UMUTEX_RB_OWNERDEAD)
					return (EOWNERDEAD); 
				rv = umtxq_check_susp(td);
				if (rv != 0)
					return (rv);
				continue;
			}
			if (owner == UMUTEX_RB_NOTRECOV)
				return (ENOTRECOVERABLE);
			rv = casueword32(&m->m_owner, UMUTEX_UNOWNED,
			    &owner, id);
			if (rv == -1)
				return (EFAULT);
			if (owner == UMUTEX_UNOWNED)
				return (0);
			if (owner == UMUTEX_CONTESTED) {
				rv = casueword32(&m->m_owner,
				    UMUTEX_CONTESTED, &owner,
				    id | UMUTEX_CONTESTED);
				if (rv == -1)
					return (EFAULT);
				if (owner == UMUTEX_CONTESTED)
					return (0);
				rv = umtxq_check_susp(td);
				if (rv != 0)
					return (rv);
				continue;
			}
		}
		if (mode == _UMUTEX_TRY)
			return (EBUSY);
		if (error != 0)
			return (error);
		if ((error = umtx_key_get(m, TYPE_NORMAL_UMUTEX,
		    GET_SHARE(flags), &uq->uq_key)) != 0)
			return (error);
		umtxq_lock(&uq->uq_key);
		umtxq_busy(&uq->uq_key);
		umtxq_insert(uq);
		umtxq_unlock(&uq->uq_key);
		rv = casueword32(&m->m_owner, owner, &old,
		    owner | UMUTEX_CONTESTED);
		if (rv == -1) {
			umtxq_lock(&uq->uq_key);
			umtxq_remove(uq);
			umtxq_unbusy(&uq->uq_key);
			umtxq_unlock(&uq->uq_key);
			umtx_key_release(&uq->uq_key);
			return (EFAULT);
		}
		umtxq_lock(&uq->uq_key);
		umtxq_unbusy(&uq->uq_key);
		if (old == owner)
			error = umtxq_sleep(uq, "umtxn", timeout == NULL ?
			    NULL : &timo);
		umtxq_remove(uq);
		umtxq_unlock(&uq->uq_key);
		umtx_key_release(&uq->uq_key);
		if (error == 0)
			error = umtxq_check_susp(td);
	}
	return (0);
}
static int do_lock_normal ( struct thread * td , struct umutex * m , uint32_t flags , struct _umtx_time * timeout , int mode ) { struct abs_timeout timo ; struct umtx_q * uq ; uint32_t owner , old , id ; int error , rv ; id = td -> td_tid ; uq = td -> td_umtxq ; error = 0 ; if ( timeout != NULL ) abs_timeout_init2 ( & timo , timeout ) ; for ( ; ; ) { rv = fueword32 ( & m -> m_owner , & owner ) ; if ( rv == -1 ) return ( EFAULT ) ; if ( mode == _UMUTEX_WAIT ) { if ( owner == UMUTEX_UNOWNED || owner == UMUTEX_CONTESTED || owner == UMUTEX_RB_OWNERDEAD || owner == UMUTEX_RB_NOTRECOV ) return ( 0 ) ; } else { if ( owner == UMUTEX_RB_OWNERDEAD ) { rv = casueword32 ( & m -> m_owner , UMUTEX_RB_OWNERDEAD , & owner , id | UMUTEX_CONTESTED ) ; if ( rv == -1 ) return ( EFAULT ) ; if ( owner == UMUTEX_RB_OWNERDEAD ) return ( EOWNERDEAD ) ; rv = umtxq_check_susp ( td ) ; if ( rv != 0 ) return ( rv ) ; continue ; } if ( owner == UMUTEX_RB_NOTRECOV ) return ( ENOTRECOVERABLE ) ; rv = casueword32 ( & m -> m_owner , UMUTEX_UNOWNED , & owner , id ) ; if ( rv == -1 ) return ( EFAULT ) ; if ( owner == UMUTEX_UNOWNED ) return ( 0 ) ; if ( owner == UMUTEX_CONTESTED ) { rv = casueword32 ( & m -> m_owner , UMUTEX_CONTESTED , & owner , id | UMUTEX_CONTESTED ) ; if ( rv == -1 ) return ( EFAULT ) ; if ( owner == UMUTEX_CONTESTED ) return ( 0 ) ; rv = umtxq_check_susp ( td ) ; if ( rv != 0 ) return ( rv ) ; continue ; } } if ( mode == _UMUTEX_TRY ) return ( EBUSY ) ; if ( error != 0 ) return ( error ) ; if ( ( error = umtx_key_get ( m , TYPE_NORMAL_UMUTEX , GET_SHARE ( flags ) , & uq -> uq_key ) ) != 0 ) return ( error ) ; umtxq_lock ( & uq -> uq_key ) ; umtxq_busy ( & uq -> uq_key ) ; umtxq_insert ( uq ) ; umtxq_unlock ( & uq -> uq_key ) ; rv = casueword32 ( & m -> m_owner , owner , & old , owner | UMUTEX_CONTESTED ) ; if ( rv == -1 ) { umtxq_lock ( & uq -> uq_key ) ; umtxq_remove ( uq ) ; umtxq_unbusy ( & uq -> uq_key ) ; umtxq_unlock ( & uq -> uq_key ) ; umtx_key_release ( & uq -> uq_key ) ; return ( EFAULT ) ; } umtxq_lock ( & uq -> uq_key ) ; umtxq_unbusy ( & uq -> uq_key ) ; if ( old == owner ) error = umtxq_sleep ( uq , " " , timeout == NULL ? NULL : & timo ) ; umtxq_remove ( uq ) ; umtxq_unlock ( & uq -> uq_key ) ; umtx_key_release ( & uq -> uq_key ) ; if ( error == 0 ) error = umtxq_check_susp ( td ) ; } return ( 0 ) ; }
Lock PTHREAD_PRIO_NONE protocol POSIX mutex.
Lock PTHREAD_PRIO_NONE protocol POSIX mutex .
/*
	 * Care must be exercised when dealing with umtx structure. It
	 * can fault on any access.
	 */ /*
			 * Robust mutex terminated.  Kernel duty is to
			 * return EOWNERDEAD to the userspace.  The
			 * umutex.m_flags UMUTEX_NONCONSISTENT is set
			 * by the common userspace code.
			 */ /* success */ /*
			 * Try the uncontested case.  This should be
			 * done in userland.
			 */ /* The address was invalid. */ /* The acquire succeeded. */ /*
			 * If no one owns it but it is contested try
			 * to acquire it.
			 */ /* The address was invalid. */ /*
				 * If this failed the lock has
				 * changed, restart.
				 */ /*
		 * If we caught a signal, we have retried and now
		 * exit immediately.
		 */ /*
		 * Set the contested bit so that a release in user space
		 * knows to use the system call for unlock.  If this fails
		 * either some one else has acquired the lock or it has been
		 * released.
		 */ /* The address was invalid. */ /*
		 * We set the contested bit, sleep. Otherwise the lock changed
		 * and we need to retry or we lost a race to the thread
		 * unlocking the umtx.
		 */