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]⟩.