1.\" 2.\" SPDX-License-Identifier: BSD-2-Clause 3.\" 4.\" Copyright 2026 The FreeBSD Foundation 5.\" 6.\" This documentation was written by Konstantin Belousov <kib@FreeBSD.org> 7.\" under sponsorship from the FreeBSD Foundation. 8.\" 9.Dd June 19, 2026 10.Dt NTSYNC 4 11.Os 12.Sh NAME 13.Nm ntsync 14.Nd NT-like synchronization operations device driver 15.Sh SYNOPSIS 16.In dev/ntsync/ntsync.h 17.Sh DESCRIPTION 18The 19.Nm 20device driver provides synchronization primitives that mimic the operations 21provided by the Windows NT kernel. 22The userspace interface is copied from the identically named driver written 23for the Linux kernel, with the goal of helping Wine implement Win32 API. 24.Pp 25The driver provides the 26.Pa /dev/ntsync 27special device node that handles 28.Xr ioctl 2 29requests of several groups: 30.Bl -tag -width "wait operations:" 31.It object creation: 32among them semaphores, mutexes, and events 33.It wait operations: 34waiting for the set of objects to become signaled, either all 35or any objects in the set can be waited for 36.El 37.Pp 38An 39.Xr open 2 40of the 41.Pa /dev/ntsync 42device returns the file descriptor which represents the synchronization 43domain. 44Each object created by the 45.Xr ioctl 2 46on the ntsync file descriptor belongs to it's domain. 47Wait requests must not mix the objects belonging to other domains. 48.Pp 49The synchronization objects are represented by file descriptors, each 50implementing type-specific set of ioctl requests. 51.Sh SEMAPHORES 52The semaphores operations usually take the 53.Bd -literal 54struct ntsync_sem_args { 55 uint32_t count; 56 uint32_t max; 57} 58.Ed 59as an argument. 60The semaphore requests are: 61.Bl -tag -width "NTSYNC_IOC_SEM_RELEASE" 62.It Dv NTSYNC_IOC_CREATE_SEM 63Creates the semaphore and returns the semaphore file descriptor. 64Must be issued on the 65.Pa /dev/ntsync 66file descriptor. 67.Pp 68Takes the 69.Va struct ntsync_sem_args 70argument, where 71.Dv count 72is the initial semaphore count, and 73.Dv max 74is the maximum allowed count. 75.It Dv NTSYNC_IOC_SEM_RELEASE 76Releases the semaphore. 77Takes the single 78.Va uint32_t 79value which is used to decrement the semaphore count. 80If the semaphore count reaches zero, the semaphore becomes signaled. 81.It Dv NTSYNC_IOC_SEM_READ 82Returns the current state of the semaphore in the 83.Va struct ntsync_sem_args . 84.El 85.Sh MUTEXES 86The mutexes operations usually take the 87.Bd -literal 88struct ntsync_mutex_args { 89 uint32_t owner; 90 uint32_t count; 91} 92.Ed 93as the argument. 94.Pp 95The mutex requests are: 96.Bl -tag -width "NTSYNC_IOC_CREATE_MUTEX" 97.It Dv NTSYNC_IOC_CREATE_MUTEX 98Creates the mutex and returns the mutex file descriptor. 99Must be issued on the 100.Pa /dev/ntsync 101file descriptor. 102.Pp 103Takes the 104.Va struct ntsync_mutex_args 105as the argument. 106The 107.Dv owner 108is an abstract 32bit number that identifies the current mutex owner. 109If 110.Dv owner 111is zero, the mutex is unowned, and 112.Dv count 113must be zero. 114If 115.Dv count 116is non-zero, indicating the owned mutex, a non-zero 117.Dv owner 118must be provided. 119.It Dv NTSYNC_IOC_MUTEX_UNLOCK 120Unlocks the mutex. 121Takes the 122.Va struct ntsync_mutex_args 123argument. 124.Pp 125The mutex must be owned by the argument's 126.Dv owner . 127Successful unlock decrements mutex' counter, and makes the mutex 128signaled and unowned if the counter reaches zero. 129.Pp 130The counter value before unlock is returned in the 131.Dv count 132member of the argument structure. 133.It Dv NTSYNC_IOC_MUTEX_KILL 134Abandon the mutex. 135Takes a single 32bit integer as the argument, indicating the current 136mutex owner. 137.Pp 138The specified owner must be equal to the current mutex owner. 139Then, the pending waiters are woken up, and get the 140.Ev EOWNERDEAD 141result. 142The mutex owner and counter are set to zero. 143.Pp 144The abandoned state is cleared by next successful wait on the mutex. 145.It Dv NTSYNC_IOC_MUTEX_READ 146Returns the current state of the mutex. 147Takes the 148.Va struct ntsync_mutex_args 149argument where the state is returned. 150For abandoned mutexes, the 151.Ev EOWNERDEAD 152error is returned in addition to the state. 153.El 154.Sh EVENTS 155The events operations usually take the 156.Bd -literal 157struct ntsync_event_args { 158 uint32_t manual; 159 uint32_t signaled; 160} 161.Ed 162.Pp 163The events requests are: 164.Bl -tag -width "NTSYNC_IOC_CREATE_EVENT" 165.It Dv NTSYNC_IOC_CREATE_EVENT 166Creates the event and returns the event file descriptor. 167Must be issued on the 168.Pa /dev/ntsync 169file descriptor. 170Takes the 171.Va struct ntsync_event_args 172argument. 173.Pp 174Events can be of two types: manual and automatic. 175Manual events needs to be reset by the request after being set. 176Automatic events are reset by the system after a wait is satisfied. 177.It Dv NTSYNC_IOC_EVENT_SET 178Set (arm) the event. 179Takes a 32bit integer argument where the state of the event before 180the operation is returned. 181.It Dv NTSYNC_IOC_EVENT_RESET 182Reset (dis-arms) the event. 183Takes a 32bit integer argument where the state of the event before 184the operation is returned. 185.It Dv NTSYNC_IOC_EVENT_PULSE 186Atomically sets the event, wakes up eligible waiters, 187and then resets the event. 188Takes a 32bit integer argument where the state of the event before 189the operation is returned. 190.Pp 191If the manual event is pulsed, it wakes up all waiters, 192after which it is reset. 193On the other hand, the automatic event is reset after 194waking up at most a single waiter. 195.It Dv NTSYNC_IOC_EVENT_READ 196Returns the current state of the event. 197Takes the 198.Va struct ntsync_event_args 199argument where the current event state is returned. 200.El 201.Sh WAIT OPERATIONS 202Wait operations take the 203.Bd -literal 204struct ntsync_wait_args { 205 uint64_t timeout; 206 uint64_t objs; 207 uint32_t count; 208 uint32_t index; 209 uint32_t flags; 210 uint32_t owner; 211 uint32_t alert; 212 uint32_t pad; 213} 214.Ed 215as the argument. 216.Pp 217The signaled state of the objects which cause the wait to 218become satisfied are consumed by the operation, 219e.g. the semaphore is acquired by incrementing its counter, 220the mutex is locked, 221and the manual event becomes not signaled. 222.Pp 223The 224.Dv timeout 225is in the nanoseconds. 226If 227.Dv timeout 228is zero, the wait request only returns when either the wait 229condition is satisfied, or a signal is queued. 230Otherwise, if the wait is not satisfied after the specified time, 231it is aborted anyway and the 232.Er ETIMEDOUT 233error is returned. 234.Pp 235The 236.Dv objs 237member points to the array of the synchronization object's file 238descriptors. 239Its size if passed in the 240.Dv count 241member. 242It might be as large as 243.Dv NTSYNC_MAX_WAIT_COUNT , 244which is 64. 245.Pp 246The 247.Dv alert 248if non-zero specifies the event file descriptor, 249signaling of which finishes the wait regardless the state of 250other objects in the 251.Dv objs 252array. 253.Pp 254On non-error return from the wait requests, the 255.Dv index 256member contains the index of the signaled object that caused 257the wait request to be satisfied. 258If the object at the index is a semaphore, the 259.Dv owner 260member reports the owner of the signaled semaphore. 261If the 262.Dv alert 263event was signaled to abort the wait, 264.Dv index 265is set to 266.Dv count . 267.Pp 268The possible values for the 269.Va flags 270parameter are 271.Bl -tag -width "NTSYNC_WAIT_REALTIME" 272.It Dv NTSYNC_WAIT_REALTIME 273The specified timeout is for 274.Dv CLOCK_REALTIME 275absolute value, otherwise it is for 276.Dv CLOCK_MONOTONIC , 277see 278.Xr clock_gettime 2 . 279.El 280.Pp 281The wait requests are: 282.Bl -tag -width "NTSYNC_IOC_WAIT_ANY" 283.It Dv NTSYNC_IOC_WAIT_ANY 284Wait for any of the objects to become signaled. 285.It Dv NTSYNC_IOC_WAIT_ALL 286Wait for all of the objects to become signaled. 287This means that the wait is satisfied only when all objects 288can be consumed together, which is done atomically. 289.Pp 290No duplicate objects are allowed in the 291.Dv objs 292array. 293The 294.Dv alert 295object is not allowed to be listed in the 296.Dv objs 297array. 298.El 299.Sh SEE ALSO 300Refer to the file 301.Pa Documentation/userspace-api/ntsync.rst 302in the Linux kernel sources for the Linux API reference, 303that was used for the implementation of the 304.Fx 305driver. 306.Sh HISTORY 307The 308.Nm 309driver and manual page first appeared in 310.Fx 15.2 . 311.Sh AUTHORS 312.An -nosplit 313The driver and the manual page were written by 314.An Konstantin Belousov Aq Mt kib@FreeBSD.org . 315