← Documents Documentation/userspace-api/ntsync.rst GitHub 원문 ↗

Linux 6.18.37 · 사용자 공간 API

NT 동기화 프리미티브 드라이버

NT 에뮬레이터용 semaphore, mutex, event 객체와 생성·상태 변경·WAIT_ANY·WAIT_ALL ioctl 의미론을 설명합니다.

Source pathDocumentation/userspace-api/ntsync.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

ntsync.rst:1-385

ntsync의 핵심은 NT 객체 의미를 한 인스턴스 안에서 원자적으로 재현하는 것입니다. 특히 abandoned mutex의 `EOWNERDEAD`는 객체 획득을 동반할 수 있고, WAIT_ALL은 모든 객체의 동시 signal과 전체 원자 획득을 요구하므로 일반적인 오류 반환이나 poll 동작으로 단순화하면 안 됩니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

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

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

ntsync의 목적과 적용 범위

1-16

이 문서는 ntsync 드라이버의 사용자 공간 API를 설명합니다.

ntsync는 사용자 공간 NT 에뮬레이터가 NT 동기화 프리미티브를 에뮬레이션하도록 돕는 드라이버입니다. 기존 사용자 공간 도구만으로는 정확한 의미론을 제공하면서 Windows 수준의 성능을 맞출 수 없기 때문에 존재합니다. 구현은 전적으로 소프트웨어이며 하드웨어 장치를 구동하지 않습니다.

이 인터페이스는 호환성 도구로만 사용해야 하며 범용 동기화에 사용해서는 안 됩니다. 일반 동기화에는 `futex(2)`와 `poll(2)` 같은 범용 인터페이스를 사용하십시오.

===================================
NT synchronization primitive driver
===================================

This page documents the user-space API for the ntsync driver.

ntsync is a support driver for emulation of NT synchronization
primitives by user-space NT emulators. It exists because implementation
in user-space, using existing tools, cannot match Windows performance
while offering accurate semantics. It is implemented entirely in
software, and does not drive any hardware device.

This interface is meant as a compatibility tool only, and should not
be used for general synchronization. Instead use generic, versatile
interfaces such as futex(2) and poll(2).

세 가지 동기화 프리미티브

17-59

ntsync 드라이버는 semaphore, mutex, event의 세 가지 동기화 프리미티브를 노출합니다.

ntsync 객체의 상태와 획득
객체보관 상태신호 상태획득 결과
semaphorevolatile 32비트 count와 고정 32비트 maxcount가 0이 아님count를 1 감소
mutexvolatile 32비트 recursion count와 owner 식별자owner가 0이거나 재귀 획득의 경우 요청 owner와 같음count를 1 증가시키고 owner 설정
auto-reset eventvolatile boolean signaledsignaled가 참대기 만족 시 비신호 상태로 전환
manual-reset eventvolatile boolean signaledsignaled가 참획득해도 상태를 유지

각 객체는 신호 상태와 대기 만족 시의 상태 전이가 다릅니다.

semaphore의 초기 count와 최대 count는 생성할 때 정합니다.

mutex는 이전 소유자가 죽었는지를 나타내는 내부 플래그도 보관하며, 이런 mutex를 abandoned 상태라고 합니다. 스레드 종료를 보고 소유자 사망을 자동 추적하지 않으므로 원문에서 지칭하는 `NTSYNC_IOC_MUTEX_KILL`을 통해 알려야 합니다. abandoned mutex는 본질적으로 소유자가 없는 것으로 간주됩니다.

0이 소유자 없음이라는 의미를 갖는 것 외에 owner 식별자의 실제 값은 ntsync가 해석하지 않습니다. 스레드 식별자를 저장하는 용도이지만 호출 스레드가 일관되거나 고유한 값을 제공하는지는 검증하지 않습니다.

event 유형은 생성 시 auto-reset 또는 manual-reset으로 지정합니다.

달리 명시하지 않는 한 같은 객체에 대한 모든 연산은 원자적이며 서로에 대해 전순서화됩니다.

객체는 파일로 표현됩니다. 객체를 가리키는 모든 파일 디스크립터가 닫히면 객체가 삭제됩니다.

Synchronization primitives
==========================

The ntsync driver exposes three types of synchronization primitives:
semaphores, mutexes, and events.

