요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
===================================
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).
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.
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 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.
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.
.. 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.
.. 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:
.. 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.
.. 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.
.. 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.
.. 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.
.. 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).
.. 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.
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.
.. 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``.
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-59ntsync 드라이버는 semaphore, mutex, event의 세 가지 동기화 프리미티브를 노출합니다.
각 객체는 신호 상태와 대기 만족 시의 상태 전이가 다릅니다.
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-68ntsync 드라이버는 단일 문자 장치 `/dev/ntsync`를 만듭니다. 이 장치에서 연 각각의 file description은 개별 NT 가상 머신을 지원하기 위한 고유 인스턴스를 나타냅니다. 한 ntsync 인스턴스에서 만든 객체는 같은 인스턴스가 만든 다른 객체와만 함께 사용할 수 있습니다.
파일 수명과 가상 머신별 인스턴스 경계를 함께 지켜야 합니다.
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에 따라 입력, 출력 또는 미사용으로 해석됩니다.
각 구조체 멤버가 입력인지 출력인지는 아래의 개별 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`가 `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의 파일 디스크립터를 반환합니다.
`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의 파일 디스크립터를 반환합니다.
이 지점부터는 개별 객체 파일에서 수행하는 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` 포인터를 받습니다.
호출자는 소유권을 증명하고 이전 재귀 깊이를 돌려받습니다.
`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세 명령 모두 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`에 현재 상태를 출력합니다.
두 필드는 모두 출력입니다.
`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 유형과 현재 신호 상태를 함께 읽습니다.
`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` 포인터의 필드는 다음과 같습니다.
시간 기준, 객체 배열, 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되어도 하나만 획득합니다.
객체 유형에 따라 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``.
요약·해설
ntsync.rst:1-385ntsync의 핵심은 NT 객체 의미를 한 인스턴스 안에서 원자적으로 재현하는 것입니다. 특히 abandoned mutex의 `EOWNERDEAD`는 객체 획득을 동반할 수 있고, WAIT_ALL은 모든 객체의 동시 signal과 전체 원자 획득을 요구하므로 일반적인 오류 반환이나 poll 동작으로 단순화하면 안 됩니다.