ntsync.rst 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. ===================================
  2. NT synchronization primitive driver
  3. ===================================
  4. This page documents the user-space API for the ntsync driver.
  5. ntsync is a support driver for emulation of NT synchronization
  6. primitives by user-space NT emulators. It exists because implementation
  7. in user-space, using existing tools, cannot match Windows performance
  8. while offering accurate semantics. It is implemented entirely in
  9. software, and does not drive any hardware device.
  10. This interface is meant as a compatibility tool only, and should not
  11. be used for general synchronization. Instead use generic, versatile
  12. interfaces such as futex(2) and poll(2).
  13. Synchronization primitives
  14. ==========================
  15. The ntsync driver exposes three types of synchronization primitives:
  16. semaphores, mutexes, and events.
  17. A semaphore holds a single volatile 32-bit counter, and a static 32-bit
  18. integer denoting the maximum value. It is considered signaled (that is,
  19. can be acquired without contention, or will wake up a waiting thread)
  20. when the counter is nonzero. The counter is decremented by one when a
  21. wait is satisfied. Both the initial and maximum count are established
  22. when the semaphore is created.
  23. A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit
  24. identifier denoting its owner. A mutex is considered signaled when its
  25. owner is zero (indicating that it is not owned). The recursion count is
  26. incremented when a wait is satisfied, and ownership is set to the given
  27. identifier.
  28. A mutex also holds an internal flag denoting whether its previous owner
  29. has died; such a mutex is said to be abandoned. Owner death is not
  30. tracked automatically based on thread death, but rather must be
  31. communicated using ``NTSYNC_IOC_MUTEX_KILL``. An abandoned mutex is
  32. inherently considered unowned.
  33. Except for the "unowned" semantics of zero, the actual value of the
  34. owner identifier is not interpreted by the ntsync driver at all. The
  35. intended use is to store a thread identifier; however, the ntsync
  36. driver does not actually validate that a calling thread provides
  37. consistent or unique identifiers.
  38. An event is similar to a semaphore with a maximum count of one. It holds
  39. a volatile boolean state denoting whether it is signaled or not. There
  40. are two types of events, auto-reset and manual-reset. An auto-reset
  41. event is designaled when a wait is satisfied; a manual-reset event is
  42. not. The event type is specified when the event is created.
  43. Unless specified otherwise, all operations on an object are atomic and
  44. totally ordered with respect to other operations on the same object.
  45. Objects are represented by files. When all file descriptors to an
  46. object are closed, that object is deleted.
  47. Char device
  48. ===========
  49. The ntsync driver creates a single char device /dev/ntsync. Each file
  50. description opened on the device represents a unique instance intended
  51. to back an individual NT virtual machine. Objects created by one ntsync
  52. instance may only be used with other objects created by the same
  53. instance.
  54. ioctl reference
  55. ===============
  56. All operations on the device are done through ioctls. There are four
  57. structures used in ioctl calls::
  58. struct ntsync_sem_args {
  59. __u32 count;
  60. __u32 max;
  61. };
  62. struct ntsync_mutex_args {
  63. __u32 owner;
  64. __u32 count;
  65. };
  66. struct ntsync_event_args {
  67. __u32 signaled;
  68. __u32 manual;
  69. };
  70. struct ntsync_wait_args {
  71. __u64 timeout;
  72. __u64 objs;
  73. __u32 count;
  74. __u32 owner;
  75. __u32 index;
  76. __u32 alert;
  77. __u32 flags;
  78. __u32 pad;
  79. };
  80. Depending on the ioctl, members of the structure may be used as input,
  81. output, or not at all.
  82. The ioctls on the device file are as follows:
  83. .. c:macro:: NTSYNC_IOC_CREATE_SEM
  84. Create a semaphore object. Takes a pointer to struct
  85. :c:type:`ntsync_sem_args`, which is used as follows:
  86. .. list-table::
  87. * - ``count``
  88. - Initial count of the semaphore.
  89. * - ``max``
  90. - Maximum count of the semaphore.
  91. Fails with ``EINVAL`` if ``count`` is greater than ``max``.
  92. On success, returns a file descriptor the created semaphore.
  93. .. c:macro:: NTSYNC_IOC_CREATE_MUTEX
  94. Create a mutex object. Takes a pointer to struct
  95. :c:type:`ntsync_mutex_args`, which is used as follows:
  96. .. list-table::
  97. * - ``count``
  98. - Initial recursion count of the mutex.
  99. * - ``owner``
  100. - Initial owner of the mutex.
  101. If ``owner`` is nonzero and ``count`` is zero, or if ``owner`` is
  102. zero and ``count`` is nonzero, the function fails with ``EINVAL``.
  103. On success, returns a file descriptor the created mutex.
  104. .. c:macro:: NTSYNC_IOC_CREATE_EVENT
  105. Create an event object. Takes a pointer to struct
  106. :c:type:`ntsync_event_args`, which is used as follows:
  107. .. list-table::
  108. * - ``signaled``
  109. - If nonzero, the event is initially signaled, otherwise
  110. nonsignaled.
  111. * - ``manual``
  112. - If nonzero, the event is a manual-reset event, otherwise
  113. auto-reset.
  114. On success, returns a file descriptor the created event.
  115. The ioctls on the individual objects are as follows:
  116. .. c:macro:: NTSYNC_IOC_SEM_POST
  117. Post to a semaphore object. Takes a pointer to a 32-bit integer,
  118. which on input holds the count to be added to the semaphore, and on
  119. output contains its previous count.
  120. If adding to the semaphore's current count would raise the latter
  121. past the semaphore's maximum count, the ioctl fails with
  122. ``EOVERFLOW`` and the semaphore is not affected. If raising the
  123. semaphore's count causes it to become signaled, eligible threads
  124. waiting on this semaphore will be woken and the semaphore's count
  125. decremented appropriately.
  126. .. c:macro:: NTSYNC_IOC_MUTEX_UNLOCK
  127. Release a mutex object. Takes a pointer to struct
  128. :c:type:`ntsync_mutex_args`, which is used as follows:
  129. .. list-table::
  130. * - ``owner``
  131. - Specifies the owner trying to release this mutex.
  132. * - ``count``
  133. - On output, contains the previous recursion count.
  134. If ``owner`` is zero, the ioctl fails with ``EINVAL``. If ``owner``
  135. is not the current owner of the mutex, the ioctl fails with
  136. ``EPERM``.
  137. The mutex's count will be decremented by one. If decrementing the
  138. mutex's count causes it to become zero, the mutex is marked as
  139. unowned and signaled, and eligible threads waiting on it will be
  140. woken as appropriate.
  141. .. c:macro:: NTSYNC_IOC_SET_EVENT
  142. Signal an event object. Takes a pointer to a 32-bit integer, which on
  143. output contains the previous state of the event.
  144. Eligible threads will be woken, and auto-reset events will be
  145. designaled appropriately.
  146. .. c:macro:: NTSYNC_IOC_RESET_EVENT
  147. Designal an event object. Takes a pointer to a 32-bit integer, which
  148. on output contains the previous state of the event.
  149. .. c:macro:: NTSYNC_IOC_PULSE_EVENT
  150. Wake threads waiting on an event object while leaving it in an
  151. unsignaled state. Takes a pointer to a 32-bit integer, which on
  152. output contains the previous state of the event.
  153. A pulse operation can be thought of as a set followed by a reset,
  154. performed as a single atomic operation. If two threads are waiting on
  155. an auto-reset event which is pulsed, only one will be woken. If two
  156. threads are waiting a manual-reset event which is pulsed, both will
  157. be woken. However, in both cases, the event will be unsignaled
  158. afterwards, and a simultaneous read operation will always report the
  159. event as unsignaled.
  160. .. c:macro:: NTSYNC_IOC_READ_SEM
  161. Read the current state of a semaphore object. Takes a pointer to
  162. struct :c:type:`ntsync_sem_args`, which is used as follows:
  163. .. list-table::
  164. * - ``count``
  165. - On output, contains the current count of the semaphore.
  166. * - ``max``
  167. - On output, contains the maximum count of the semaphore.
  168. .. c:macro:: NTSYNC_IOC_READ_MUTEX
  169. Read the current state of a mutex object. Takes a pointer to struct
  170. :c:type:`ntsync_mutex_args`, which is used as follows:
  171. .. list-table::
  172. * - ``owner``
  173. - On output, contains the current owner of the mutex, or zero
  174. if the mutex is not currently owned.
  175. * - ``count``
  176. - On output, contains the current recursion count of the mutex.
  177. If the mutex is marked as abandoned, the function fails with
  178. ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to
  179. zero.
  180. .. c:macro:: NTSYNC_IOC_READ_EVENT
  181. Read the current state of an event object. Takes a pointer to struct
  182. :c:type:`ntsync_event_args`, which is used as follows:
  183. .. list-table::
  184. * - ``signaled``
  185. - On output, contains the current state of the event.
  186. * - ``manual``
  187. - On output, contains 1 if the event is a manual-reset event,
  188. and 0 otherwise.
  189. .. c:macro:: NTSYNC_IOC_KILL_OWNER
  190. Mark a mutex as unowned and abandoned if it is owned by the given
  191. owner. Takes an input-only pointer to a 32-bit integer denoting the
  192. owner. If the owner is zero, the ioctl fails with ``EINVAL``. If the
  193. owner does not own the mutex, the function fails with ``EPERM``.
  194. Eligible threads waiting on the mutex will be woken as appropriate
  195. (and such waits will fail with ``EOWNERDEAD``, as described below).
  196. .. c:macro:: NTSYNC_IOC_WAIT_ANY
  197. Poll on any of a list of objects, atomically acquiring at most one.
  198. Takes a pointer to struct :c:type:`ntsync_wait_args`, which is
  199. used as follows:
  200. .. list-table::
  201. * - ``timeout``
  202. - Absolute timeout in nanoseconds. If ``NTSYNC_WAIT_REALTIME``
  203. is set, the timeout is measured against the REALTIME clock;
  204. otherwise it is measured against the MONOTONIC clock. If the
  205. timeout is equal to or earlier than the current time, the
  206. function returns immediately without sleeping. If ``timeout``
  207. is U64_MAX, the function will sleep until an object is
  208. signaled, and will not fail with ``ETIMEDOUT``.
  209. * - ``objs``
  210. - Pointer to an array of ``count`` file descriptors
  211. (specified as an integer so that the structure has the same
  212. size regardless of architecture). If any object is
  213. invalid, the function fails with ``EINVAL``.
  214. * - ``count``
  215. - Number of objects specified in the ``objs`` array.
  216. If greater than ``NTSYNC_MAX_WAIT_COUNT``, the function fails
  217. with ``EINVAL``.
  218. * - ``owner``
  219. - Mutex owner identifier. If any object in ``objs`` is a mutex,
  220. the ioctl will attempt to acquire that mutex on behalf of
  221. ``owner``. If ``owner`` is zero, the ioctl fails with
  222. ``EINVAL``.
  223. * - ``index``
  224. - On success, contains the index (into ``objs``) of the object
  225. which was signaled. If ``alert`` was signaled instead,
  226. this contains ``count``.
  227. * - ``alert``
  228. - Optional event object file descriptor. If nonzero, this
  229. specifies an "alert" event object which, if signaled, will
  230. terminate the wait. If nonzero, the identifier must point to a
  231. valid event.
  232. * - ``flags``
  233. - Zero or more flags. Currently the only flag is
  234. ``NTSYNC_WAIT_REALTIME``, which causes the timeout to be
  235. measured against the REALTIME clock instead of MONOTONIC.
  236. * - ``pad``
  237. - Unused, must be set to zero.
  238. This function attempts to acquire one of the given objects. If unable
  239. to do so, it sleeps until an object becomes signaled, subsequently
  240. acquiring it, or the timeout expires. In the latter case the ioctl
  241. fails with ``ETIMEDOUT``. The function only acquires one object, even
  242. if multiple objects are signaled.
  243. A semaphore is considered to be signaled if its count is nonzero, and
  244. is acquired by decrementing its count by one. A mutex is considered
  245. to be signaled if it is unowned or if its owner matches the ``owner``
  246. argument, and is acquired by incrementing its recursion count by one
  247. and setting its owner to the ``owner`` argument. An auto-reset event
  248. is acquired by designaling it; a manual-reset event is not affected
  249. by acquisition.
  250. Acquisition is atomic and totally ordered with respect to other
  251. operations on the same object. If two wait operations (with different
  252. ``owner`` identifiers) are queued on the same mutex, only one is
  253. signaled. If two wait operations are queued on the same semaphore,
  254. and a value of one is posted to it, only one is signaled.
  255. If an abandoned mutex is acquired, the ioctl fails with
  256. ``EOWNERDEAD``. Although this is a failure return, the function may
  257. otherwise be considered successful. The mutex is marked as owned by
  258. the given owner (with a recursion count of 1) and as no longer
  259. abandoned, and ``index`` is still set to the index of the mutex.
  260. The ``alert`` argument is an "extra" event which can terminate the
  261. wait, independently of all other objects.
  262. It is valid to pass the same object more than once, including by
  263. passing the same event in the ``objs`` array and in ``alert``. If a
  264. wakeup occurs due to that object being signaled, ``index`` is set to
  265. the lowest index corresponding to that object.
  266. The function may fail with ``EINTR`` if a signal is received.
  267. .. c:macro:: NTSYNC_IOC_WAIT_ALL
  268. Poll on a list of objects, atomically acquiring all of them. Takes a
  269. pointer to struct :c:type:`ntsync_wait_args`, which is used
  270. identically to ``NTSYNC_IOC_WAIT_ANY``, except that ``index`` is
  271. always filled with zero on success if not woken via alert.
  272. This function attempts to simultaneously acquire all of the given
  273. objects. If unable to do so, it sleeps until all objects become
  274. simultaneously signaled, subsequently acquiring them, or the timeout
  275. expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and no
  276. objects are modified.
  277. Objects may become signaled and subsequently designaled (through
  278. acquisition by other threads) while this thread is sleeping. Only
  279. once all objects are simultaneously signaled does the ioctl acquire
  280. them and return. The entire acquisition is atomic and totally ordered
  281. with respect to other operations on any of the given objects.
  282. If an abandoned mutex is acquired, the ioctl fails with
  283. ``EOWNERDEAD``. Similarly to ``NTSYNC_IOC_WAIT_ANY``, all objects are
  284. nevertheless marked as acquired. Note that if multiple mutex objects
  285. are specified, there is no way to know which were marked as
  286. abandoned.
  287. As with "any" waits, the ``alert`` argument is an "extra" event which
  288. can terminate the wait. Critically, however, an "all" wait will
  289. succeed if all members in ``objs`` are signaled, *or* if ``alert`` is
  290. signaled. In the latter case ``index`` will be set to ``count``. As
  291. with "any" waits, if both conditions are filled, the former takes
  292. priority, and objects in ``objs`` will be acquired.
  293. Unlike ``NTSYNC_IOC_WAIT_ANY``, it is not valid to pass the same
  294. object more than once, nor is it valid to pass the same object in
  295. ``objs`` and in ``alert``. If this is attempted, the function fails
  296. with ``EINVAL``.