A semaphore holds a single volatile 32-bit counter, and a static 32-bit
integer denoting the maximum value. It is considered signaled (that is,
can be acquired without contention, or will wake up a waiting thread)
when the counter is nonzero. The counter is decremented by one when a
wait is satisfied. Both the initial and maximum count are established
when the semaphore is created.

A mutex holds a volatile 32-bit recursion count, and a volatile 32-bit
identifier denoting its owner. A mutex is considered signaled when its
owner is zero (indicating that it is not owned). The recursion count is
incremented when a wait is satisfied, and ownership is set to the given
identifier.

A mutex also holds an internal flag denoting whether its previous owner
has died; such a mutex is said to be abandoned. Owner death is not
tracked automatically based on thread death, but rather must be
communicated using ``NTSYNC_IOC_MUTEX_KILL``. An abandoned mutex is
inherently considered unowned.

Except for the "unowned" semantics of zero, the actual value of the
owner identifier is not interpreted by the ntsync driver at all. The
intended use is to store a thread identifier; however, the ntsync
driver does not actually validate that a calling thread provides
consistent or unique identifiers.

An event is similar to a semaphore with a maximum count of one. It holds
a volatile boolean state denoting whether it is signaled or not. There
are two types of events, auto-reset and manual-reset. An auto-reset
event is designaled when a wait is satisfied; a manual-reset event is
not. The event type is specified when the event is created.

Unless specified otherwise, all operations on an object are atomic and
totally ordered with respect to other operations on the same object.

Objects are represented by files. When all file descriptors to an
object are closed, that object is deleted.

문자 장치와 인스턴스 격리

60-68

ntsync 드라이버는 단일 문자 장치 `/dev/ntsync`를 만듭니다. 이 장치에서 연 각각의 file description은 개별 NT 가상 머신을 지원하기 위한 고유 인스턴스를 나타냅니다. 한 ntsync 인스턴스에서 만든 객체는 같은 인스턴스가 만든 다른 객체와만 함께 사용할 수 있습니다.

ntsync 객체의 범위
Open /dev/ntsync and obtain one instance descriptionCreate semaphore, mutex, and event files from that instanceUse only objects belonging to the same instanceClose every descriptor to delete an object

파일 수명과 가상 머신별 인스턴스 경계를 함께 지켜야 합니다.

Char device
===========

The ntsync driver creates a single char device /dev/ntsync. Each file
description opened on the device represents a unique instance intended
to back an individual NT virtual machine. Objects created by one ntsync
instance may only be used with other objects created by the same
instance.

ioctl 인자 구조체

69-103

장치의 모든 연산은 ioctl로 수행하며 네 구조체를 사용합니다.

   struct ntsync_sem_args {
   	__u32 count;
   	__u32 max;
   };

   struct ntsync_mutex_args {
   	__u32 owner;
   	__u32 count;
   };

   struct ntsync_event_args {
   	__u32 signaled;
   	__u32 manual;
   };

   struct ntsync_wait_args {
   	__u64 timeout;
   	__u64 objs;
   	__u32 count;
   	__u32 owner;
   	__u32 index;
   	__u32 alert;
   	__u32 flags;
   	__u32 pad;
   };
ioctl 인자 구조체
구조체핵심 필드
`ntsync_sem_args``count`, `max`
`ntsync_mutex_args``owner`, `count`
`ntsync_event_args``signaled`, `manual`
`ntsync_wait_args``timeout`, `objs`, `count`, `owner`, `index`, `alert`, `flags`, `pad`

동일한 필드도 ioctl에 따라 입력, 출력 또는 미사용으로 해석됩니다.

각 구조체 멤버가 입력인지 출력인지는 아래의 개별 ioctl 정의를 따라야 합니다.

ioctl reference
===============

All operations on the device are done through ioctls. There are four
structures used in ioctl calls::

   struct ntsync_sem_args {
   	__u32 count;
   	__u32 max;
   };

   struct ntsync_mutex_args {
   	__u32 owner;
   	__u32 count;
   };

   struct ntsync_event_args {
   	__u32 signaled;
   	__u32 manual;
   };

   struct ntsync_wait_args {
   	__u64 timeout;
   	__u64 objs;
   	__u32 count;
   	__u32 owner;
   	__u32 index;
   	__u32 alert;
   	__u32 flags;
   	__u32 pad;
   };

Depending on the ioctl, members of the structure may be used as input,
output, or not at all.

NTSYNC_IOC_CREATE_SEM

104-120

