forked from KolibriOS/kolibrios
233 lines
19 KiB
Plaintext
233 lines
19 KiB
Plaintext
Дата последней правки 26/07/2013.
|
||
Подсистема событий ядра может понадобиться при написании драйверов и сервисов, работающих в режиме ядра.
|
||
Она не имеет отношения к подсистеме событий пользовательского интерфейса.
|
||
С точки зрения ядра событие - объект ядра и принадлежит создавшему его потоку.
|
||
|
||
struc EVENT
|
||
{
|
||
.magic dd ? ; 'EVNT'
|
||
.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. (Здесь можно передавать какие-то свои данные,
|
||
; при необходимости :)
|
||
.size = $ - .magic
|
||
.codesize = $ - .code
|
||
}
|
||
|
||
События реального времени получили класс 0хFF. Пока определёны только:
|
||
EVENT.code= ;(Используется в звуковой подсистеме).
|
||
RT_INP_EMPTY = 0xFF000001
|
||
RT_OUT_EMPTY = 0xFF000002
|
||
RT_INP_FULL = 0xFF000003
|
||
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, не возвращать событие в список свободных по получении.
|
||
|
||
На момент ревизии 3732 (и далее по тексту то же) определение находится в \kernel\trunk\const.inc
|
||
и выглядит так:
|
||
|
||
struct APPOBJ ; common object header
|
||
magic dd ? ;
|
||
destroy dd ? ; internal destructor
|
||
fd dd ? ; next object in list
|
||
bk dd ? ; prev object in list
|
||
pid dd ? ; owner id
|
||
ends
|
||
|
||
struct EVENT APPOBJ
|
||
id dd ? ;event uid
|
||
state dd ? ;internal flags
|
||
code dd ?
|
||
rd 5 ; .data
|
||
ends
|
||
|
||
Код находится в gui/event.inc.
|
||
Сами события как обьекты существуют в памяти ядра в виде двусвязного списка (см. поля .bk и .fd).
|
||
При инициализации ядро резервирует память и создает 512 таких обьектов, помещая их в список FreeEvents
|
||
(свободных событий). При нехватке событий (все заняты, а нужно ещё) ядро создает ещё 512 свободных
|
||
и т.д. Каждый поток имеет свои (двусвязные) списки (в которые может быть помещено событие):
|
||
ObjList - список объектов ядра, ассоциированных с этим потоком;
|
||
EventList - список событий ядра для потока.
|
||
Сами события, физически, при перемещении между списками и смене очередности в списке не перемещаются
|
||
и не копируются. Это происходит только благодаря модификации полей .fd и .bk. Принцип работы списков,
|
||
как очередей - FIFO. Использутся неблокирующая отправка и блокирующее получение. Адресация - прямая
|
||
(у события всегда есть поток-владелец), по идентификатору потока.
|
||
|
||
Жизненый цикл событий определяется флагами при создании. По умолчанию ядро использует значения
|
||
MANUAL_RESET = 0 и MANUAL_DESTROY = 0. Такое событие является "одноразовым", и автоматически освобождается
|
||
ядром, возвращаясь в список свободных событий после получения.
|
||
Событие с флагом MANUAL_DESTROY = 1 после получения переходит в неактивное состояние, но остаётся в списке
|
||
объектов потока и может использоваться снова. Событие с флагами MANUAL_DESTROY = 1 и MANUAL_RESET = 1
|
||
остаётся активным после получения и может быть сброшено вызовом ClearEvent.
|
||
|
||
Пример (вариант) жизненного цикла события из звуковой подсистемы:
|
||
Для зукового буфера (их может быть несколько) драйвер создает событие в списке ObjList с помощью
|
||
CreateEvent и флагом MANUAL_DESTROY. Далее драйвер вызывает WaitEvent для этого события (ожидает флага
|
||
EVENT_SIGNALED в событии) и блокируется, в ожидании запроса на пополнение буфера. Запрос отправляется
|
||
с помощью RaiseEvent из другого потока. Отправка (RaiseEvent) и получение (WaitEvent) циклически
|
||
повторяются при опустошении буфера. При остановке воспроизведения драйвер деактивирует событие с помощью
|
||
ClearEvent.
|
||
|
||
Вообще говоря, структура события приведена здесь только лишь для понимания принципов работы подсистемы.
|
||
Самостоятельная работа с полями не приветствуется, ввиду возможных в будущем проблем с совместимостью.
|
||
Работа должна производится только через API (функции подсистемы), с доступом только к тем полям, доступ к
|
||
которым предоставляет функция. При этом пару "указатель на событие" и "уникальный идентификатор события"
|
||
следует рассматривать как один 64-х битный уникальный идентификатор. (Если вы вызвали CreateEvent, напимер,
|
||
его нужно запомнить где-нибудь [если это нужно] для дальнейшей работы с событием).
|
||
|
||
Функции для работы с событиями экспортитуемые ядром:
|
||
(для драйверов и т.п.; вызываются в режиме ядра)
|
||
|
||
CreateEvent
|
||
RaiseEvent
|
||
ClearEvent
|
||
SendEvent
|
||
DestroyEvent
|
||
WaitEvent
|
||
WaitEventTimeout
|
||
GetEvent
|
||
Для пользовательских приложений Ф68.14 (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
|
||
---------------------------------------------------------------------------------------------
|
||
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 .
|
||
---------------------------------------------------------------------------------------------
|
||
ClearEvent:
|
||
Перемещает событие в список ObjList потока-владельца. (Возможно оно там и находилось.)
|
||
Сбрасывает флаги EVENT_SIGNALED, EVENT_WATCHED. С остальными полями (.code, .id),
|
||
ничего не делает.
|
||
Принимает:
|
||
eax - указатель на событие;
|
||
ebx - id, уникальный идентификатор события.
|
||
Возвращает: ?
|
||
Портит: 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 .
|
||
---------------------------------------------------------------------------------------------
|
||
DestroyEvent:
|
||
Переносит EVENT в список FreeEvents, чистит поля .magic,.destroy,.pid,.id.
|
||
Событие может принадлежать другому потоку.
|
||
Принимает:
|
||
eax - указатель на событие;
|
||
ebx - id, уникальный идентификатор события.
|
||
Возвращает:
|
||
eax - 0 при ошибке, не 0 при успехе.
|
||
Портит: 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 .
|
||
---------------------------------------------------------------------------------------------
|
||
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 .
|
||
---------------------------------------------------------------------------------------------
|
||
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 .
|
||
---------------------------------------------------------------------------------------------
|