1,8 → 1,10 |
Дата последней правки 26/07/2013. |
Подсистема событий ядра может понадобиться при написании драйверов и сервисов, работающих в режиме ядра. |
Она не имеет отношения к подсистеме событий пользовательского интерфейса. |
С точки зрения ядра событие - объект ядра и принадлежит создавшему его потоку. |
Last edit: 26/07/2013 |
|
Kernel event subsystem may be useful when writing drivers and kernel space |
services. It is not related to the subsystem of GUI events. An event, from the |
kernel's point of view, is a kernel space object which is owned by the thread |
that created it. |
|
struc EVENT |
{ |
.magic dd ? ; 'EVNT' |
9,22 → 11,21 |
.destroy dd ? ; internal destructor |
.fd dd ? ; next object in list |
.bk dd ? ; prev object in list |
.pid dd ? ; owner id. идентификатор владельца (потока) |
.id dd ? ; event uid. уникальный идентификатор события (просто номерок) |
.state dd ? ; internal flags; см. далее. |
.code dd ? ; старший байт класс события, ; следующий байт приоритет |
; (будет использоваться только внутри ядра, при чтении всегда 0), |
; Чем больше численное значение двойного слова тем важнее событие. |
; два младших байта код события. |
rd 5 ; .data - точная структура этого поля не определена и зависит |
; от поля .code. (Здесь можно передавать какие-то свои данные, |
; при необходимости :) |
.pid dd ? ; owner (thread) id |
.id dd ? ; event uid. (just a number) |
.state dd ? ; internal flags; see below |
.code dd ? ; MSB: event class; next byte: priority |
; (used by kernel only, always 0 for reading), |
; The higher dword value the higher event priority. |
; Two LSBs: event code. |
rd 5 ; .data: the structure of this field is not defined and |
; depends on .code field. (Pass any data you need here) |
.size = $ - .magic |
.codesize = $ - .code |
} |
|
События реального времени получили класс 0хFF. Пока определёны только: |
EVENT.code= ;(Используется в звуковой подсистеме). |
Realtime events have class 0хFF. Currently defined: |
EVENT.code= ; (Used in sound subsystem) |
RT_INP_EMPTY = 0xFF000001 |
RT_OUT_EMPTY = 0xFF000002 |
RT_INP_FULL = 0xFF000003 |
31,14 → 32,17 |
RT_OUT_FULL = 0xFF000004 |
|
|
Флаги поля EVENT.state определены в gui/event.inc. |
EVENT_SIGNALED = 0x20000000 ;бит 29 событие активно/неактивно; |
EVENT_WATCHED = 0x10000000 ;бит 28, поток-владелец ожидает активации события; |
MANUAL_RESET = 0x40000000 ;бит 30, не деактивировать событие автоматически по получении; |
MANUAL_DESTROY = 0x80000000 ;бит 31, не возвращать событие в список свободных по получении. |
Flags of EVENT.state field are defined in gui/event.inc. |
EVENT_SIGNALED = 0x20000000 ; bit 29: event is active/inactive |
EVENT_WATCHED = 0x10000000 ; bit 28: owner thread is waiting for the |
; event to be active |
MANUAL_RESET = 0x40000000 ; bit 30: do not deactivate event |
: automatically on receive |
MANUAL_DESTROY = 0x80000000 ; bit 31: do not return event to a list of |
; free ones on receive |
|
На момент ревизии 3732 (и далее по тексту то же) определение находится в \kernel\trunk\const.inc |
и выглядит так: |
As of SVN r3732 (assume same below) the definition is located in |
/kernel/trunk/const.inc and is as follows: |
|
struct APPOBJ ; common object header |
magic dd ? ; |
55,42 → 59,46 |
rd 5 ; .data |
ends |
|
Код находится в gui/event.inc. |
Сами события как обьекты существуют в памяти ядра в виде двусвязного списка (см. поля .bk и .fd). |
При инициализации ядро резервирует память и создает 512 таких обьектов, помещая их в список FreeEvents |
(свободных событий). При нехватке событий (все заняты, а нужно ещё) ядро создает ещё 512 свободных |
и т.д. Каждый поток имеет свои (двусвязные) списки (в которые может быть помещено событие): |
ObjList - список объектов ядра, ассоциированных с этим потоком; |
EventList - список событий ядра для потока. |
Сами события, физически, при перемещении между списками и смене очередности в списке не перемещаются |
и не копируются. Это происходит только благодаря модификации полей .fd и .bk. Принцип работы списков, |
как очередей - FIFO. Использутся неблокирующая отправка и блокирующее получение. Адресация - прямая |
(у события всегда есть поток-владелец), по идентификатору потока. |
Code is located in gui/event.inc. |
Event objects live in kernel memory as a double-linked list (see fields .bk and |
.fd). While initialization the kernel reserves memory, creates 512 events and |
places them into FreeEvents list. When out of free event, kernel creates another |
512 ones etc. Each thread has own double-linked lists where an event may be |
placed to: |
ObjList -- a list of kernel objects associated with the thread; |
EventList -- a list of kernel events for the thread. |
When events are moved between lists or reordered their data are not copied. This |
is done only via modification of .fd and .bk fields. These lists work as FIFO |
queues. Sending does not block, receiving blocks. Addressing is direct, by |
thread id. There always is an owner thread for an event. |
|
Жизненый цикл событий определяется флагами при создании. По умолчанию ядро использует значения |
MANUAL_RESET = 0 и MANUAL_DESTROY = 0. Такое событие является "одноразовым", и автоматически освобождается |
ядром, возвращаясь в список свободных событий после получения. |
Событие с флагом MANUAL_DESTROY = 1 после получения переходит в неактивное состояние, но остаётся в списке |
объектов потока и может использоваться снова. Событие с флагами MANUAL_DESTROY =1 и MANUAL_RESET = 1 |
остаётся активным после получения и может быть сброшено вызовом ClearEvent. |
Event's life cycle is defined by flags while creation. By default the kernel |
uses values MANUAL_RESET = 0 and MANUAL_DESTROY = 0. Such an event is oneshot |
and is automatically freed by the kernel and returned to the FreeEvents list |
when received. An event with flag MANUAL_DESTROY = 1 becomes inactive when |
received but remains in thread's object list and can be reused. An event with |
flags MANUAL_DESTROY = 1 and MANUAL_RESET = 1 remains active when received and |
can be reset via call to ClearEvent. |
|
Пример (вариант) жизненного цикла события из звуковой подсистемы: |
Для зукового буфера (их может быть несколько) драйвер создает событие в списке ObjList с помощью |
CreateEvent и флагом MANUAL_DESTROY. Далее драйвер вызывает WaitEvent для этого события (ожидает флага |
EVENT_SIGNALED в событии) и блокируется, в ожидании запроса на пополнение буфера. Запрос отправляется |
с помощью RaiseEvent из другого потока. Отправка (RaiseEvent) и получение (WaitEvent) циклически |
повторяются при опустошении буфера. При остановке воспроизведения драйвер деактивирует событие с помощью |
ClearEvent. |
A life cycle example of a sound subsystem event: |
* For an audio buffer (possibly several) the driver creates an event in ObjList |
by calling CreateEvent with flag MANUAL_DESTROY. |
* Then driver calls WaitEvent for the event (waits for EVENT_SIGNALED event |
flag) and blocks waiting for buffer update request. |
* The buffer update request is sent with RaiseEvent from another thread. |
* Sending (RaiseEvent) and receiving (WaitEvent) are repeated as buffer gets |
empty. |
* Driver deactivates the event with ClearEvent when playback is stopped. |
|
Вообще говоря, структура события приведена здесь только лишь для понимания принципов работы подсистемы. |
Самостоятельная работа с полями не приветствуется, ввиду возможных в будущем проблем с совместимостью. |
Работа должна производится только через API (функции подсистемы), с доступом только к тем полям, доступ к |
которым предоставляет функция. При этом пару "указатель на событие" и "уникальный идентификатор события" |
следует рассматривать как один 64-х битный уникальный идентификатор. (Если вы вызвали CreateEvent, напимер, |
его нужно запомнить где-нибудь [если это нужно] для дальнейшей работы с событием). |
Actually, the event structure is described here only for understanding of |
subsystem work principles. Direct field access is discouraged due to possible |
compatibility issues in the future. Only API calls should be used. A pair |
"pointer to an event" and "event id" is considered a single 64-bit id. This id |
should be stored somewhere after a call to CreateEvent for further work with the |
event. |
|
Функции для работы с событиями экспортитуемые ядром: |
(для драйверов и т.п.; вызываются в режиме ядра) |
The kernel exports following event related functions: |
(for drivers, etc; called from kernel mode) |
|
CreateEvent |
RaiseEvent |
100,133 → 108,141 |
WaitEvent |
WaitEventTimeout |
GetEvent |
Для пользовательских приложений Ф68.14 (GetEvent с обёрткой) |
For user applications sysfn 68.14 (a wrapper to GetEvent) |
|
--------------------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
CreateEvent: |
Создаёт новое событие в очереди ObjList текущего потока. |
Устанавливает: |
EVENT.destroy <= внутренний деструктор по умолчанию; |
EVENT.pid <= текущий Process id; |
EVENT.id <= уникальный идентификатор; |
EVENT.state <= ecx - флаги; |
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; |
Возвращает: |
eax - указатель на событие или 0 при ошибке. |
edx - Event.id. |
Портит: eax,ebx,edx,ecx,esi,edi |
--------------------------------------------------------------------------------------------- |
Creates a new event in ObjList queue of current thread. |
Sets: |
EVENT.destroy <= default internal destructor |
EVENT.pid <= current Process id |
EVENT.id <= unique id |
EVENT.state <= ecx: flags |
EVENT.code <= [esi]: size is 6*dword, do not copy if esi=0 |
Returns: |
eax -- pointer to the event or 0 for error. |
edx -- Event.id. |
Destroys: eax,ebx,edx,ecx,esi,edi |
-------------------------------------------------------------------------------- |
RaiseEvent: |
Активирует уже существующее событие (может принадлежать другому потоку) установкой |
флага EVENT_SIGNALED. Если необходимо, - устанавливает данные EVENT.code. |
Если флаг EVENT_SIGNALED в самом событии уже активен - больше ничего не делает. |
Если EVENT_SIGNALED не установлен в самом событии, то он будет установлен, кроме случая |
{EVENT_WATCHED в edx=1 и EVENT_WATCHED в событии=0}. |
Т.е. при установке EVENT_WATCHED в edx, проверяется, ожидает ли поток-владелец активации |
события. |
Кроме EVENT_SIGNALED в событии никакие другие флаги не модифицируются. |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события; |
edx - флаги для операции (формат EVENT.state); |
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; |
Возвращает: ? |
Портит: eax,ebx,edx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
Activates existing event (may be owned by another thread) by setting |
EVENT_SIGNALED flag. Sets EVENT.code data if necessary. Does nothing |
more if EVENT_SIGNALED flag is already active in the event. If |
EVENT_SIGNALED flag is not set in the event it will be set, except when |
EVENT_WATCHED in edx = 1 and EVENT_WATCHED in the event = 0. I.e. while |
setting EVENT_WATCHED in edx it is checked if owner thread is waiting |
for event activation. No flags, except EVENT_SIGNALED, are modified in |
the event. |
Gets: |
eax -- pointer to event |
ebx -- id |
edx -- flags (see EVENT.state) |
Sets: |
EVENT.code <= [esi]: size is 6*dword, do not copy if esi=0 |
Returns: ? |
Destroys: eax,ebx,edx,ecx,esi,edi |
-------------------------------------------------------------------------------- |
ClearEvent: |
Перемещает событие в список ObjList потока-владельца. (Возможно оно там и находилось.) |
Сбрасывает флаги EVENT_SIGNALED, EVENT_WATCHED. С остальными полями (.code, .id), |
ничего не делает. |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
Возвращает: ? |
Портит: eax,ebx,ecx,edi . |
--------------------------------------------------------------------------------------------- |
Move event to ObjList of owner thread. (May be it was already there.) |
Reset flags EVENT_SIGNALED and EVENT_WATCHED, keep other fields (.code, |
.id). |
Gets: |
eax -- pointer to event |
ebx -- id |
Returns: ? |
Destroys: eax,ebx,ecx,edi |
-------------------------------------------------------------------------------- |
SendEvent: |
Создаёт новое событие в списке событий целевого потока. Устанавливает в событии |
флаг EVENT_SIGNALED. |
Принимает: |
EVENT.pid <= eax - pid, идентификатор целевого потока; |
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword; |
Возвращает: |
eax - указатель на событие или 0 при ошибке. |
edx - Event.id. уникальный идентификатор. |
Портит: eax,ebx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
Create a new event in the event list of target thread. Sets |
EVENT_SIGNALED flag in the event. |
Gets: |
EVENT.pid <= eax: target thread id; |
EVENT.code <= [esi]: size is 6*dword, do not copy if esi=0 |
Returns: |
eax -- pointer to event or 0 for error |
edx -- Event.id |
Destroys: eax,ebx,ecx,esi,edi |
-------------------------------------------------------------------------------- |
DestroyEvent: |
Переносит EVENT в список FreeEvents, чистит поля .magic,.destroy,.pid,.id. |
Событие может принадлежать другому потоку. |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
Возвращает: |
eax - 0 при ошибке, не 0 при успехе. |
Портит: eax,ebx,ecx . |
--------------------------------------------------------------------------------------------- |
Moves event to FreeEvents, clears fields .magic, .destroy, .pid, .id. |
The event may be owned by other thread. |
Gets: |
eax -- pointer to event |
ebx -- event id |
Returns: |
eax -- 0 for error, non-zero for success |
Destroy: eax,ebx,ecx |
-------------------------------------------------------------------------------- |
WaitEvent: |
Бесконечно ожидает установки флага EVENT_SIGNALED в конкретном событии, принадлежащем |
вызывающему WaitEvent потоку. Сигнализирующий поток устанавливат этот флаг через |
RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. |
Перед заморозкой устанавливается флаг EVENT_WATCHED в событии. |
Если в полученном событии НЕ установлен MANUAL_RESET, то: |
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. |
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), |
а при активном - перемещается в список ObjList текущего слота.} |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
Возвращает: ? |
Портит: eax,ebx,edx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
Wait infinitely until flag EVENT_SIGNALED is set in the event owned by |
the caller thread. This flag is set by signaling thread via RaiseEvent. |
Waiting thread is frozen by setting TASKDATA.state <= TSTATE_WAITING=5. |
Flag EVENT_WATCHED is set in the event before freeze. |
If flag MANUAL_RESET is NOT set in the event then: |
EVENT_SIGNALED and EVENT_WATCHED are reset when the event is |
received. |
When MANUAL_DESTROY is |
inactive: the event is destroyed by DestroyEvent, |
active: the event is moved to ObjList of current thread. |
Gets: |
eax -- pointer to event |
ebx -- event id |
Returns: ? |
Destroys: eax,ebx,edx,ecx,esi,edi |
-------------------------------------------------------------------------------- |
WaitEventTimeout: |
Ожидает с таймаутом установки флага EVENT_SIGNALED в конкретном событии, принадлежащем |
вызывающему WaitEventTimeout потоку. Сигнализирующий поток устанавливат этот флаг через |
RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. |
Перед заморозкой устанавливается флаг EVENT_WATCHED в событии. |
Если в полученном событии НЕ установлен MANUAL_RESET, то: |
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. |
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), |
а при активном - перемещается в список ObjList текущего слота.} |
Принимает: |
eax - указатель на событие; |
ebx - id, уникальный идентификатор события. |
ecx - время ожидания в тиках системного таймера. |
Возвращает: |
eax - 0 - таймаут, если событие не активировалось, или |
не 0, если было активировано. |
Портит: eax,ebx,edx,ecx,esi,edi . |
--------------------------------------------------------------------------------------------- |
Wait with a timeout until flag EVENT_SIGNALED is set in the event owned |
by caller thread. This flag is set by signaling thread via RaiseEvent. |
Waiting thread is frozen by setting TASKDATA.state <= TSTATE_WAITING=5. |
Flag EVENT_WATCHED is set in the event before freeze. |
If flag MANUAL_RESET is NOT set in the event then: |
EVENT_SIGNALED and EVENT_WATCHED are reset when the event is |
received. |
When MANUAL_DESTROY is |
inactive: the event is destroyed by DestroyEvent, |
active: the event is moved to ObjList of current thread. |
Gets: |
eax -- pointer to event |
ebx -- event id |
ecx -- timeout, in ticks of system timer |
Returns: |
eax -- 0 if the event was not activated, or |
not 0 if activated |
Destroys: eax,ebx,edx,ecx,esi,edi |
-------------------------------------------------------------------------------- |
GetEvent: |
Бесконечно ожидает любое событие в очереди событий текущего потока. Поток замораживается |
путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword) |
по получении копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере. |
Если в полученном событии НЕ установлен MANUAL_RESET, то: |
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются. |
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent), |
а при активном - перемещается в список ObjList текущего слота.} |
Принимает: |
edi - указатель на буфер, куда копировать данные. |
Возвращает: |
буфер, содержащий следующую информацию: |
+0: (EVENT.code) dword: идентификатор последующих данных сигнала |
+4: (EVENT.data, поле формально не определено) данные принятого |
сигнала (5*dword), формат которых определяется первым dword-ом. |
Портит: eax,ebx,edx,ecx,esi,edi . |
-------------------------------------------------------------------------------------------- |
Ф 68.14 для приложений: ;это тот же GetEvent, но с обёрткой. |
Бесконечно ожидает любое событие в очереди событий текущего потока. Ожидающий поток |
замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword) |
копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере. |
Принимает: |
eax - 68 - номер функции |
ebx - 14 - номер подфункции |
ecx - указатель на буфер для информации (размер 6*dword) |
Возвращает: |
буфер, на который указывает ecx, содержит следующую информацию: |
+0: (EVENT.code) dword: идентификатор последующих данных сигнала |
+4: (EVENT.data, поле формально не определено) данные принятого |
сигнала (5*dword), формат которых определяется первым dword-ом. |
Портит: |
eax . |
--------------------------------------------------------------------------------------------- |
Waits infinitely for any event in the queue of current thread. Thread is |
frozen by setting TASKDATA.state <= TSTATE_WAITING = 5. Event data |
(EVENT.code + 5*dword) are copied to specified buffer when received. |
Reset priority byte (see above) in the buffer. |
If flag MANUAL_RESET is NOT set in the event then: |
EVENT_SIGNALED and EVENT_WATCHED are reset when the event is |
received. |
When MANUAL_DESTROY is |
inactive: the event is destroyed by DestroyEvent, |
active: the event is moved to ObjList of current thread. |
Gets: |
edi -- pointer to buffer to copy data |
Returns: |
buffer with following data: |
+0: (EVENT.code) dword: id of following signal data |
+4: (EVENT.data) 5*dword: signal data, format depends on |
EVENT.code |
Destroys: eax,ebx,edx,ecx,esi,edi |
-------------------------------------------------------------------------------- |
SysFn 68.14 for application: ; wrapped GetEvent |
Waits infinitely for any event in the queue of current thread. Thread is |
frozen by setting TASKDATA.state <= TSTATE_WAITING = 5. Event data |
(EVENT.code + 5*dword) are copied to specified buffer when received. |
Reset priority byte (see above) in the buffer. |
Gets: |
eax -- 68: function number |
ebx -- 14: subfunction number |
ecx -- pointer to data buffer (size is 6*dword) |
Returns: |
ecx = buffer with following data: |
+0: (EVENT.code) dword: id of following signal data |
+4: (EVENT.data) 5*dword: signal data, format depends on |
EVENT.code |
Destroys: |
eax |