`NTSYNC_IOC_CREATE_SEM`은 semaphore 객체를 만들며 `struct ntsync_sem_args` 포인터를 받습니다.

semaphore 생성 인자
필드입력 의미
`count`semaphore의 초기 count
`max`semaphore의 최대 count

생성 성공 시 새 semaphore의 파일 디스크립터를 반환합니다.

`count`가 `max`보다 크면 `EINVAL`로 실패합니다.

The ioctls on the device file are as follows:

.. c:macro:: NTSYNC_IOC_CREATE_SEM

  Create a semaphore object. Takes a pointer to struct
  :c:type:`ntsync_sem_args`, which is used as follows:

  .. list-table::

     * - ``count``
       - Initial count of the semaphore.
     * - ``max``
       - Maximum count of the semaphore.

  Fails with ``EINVAL`` if ``count`` is greater than ``max``.
  On success, returns a file descriptor the created semaphore.

NTSYNC_IOC_CREATE_MUTEX

121-136

`NTSYNC_IOC_CREATE_MUTEX`는 mutex 객체를 만들며 `struct ntsync_mutex_args` 포인터를 받습니다.

mutex 생성 인자
필드입력 의미
`count`mutex의 초기 재귀 count
`owner`mutex의 초기 owner

생성 성공 시 새 mutex의 파일 디스크립터를 반환합니다.

`owner`는 0이 아닌데 `count`가 0이거나, `owner`는 0인데 `count`가 0이 아니면 `EINVAL`로 실패합니다.

.. c:macro:: NTSYNC_IOC_CREATE_MUTEX

  Create a mutex object. Takes a pointer to struct
  :c:type:`ntsync_mutex_args`, which is used as follows:

  .. list-table::

     * - ``count``
       - Initial recursion count of the mutex.
     * - ``owner``
       - Initial owner of the mutex.

  If ``owner`` is nonzero and ``count`` is zero, or if ``owner`` is
  zero and ``count`` is nonzero, the function fails with ``EINVAL``.
  On success, returns a file descriptor the created mutex.

NTSYNC_IOC_CREATE_EVENT

137-153

`NTSYNC_IOC_CREATE_EVENT`는 event 객체를 만들며 `struct ntsync_event_args` 포인터를 받습니다.

event 생성 인자
필드입력 의미
`signaled`0이 아니면 처음부터 signaled, 0이면 nonsignaled
`manual`0이 아니면 manual-reset, 0이면 auto-reset

생성 성공 시 새 event의 파일 디스크립터를 반환합니다.

이 지점부터는 개별 객체 파일에서 수행하는 ioctl을 설명합니다.

.. c:macro:: NTSYNC_IOC_CREATE_EVENT

  Create an event object. Takes a pointer to struct
  :c:type:`ntsync_event_args`, which is used as follows:

  .. list-table::

     * - ``signaled``
       - If nonzero, the event is initially signaled, otherwise
         nonsignaled.
     * - ``manual``
       - If nonzero, the event is a manual-reset event, otherwise
         auto-reset.

  On success, returns a file descriptor the created event.

The ioctls on the individual objects are as follows:

NTSYNC_IOC_SEM_POST

154-167

`NTSYNC_IOC_SEM_POST`는 semaphore에 count를 더합니다. 32비트 정수 포인터가 입력에서는 더할 수를 담고, 출력에서는 연산 전 count를 받습니다.

현재 count에 입력값을 더한 결과가 최대값을 넘으면 `EOVERFLOW`로 실패하며 semaphore는 바뀌지 않습니다. count 증가로 객체가 signaled 상태가 되면 대기 중인 적격 스레드를 깨우고, 만족된 대기 수만큼 count를 적절히 감소시킵니다.


.. c:macro:: NTSYNC_IOC_SEM_POST

  Post to a semaphore object. Takes a pointer to a 32-bit integer,
  which on input holds the count to be added to the semaphore, and on
  output contains its previous count.

  If adding to the semaphore's current count would raise the latter
  past the semaphore's maximum count, the ioctl fails with
  ``EOVERFLOW`` and the semaphore is not affected. If raising the
  semaphore's count causes it to become signaled, eligible threads
  waiting on this semaphore will be woken and the semaphore's count
  decremented appropriately.

NTSYNC_IOC_MUTEX_UNLOCK

168-188

`NTSYNC_IOC_MUTEX_UNLOCK`은 mutex를 해제하며 `struct ntsync_mutex_args` 포인터를 받습니다.

