sys/kern/kern_umtx.c
int
sys_umtx_sleep(struct umtx_sleep_args *uap)
{
    struct lwbuf lwb_cache;
    struct lwbuf *lwb;
    struct vm_page_action action;
    vm_page_t m;
    void *waddr;
    int offset;
    int timeout;
    int error = EBUSY;

    if (uap->timeout < 0)
	return (EINVAL);
    if ((vm_offset_t)uap->ptr & (sizeof(int) - 1))
	return (EFAULT);

    /*
     * When faulting in the page, force any COW pages to be resolved.
     * Otherwise the physical page we sleep on my not match the page
     * being woken up.
     */
    m = vm_fault_page_quick((vm_offset_t)uap->ptr,
			    VM_PROT_READ|VM_PROT_WRITE, &error);
    if (m == NULL) {
	error = EFAULT;
	goto done;
    }
    lwb = lwbuf_alloc(m, &lwb_cache);
    offset = (vm_offset_t)uap->ptr & PAGE_MASK;

    /*
     * The critical section is required to interlock the tsleep against
     * a wakeup from another cpu.  The lfence forces synchronization.
     */
    if (*(int *)(lwbuf_kva(lwb) + offset) == uap->value) {
	if ((timeout = uap->timeout) != 0) {
	    timeout = (timeout / 1000000) * hz +
		      ((timeout % 1000000) * hz + 999999) / 1000000;
	}
	waddr = (void *)((intptr_t)VM_PAGE_TO_PHYS(m) + offset);
	crit_enter();
	tsleep_interlock(waddr, PCATCH | PDOMAIN_UMTX);
	if (*(int *)(lwbuf_kva(lwb) + offset) == uap->value) {
	    vm_page_init_action(m, &action, umtx_sleep_page_action_cow, waddr);
	    vm_page_register_action(&action, VMEVENT_COW);
	    if (*(int *)(lwbuf_kva(lwb) + offset) == uap->value) {
		    error = tsleep(waddr, PCATCH | PINTERLOCKED | PDOMAIN_UMTX,
				   "umtxsl", timeout);
	    } else {
		    error = EBUSY;
	    }
	    vm_page_unregister_action(&action);
	} else {
	    error = EBUSY;
	}
	crit_exit();
	/* Always break out in case of signal, even if restartable */
	if (error == ERESTART)
		error = EINTR;
    } else {
	error = EBUSY;
    }

    lwbuf_free(lwb);
    /*vm_page_dirty(m); we don't actually dirty the page */
    vm_page_unhold(m);
done:
    return(error);
}
/*
 * If the contents of the userland-supplied pointer matches the specified
 * value enter an interruptable sleep for up to <timeout> microseconds.
 * If the contents does not match then return immediately.
 *
 * Returns 0 if we slept and were woken up, -1 and EWOULDBLOCK if we slept
 * and timed out, and EBUSY if the contents of the pointer already does
 * not match the specified value.  A timeout of 0 indicates an unlimited sleep.
 * EINTR is returned if the call was interrupted by a signal (even if
 * the signal specifies that the system call should restart).
 *
 * This function interlocks against call to umtx_wakeup.  It does NOT interlock
 * against changes in *ptr.  However, it does not have to.  The standard use
 * of *ptr is to differentiate between an uncontested and a contested mutex
 * and call umtx_wakeup when releasing a contested mutex.  Therefore we can
 * safely race against changes in *ptr as long as we are properly interlocked
 * against the umtx_wakeup() call.
 *
 * The VM page associated with the mutex is held in an attempt to keep
 * the mutex's physical address consistent, allowing umtx_sleep() and
 * umtx_wakeup() to use the physical address as their rendezvous.  BUT
 * situations can arise where the physical address may change, particularly
 * if a threaded program fork()'s and the mutex's memory becomes
 * copy-on-write.  We register an event on the VM page to catch COWs.
 *
 * umtx_sleep { const int *ptr, int value, int timeout }
 */
If the contents of the userland-supplied pointer matches the specified
value enter an interruptable sleep for up to  microseconds.
If the contents does not match then return immediately.

Returns 0 if we slept and were woken up, -1 and EWOULDBLOCK if we slept
and timed out, and EBUSY if the contents of the pointer already does
not match the specified value.  A timeout of 0 indicates an unlimited sleep.
EINTR is returned if the call was interrupted by a signal (even if
the signal specifies that the system call should restart).

This function interlocks against call to umtx_wakeup.  It does NOT interlock
against changes in *ptr.  However, it does not have to.  The standard use
of *ptr is to differentiate between an uncontested and a contested mutex
and call umtx_wakeup when releasing a contested mutex.  Therefore we can
safely race against changes in *ptr as long as we are properly interlocked
against the umtx_wakeup() call.

The VM page associated with the mutex is held in an attempt to keep
the mutex's physical address consistent, allowing umtx_sleep() and
umtx_wakeup() to use the physical address as their rendezvous.  BUT
situations can arise where the physical address may change, particularly
if a threaded program fork()'s and the mutex's memory becomes
copy-on-write.  We register an event on the VM page to catch COWs.


