Reference

ntsync(4)

NT-like synchronization operations device driver

NAME

ntsync – NT-like synchronization operations device driver

SYNOPSIS

#include <dev/ntsync/ntsync.h>

DESCRIPTION

The ntsync device driver provides synchronization primitives that mimic the operations provided by the Windows NT kernel. The userspace interface is copied from the identically named driver written for the Linux kernel, with the goal of helping Wine implement Win32 API.

The driver provides the /dev/ntsync special device node that handles ioctl(2) requests of several groups:

object creation:

among them semaphores, mutexes, and events

wait operations:

waiting for the set of objects to become signaled, either all or any objects in the set can be waited for

An open(2) of the /dev/ntsync device returns the file descriptor which represents the synchronization domain. Each object created by the ioctl(2) on the ntsync file descriptor belongs to it's domain. Wait requests must not mix the objects belonging to other domains.

The synchronization objects are represented by file descriptors, each implementing type-specific set of ioctl requests.

SEMAPHORES

The semaphores operations usually take the

struct ntsync_sem_args {
	uint32_t count;
	uint32_t max;
}

as an argument. The semaphore requests are:

NTSYNC_IOC_CREATE_SEM

Creates the semaphore and returns the semaphore file descriptor. Must be issued on the /dev/ntsync file descriptor.

Takes the struct ntsync_sem_args argument, where count is the initial semaphore count, and max is the maximum allowed count.

NTSYNC_IOC_SEM_RELEASE

Releases the semaphore. Takes the single uint32_t value which is used to decrement the semaphore count. If the semaphore count reaches zero, the semaphore becomes signaled.

NTSYNC_IOC_SEM_READ

Returns the current state of the semaphore in the struct ntsync_sem_args.

MUTEXES

The mutexes operations usually take the

struct ntsync_mutex_args {
	uint32_t owner;
	uint32_t count;
}

as the argument.

The mutex requests are:

NTSYNC_IOC_CREATE_MUTEX

Creates the mutex and returns the mutex file descriptor. Must be issued on the /dev/ntsync file descriptor.

Takes the struct ntsync_mutex_args as the argument. The owner is an abstract 32bit number that identifies the current mutex owner. If owner is zero, the mutex is unowned, and count must be zero. If count is non-zero, indicating the owned mutex, a non-zero owner must be provided.

NTSYNC_IOC_MUTEX_UNLOCK

Unlocks the mutex. Takes the struct ntsync_mutex_args argument.

The mutex must be owned by the argument's owner. Successful unlock decrements mutex' counter, and makes the mutex signaled and unowned if the counter reaches zero.

The counter value before unlock is returned in the count member of the argument structure.

NTSYNC_IOC_MUTEX_KILL

Abandon the mutex. Takes a single 32bit integer as the argument, indicating the current mutex owner.

The specified owner must be equal to the current mutex owner. Then, the pending waiters are woken up, and get the EOWNERDEAD result. The mutex owner and counter are set to zero.

The abandoned state is cleared by next successful wait on the mutex.

NTSYNC_IOC_MUTEX_READ

Returns the current state of the mutex. Takes the struct ntsync_mutex_args argument where the state is returned. For abandoned mutexes, the EOWNERDEAD error is returned in addition to the state.

EVENTS

The events operations usually take the

struct ntsync_event_args {
	uint32_t manual;
	uint32_t signaled;
}

The events requests are:

NTSYNC_IOC_CREATE_EVENT

Creates the event and returns the event file descriptor. Must be issued on the /dev/ntsync file descriptor. Takes the struct ntsync_event_args argument.

Events can be of two types: manual and automatic. Manual events needs to be reset by the request after being set. Automatic events are reset by the system after a wait is satisfied.

NTSYNC_IOC_EVENT_SET

Set (arm) the event. Takes a 32bit integer argument where the state of the event before the operation is returned.

NTSYNC_IOC_EVENT_RESET

Reset (dis-arms) the event. Takes a 32bit integer argument where the state of the event before the operation is returned.

NTSYNC_IOC_EVENT_PULSE

Atomically sets the event, wakes up eligible waiters, and then resets the event. Takes a 32bit integer argument where the state of the event before the operation is returned.

If the manual event is pulsed, it wakes up all waiters, after which it is reset. On the other hand, the automatic event is reset after waking up at most a single waiter.

NTSYNC_IOC_EVENT_READ

Returns the current state of the event. Takes the struct ntsync_event_args argument where the current event state is returned.

WAIT OPERATIONS

Wait operations take the

struct ntsync_wait_args {
	uint64_t timeout;
	uint64_t objs;
	uint32_t count;
	uint32_t index;
	uint32_t flags;
	uint32_t owner;
	uint32_t alert;
	uint32_t pad;
}

as the argument.

The signaled state of the objects which cause the wait to become satisfied are consumed by the operation, e.g. the semaphore is acquired by incrementing its counter, the mutex is locked, and the manual event becomes not signaled.

The timeout is in the nanoseconds. If timeout is zero, the wait request only returns when either the wait condition is satisfied, or a signal is queued. Otherwise, if the wait is not satisfied after the specified time, it is aborted anyway and the ETIMEDOUT error is returned.

The objs member points to the array of the synchronization object's file descriptors. Its size if passed in the count member. It might be as large as NTSYNC_MAX_WAIT_COUNT, which is 64.

The alert if non-zero specifies the event file descriptor, signaling of which finishes the wait regardless the state of other objects in the objs array.

On non-error return from the wait requests, the index member contains the index of the signaled object that caused the wait request to be satisfied. If the object at the index is a semaphore, the owner member reports the owner of the signaled semaphore. If the alert event was signaled to abort the wait, index is set to count.

The possible values for the flags parameter are

NTSYNC_WAIT_REALTIME

The specified timeout is for CLOCK_REALTIME absolute value, otherwise it is for CLOCK_MONOTONIC, see clock_gettime(2).

The wait requests are:

NTSYNC_IOC_WAIT_ANY

Wait for any of the objects to become signaled.

NTSYNC_IOC_WAIT_ALL

Wait for all of the objects to become signaled. This means that the wait is satisfied only when all objects can be consumed together, which is done atomically.

No duplicate objects are allowed in the objs array. The alert object is not allowed to be listed in the objs array.

SEE ALSO

Refer to the file Documentation/userspace-api/ntsync.rst in the Linux kernel sources for the Linux API reference, that was used for the implementation of the FreeBSD driver.

HISTORY

The ntsync driver and manual page first appeared in FreeBSD 15.2.

AUTHORS

The driver and the manual page were written by Konstantin Belousov ⟨[email protected]⟩.