mutex 해제 인자
필드방향과 의미
`owner`입력: mutex를 해제하려는 owner
`count`출력: 이전 recursion count

호출자는 소유권을 증명하고 이전 재귀 깊이를 돌려받습니다.

`owner`가 0이면 `EINVAL`, 현재 owner와 다르면 `EPERM`으로 실패합니다.

성공하면 mutex count를 1 줄입니다. count가 0이 되면 소유자 없음과 signaled 상태로 표시하고, 이 mutex를 기다리는 적격 스레드를 깨웁니다.

.. c:macro:: NTSYNC_IOC_MUTEX_UNLOCK

  Release a mutex object. Takes a pointer to struct
  :c:type:`ntsync_mutex_args`, which is used as follows:

  .. list-table::

     * - ``owner``
       - Specifies the owner trying to release this mutex.
     * - ``count``
       - On output, contains the previous recursion count.

  If ``owner`` is zero, the ioctl fails with ``EINVAL``. If ``owner``
  is not the current owner of the mutex, the ioctl fails with
  ``EPERM``.

  The mutex's count will be decremented by one. If decrementing the
  mutex's count causes it to become zero, the mutex is marked as
  unowned and signaled, and eligible threads waiting on it will be
  woken as appropriate.

event 설정, 리셋, 펄스

189-215
event 상태 변경 ioctl
ioctl동작
`NTSYNC_IOC_SET_EVENT`event를 signal하고 적격 대기자를 깨웁니다. auto-reset event는 대기 만족에 맞춰 다시 비신호 상태가 됩니다.
`NTSYNC_IOC_RESET_EVENT`event를 비신호 상태로 만듭니다.
`NTSYNC_IOC_PULSE_EVENT`대기 중인 스레드를 깨우되 event는 비신호 상태로 남깁니다.

세 명령 모두 32비트 정수 포인터에 이전 event 상태를 출력합니다.

pulse는 set과 reset을 하나의 원자 연산으로 수행한 것으로 볼 수 있습니다. 두 스레드가 auto-reset event를 기다리면 하나만 깨어나고, manual-reset event를 기다리면 둘 다 깨어납니다. 어느 경우든 연산 뒤 event는 비신호 상태이며 동시에 수행한 read도 항상 비신호 상태를 보고합니다.

.. c:macro:: NTSYNC_IOC_SET_EVENT

  Signal an event object. Takes a pointer to a 32-bit integer, which on
  output contains the previous state of the event.

  Eligible threads will be woken, and auto-reset events will be
  designaled appropriately.

.. c:macro:: NTSYNC_IOC_RESET_EVENT

  Designal an event object. Takes a pointer to a 32-bit integer, which
  on output contains the previous state of the event.

.. c:macro:: NTSYNC_IOC_PULSE_EVENT

  Wake threads waiting on an event object while leaving it in an
  unsignaled state. Takes a pointer to a 32-bit integer, which on
  output contains the previous state of the event.

  A pulse operation can be thought of as a set followed by a reset,
  performed as a single atomic operation. If two threads are waiting on
  an auto-reset event which is pulsed, only one will be woken. If two
  threads are waiting a manual-reset event which is pulsed, both will
  be woken. However, in both cases, the event will be unsignaled
  afterwards, and a simultaneous read operation will always report the
  event as unsignaled.

semaphore와 mutex 상태 읽기

216-244

`NTSYNC_IOC_READ_SEM`은 `struct ntsync_sem_args`에 현재 상태를 출력합니다.

semaphore 상태 출력
필드출력
`count`현재 semaphore count
`max`semaphore의 최대 count

두 필드는 모두 출력입니다.

`NTSYNC_IOC_READ_MUTEX`는 `struct ntsync_mutex_args`에 현재 owner와 recursion count를 출력합니다. 소유자가 없으면 `owner`는 0입니다.

mutex가 abandoned로 표시되어 있으면 `EOWNERDEAD`로 실패하고 `count`와 `owner`를 모두 0으로 설정합니다.

.. c:macro:: NTSYNC_IOC_READ_SEM

  Read the current state of a semaphore object. Takes a pointer to
  struct :c:type:`ntsync_sem_args`, which is used as follows:

  .. list-table::

     * - ``count``
       - On output, contains the current count of the semaphore.
     * - ``max``
       - On output, contains the maximum count of the semaphore.