If the contents of the userland - supplied pointer matches the specified value enter an interruptable sleep for up to microseconds . If the contents does not match then return immediately . Returns 0 if we slept and were woken up - 1 and EWOULDBLOCK if we slept and timed out and EBUSY if the contents of the pointer already does not match the specified value . A timeout of 0 indicates an unlimited sleep . EINTR is returned if the call was interrupted by a signal ( even if the signal specifies that the system call should restart ) . This function interlocks against call to umtx_wakeup . It does NOT interlock against changes in * ptr . However it does not have to . The standard use of * ptr is to differentiate between an uncontested and a contested mutex and call umtx_wakeup when releasing a contested mutex . Therefore we can safely race against changes in * ptr as long as we are properly interlocked against the umtx_wakeup () call . The VM page associated with the mutex is held in an attempt to keep the mutex ' s physical address consistent allowing umtx_sleep () and umtx_wakeup () to use the physical address as their rendezvous . BUT situations can arise where the physical address may change particularly if a threaded program fork () ' s and the mutex ' s memory becomes copy - on - write . We register an event on the VM page to catch COWs .
int
sys_umtx_sleep(struct umtx_sleep_args *uap)
{
    struct lwbuf lwb_cache;
    struct lwbuf *lwb;
    struct vm_page_action action;
    vm_page_t m;
    void *waddr;
    int offset;
    int timeout;
    int error = EBUSY;
    if (uap->timeout < 0)
	return (EINVAL);
    if ((vm_offset_t)uap->ptr & (sizeof(int) - 1))
	return (EFAULT);
    m = vm_fault_page_quick((vm_offset_t)uap->ptr,
			    VM_PROT_READ|VM_PROT_WRITE, &error);
    if (m == NULL) {
	error = EFAULT;
	goto done;
    }
    lwb = lwbuf_alloc(m, &lwb_cache);
    offset = (vm_offset_t)uap->ptr & PAGE_MASK;
    if (*(int *)(lwbuf_kva(lwb) + offset) == uap->value) {
	if ((timeout = uap->timeout) != 0) {
	    timeout = (timeout / 1000000) * hz +
		      ((timeout % 1000000) * hz + 999999) / 1000000;
	}
	waddr = (void *)((intptr_t)VM_PAGE_TO_PHYS(m) + offset);
	crit_enter();
	tsleep_interlock(waddr, PCATCH | PDOMAIN_UMTX);
	if (*(int *)(lwbuf_kva(lwb) + offset) == uap->value) {
	    vm_page_init_action(m, &action, umtx_sleep_page_action_cow, waddr);
	    vm_page_register_action(&action, VMEVENT_COW);
	    if (*(int *)(lwbuf_kva(lwb) + offset) == uap->value) {
		    error = tsleep(waddr, PCATCH | PINTERLOCKED | PDOMAIN_UMTX,
				   "umtxsl", timeout);
	    } else {
		    error = EBUSY;
	    }
	    vm_page_unregister_action(&action);
	} else {
	    error = EBUSY;
	}
	crit_exit();
	if (error == ERESTART)
		error = EINTR;
    } else {
	error = EBUSY;
    }
    lwbuf_free(lwb);
    vm_page_unhold(m);
done:
    return(error);
}
int sys_umtx_sleep ( struct umtx_sleep_args * uap ) { struct lwbuf lwb_cache ; struct lwbuf * lwb ; struct vm_page_action action ; vm_page_t m ; void * waddr ; int offset ; int timeout ; int error = EBUSY ; if ( uap -> timeout < 0 ) return ( EINVAL ) ; if ( ( vm_offset_t ) uap -> ptr & ( sizeof ( int ) - 1 ) ) return ( EFAULT ) ; m = vm_fault_page_quick ( ( vm_offset_t ) uap -> ptr , VM_PROT_READ | VM_PROT_WRITE , & error ) ; if ( m == NULL ) { error = EFAULT ; goto done ; } lwb = lwbuf_alloc ( m , & lwb_cache ) ; offset = ( vm_offset_t ) uap -> ptr & PAGE_MASK ; if ( * ( int * ) ( lwbuf_kva ( lwb ) + offset ) == uap -> value ) { if ( ( timeout = uap -> timeout ) != 0 ) { timeout = ( timeout / 1000000 ) * hz + ( ( timeout % 1000000 ) * hz + 999999 ) / 1000000 ; } waddr = ( void * ) ( ( intptr_t ) VM_PAGE_TO_PHYS ( m ) + offset ) ; crit_enter ( ) ; tsleep_interlock ( waddr , PCATCH | PDOMAIN_UMTX ) ; if ( * ( int * ) ( lwbuf_kva ( lwb ) + offset ) == uap -> value ) { vm_page_init_action ( m , & action , umtx_sleep_page_action_cow , waddr ) ; vm_page_register_action ( & action , VMEVENT_COW ) ; if ( * ( int * ) ( lwbuf_kva ( lwb ) + offset ) == uap -> value ) { error = tsleep ( waddr , PCATCH | PINTERLOCKED | PDOMAIN_UMTX , " " , timeout ) ; } else { error = EBUSY ; } vm_page_unregister_action ( & action ) ; } else { error = EBUSY ; } crit_exit ( ) ; if ( error == ERESTART ) error = EINTR ; } else { error = EBUSY ; } lwbuf_free ( lwb ) ; vm_page_unhold ( m ) ; done : return ( error ) ; }
If the contents of the userland-supplied pointer matches the specified
 value enter an interruptable sleep for up to <timeout> microseconds.
If the contents of the userland - supplied pointer matches the specified value enter an interruptable sleep for up to <timeout > microseconds .
/*
     * When faulting in the page, force any COW pages to be resolved.
     * Otherwise the physical page we sleep on my not match the page
     * being woken up.
     */ /*
     * The critical section is required to interlock the tsleep against
     * a wakeup from another cpu.  The lfence forces synchronization.
     */ /* Always break out in case of signal, even if restartable */ /*vm_page_dirty(m); we don't actually dirty the page */