.. c:macro:: NTSYNC_IOC_READ_MUTEX

  Read the current state of a mutex object. Takes a pointer to struct
  :c:type:`ntsync_mutex_args`, which is used as follows:

  .. list-table::

     * - ``owner``
       - On output, contains the current owner of the mutex, or zero
         if the mutex is not currently owned.
     * - ``count``
       - On output, contains the current recursion count of the mutex.

  If the mutex is marked as abandoned, the function fails with
  ``EOWNERDEAD``. In this case, ``count`` and ``owner`` are set to
  zero.

event 읽기와 owner 사망 통지

245-267

`NTSYNC_IOC_READ_EVENT`는 `struct ntsync_event_args`에 event 상태를 출력합니다.

event 상태 출력
필드출력
`signaled`현재 event 상태
`manual`manual-reset event이면 1, 아니면 0

event 유형과 현재 신호 상태를 함께 읽습니다.

`NTSYNC_IOC_KILL_OWNER`는 지정한 owner가 mutex를 소유한 경우 그 mutex를 소유자 없음 및 abandoned 상태로 표시합니다. 입력 전용 32비트 owner 포인터를 받으며 owner가 0이면 `EINVAL`, 해당 mutex의 소유자가 아니면 `EPERM`으로 실패합니다.

성공하면 mutex를 기다리는 적격 스레드를 깨웁니다. 이런 대기는 아래 설명처럼 `EOWNERDEAD`로 반환됩니다.

.. c:macro:: NTSYNC_IOC_READ_EVENT

  Read the current state of an event object. Takes a pointer to struct
  :c:type:`ntsync_event_args`, which is used as follows:

  .. list-table::

     * - ``signaled``
       - On output, contains the current state of the event.
     * - ``manual``
       - On output, contains 1 if the event is a manual-reset event,
         and 0 otherwise.

.. c:macro:: NTSYNC_IOC_KILL_OWNER

  Mark a mutex as unowned and abandoned if it is owned by the given
  owner. Takes an input-only pointer to a 32-bit integer denoting the
  owner. If the owner is zero, the ioctl fails with ``EINVAL``. If the
  owner does not own the mutex, the function fails with ``EPERM``.

  Eligible threads waiting on the mutex will be woken as appropriate
  (and such waits will fail with ``EOWNERDEAD``, as described below).

NTSYNC_IOC_WAIT_ANY 인자

268-313

`NTSYNC_IOC_WAIT_ANY`는 객체 목록 중 하나를 poll하고 최대 하나를 원자적으로 획득합니다. `struct ntsync_wait_args` 포인터의 필드는 다음과 같습니다.

ntsync_wait_args 필드
필드의미
`timeout`나노초 단위 절대 시각입니다. 기본은 MONOTONIC, `NTSYNC_WAIT_REALTIME`이면 REALTIME 기준입니다. 현재 이하이면 즉시 반환하고 U64_MAX이면 신호까지 무기한 기다립니다.
`objs``count`개 파일 디스크립터 배열을 가리키는 정수형 포인터 값입니다. 구조체 크기를 아키텍처와 무관하게 유지합니다. 잘못된 객체가 있으면 `EINVAL`입니다.
`count``objs` 배열의 객체 수입니다. `NTSYNC_MAX_WAIT_COUNT`보다 크면 `EINVAL`입니다.
`owner`mutex를 획득할 owner 식별자입니다. 목록에 mutex가 있는데 owner가 0이면 `EINVAL`입니다.
`index`성공 시 signal된 객체의 `objs` 인덱스입니다. `alert`가 원인이면 `count`가 됩니다.
`alert`선택적 event 파일 디스크립터입니다. 0이 아니면 유효한 event여야 하며 signal 시 대기를 끝냅니다.
`flags`0개 이상의 플래그입니다. 현재는 timeout을 REALTIME 기준으로 바꾸는 `NTSYNC_WAIT_REALTIME`만 있습니다.
`pad`사용하지 않으며 반드시 0이어야 합니다.

시간 기준, 객체 배열, owner와 alert를 명시적으로 제공합니다.

.. c:macro:: NTSYNC_IOC_WAIT_ANY

  Poll on any of a list of objects, atomically acquiring at most one.
  Takes a pointer to struct :c:type:`ntsync_wait_args`, which is
  used as follows:

  .. list-table::

     * - ``timeout``
       - Absolute timeout in nanoseconds. If ``NTSYNC_WAIT_REALTIME``
         is set, the timeout is measured against the REALTIME clock;
         otherwise it is measured against the MONOTONIC clock. If the
         timeout is equal to or earlier than the current time, the
         function returns immediately without sleeping. If ``timeout``
         is U64_MAX, the function will sleep until an object is
         signaled, and will not fail with ``ETIMEDOUT``.
     * - ``objs``
       - Pointer to an array of ``count`` file descriptors
         (specified as an integer so that the structure has the same
         size regardless of architecture). If any object is
         invalid, the function fails with ``EINVAL``.
     * - ``count``
       - Number of objects specified in the ``objs`` array.
         If greater than ``NTSYNC_MAX_WAIT_COUNT``, the function fails
         with ``EINVAL``.
     * - ``owner``
       - Mutex owner identifier. If any object in ``objs`` is a mutex,
         the ioctl will attempt to acquire that mutex on behalf of
         ``owner``. If ``owner`` is zero, the ioctl fails with
         ``EINVAL``.
     * - ``index``
       - On success, contains the index (into ``objs``) of the object
         which was signaled. If ``alert`` was signaled instead,
         this contains ``count``.
     * - ``alert``
       - Optional event object file descriptor. If nonzero, this
         specifies an "alert" event object which, if signaled, will
         terminate the wait. If nonzero, the identifier must point to a
         valid event.
     * - ``flags``
       - Zero or more flags. Currently the only flag is
         ``NTSYNC_WAIT_REALTIME``, which causes the timeout to be
         measured against the REALTIME clock instead of MONOTONIC.
     * - ``pad``
       - Unused, must be set to zero.

WAIT_ANY 획득 의미

314-348

호출은 주어진 객체 중 하나를 획득하려고 시도합니다. 즉시 획득할 수 없으면 객체가 signaled 상태가 되어 획득하거나 timeout이 만료될 때까지 잠듭니다. timeout이면 `ETIMEDOUT`으로 실패하며 여러 객체가 signal되어도 하나만 획득합니다.

WAIT_ANY의 객체별 획득
객체signal 조건획득
semaphorecount가 0이 아님count를 1 감소
mutex소유자가 없거나 기존 owner가 요청 `owner`와 같음recursion count를 1 증가시키고 owner 설정
auto-reset eventsignaled비신호 상태로 전환
manual-reset eventsignaled상태 변화 없음

객체 유형에 따라 signal 판정과 상태 전이가 달라집니다.

획득은 같은 객체의 다른 연산에 대해 원자적이고 전순서화됩니다. 서로 다른 owner로 같은 mutex를 기다리는 두 대기 중 하나만 signal되며, 같은 semaphore를 기다리는 두 대기에 1을 post해도 하나만 signal됩니다.

abandoned mutex를 획득하면 ioctl은 `EOWNERDEAD`로 실패하지만 다른 의미에서는 성공한 것으로 보아야 합니다. mutex는 주어진 owner가 recursion count 1로 소유하고 abandoned 표시는 제거되며, `index`도 해당 mutex 인덱스로 설정됩니다.

`alert`는 다른 객체와 독립적으로 대기를 끝낼 수 있는 추가 event입니다.

같은 객체를 `objs`에 여러 번 넣거나 같은 event를 `objs`와 `alert`에 함께 넣어도 됩니다. 그 객체 때문에 깨어나면 `index`는 해당 객체가 나타나는 가장 낮은 인덱스가 됩니다.

signal을 받으면 `EINTR`로 실패할 수 있습니다.

  This function attempts to acquire one of the given objects. If unable
  to do so, it sleeps until an object becomes signaled, subsequently
  acquiring it, or the timeout expires. In the latter case the ioctl
  fails with ``ETIMEDOUT``. The function only acquires one object, even
  if multiple objects are signaled.

  A semaphore is considered to be signaled if its count is nonzero, and
  is acquired by decrementing its count by one. A mutex is considered
  to be signaled if it is unowned or if its owner matches the ``owner``
  argument, and is acquired by incrementing its recursion count by one
  and setting its owner to the ``owner`` argument. An auto-reset event
  is acquired by designaling it; a manual-reset event is not affected
  by acquisition.

  Acquisition is atomic and totally ordered with respect to other
  operations on the same object. If two wait operations (with different
  ``owner`` identifiers) are queued on the same mutex, only one is
  signaled. If two wait operations are queued on the same semaphore,
  and a value of one is posted to it, only one is signaled.

  If an abandoned mutex is acquired, the ioctl fails with
  ``EOWNERDEAD``. Although this is a failure return, the function may
  otherwise be considered successful. The mutex is marked as owned by
  the given owner (with a recursion count of 1) and as no longer
  abandoned, and ``index`` is still set to the index of the mutex.

  The ``alert`` argument is an "extra" event which can terminate the
  wait, independently of all other objects.

  It is valid to pass the same object more than once, including by
  passing the same event in the ``objs`` array and in ``alert``. If a
  wakeup occurs due to that object being signaled, ``index`` is set to
  the lowest index corresponding to that object.

  The function may fail with ``EINTR`` if a signal is received.

NTSYNC_IOC_WAIT_ALL

349-385

`NTSYNC_IOC_WAIT_ALL`은 객체 목록 전체를 poll해 모두 원자적으로 획득합니다. 인자는 `NTSYNC_IOC_WAIT_ANY`와 같지만 alert로 깨어난 경우가 아니라면 성공 시 `index`는 항상 0입니다.

모든 객체를 동시에 획득할 수 없으면 전부가 동시에 signaled 상태가 되거나 timeout이 만료될 때까지 잠듭니다. timeout이면 `ETIMEDOUT`으로 실패하고 어떤 객체도 수정하지 않습니다.

잠든 동안 객체가 signal되었다가 다른 스레드의 획득으로 다시 비신호 상태가 될 수 있습니다. 모든 객체가 동시에 signal된 순간에만 전체를 획득해 반환하며, 전체 획득은 관련된 모든 객체의 다른 연산에 대해 원자적이고 전순서화됩니다.

abandoned mutex를 획득하면 `EOWNERDEAD`로 실패하지만 WAIT_ANY와 마찬가지로 모든 객체는 획득된 상태가 됩니다. mutex를 여러 개 지정했다면 어느 것이 abandoned였는지는 알 수 없습니다.

WAIT_ALL도 `alert` event 하나로 대기를 끝낼 수 있습니다. 모든 `objs`가 signal되거나 `alert`가 signal되면 성공하며, alert가 원인이면 `index`는 `count`입니다. 두 조건이 동시에 충족되면 객체 목록의 획득이 우선합니다.

WAIT_ANY와 달리 같은 객체를 두 번 이상 전달하거나 같은 객체를 `objs`와 `alert`에 함께 넣는 것은 유효하지 않습니다. 이런 경우 `EINVAL`로 실패합니다.


.. c:macro:: NTSYNC_IOC_WAIT_ALL

  Poll on a list of objects, atomically acquiring all of them. Takes a
  pointer to struct :c:type:`ntsync_wait_args`, which is used
  identically to ``NTSYNC_IOC_WAIT_ANY``, except that ``index`` is
  always filled with zero on success if not woken via alert.

  This function attempts to simultaneously acquire all of the given
  objects. If unable to do so, it sleeps until all objects become
  simultaneously signaled, subsequently acquiring them, or the timeout
  expires. In the latter case the ioctl fails with ``ETIMEDOUT`` and no
  objects are modified.

  Objects may become signaled and subsequently designaled (through
  acquisition by other threads) while this thread is sleeping. Only
  once all objects are simultaneously signaled does the ioctl acquire
  them and return. The entire acquisition is atomic and totally ordered
  with respect to other operations on any of the given objects.

  If an abandoned mutex is acquired, the ioctl fails with
  ``EOWNERDEAD``. Similarly to ``NTSYNC_IOC_WAIT_ANY``, all objects are
  nevertheless marked as acquired. Note that if multiple mutex objects
  are specified, there is no way to know which were marked as
  abandoned.

  As with "any" waits, the ``alert`` argument is an "extra" event which
  can terminate the wait. Critically, however, an "all" wait will
  succeed if all members in ``objs`` are signaled, *or* if ``alert`` is
  signaled. In the latter case ``index`` will be set to ``count``. As
  with "any" waits, if both conditions are filled, the former takes
  priority, and objects in ``objs`` will be acquired.

  Unlike ``NTSYNC_IOC_WAIT_ANY``, it is not valid to pass the same
  object more than once, nor is it valid to pass the same object in
  ``objs`` and in ``alert``. If this is attempted, the function fails
  with ``EINVAL``.