0,0 → 1,232 |
Дата последней правки 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 equ 0xFF000001 |
RT_OUT_EMPTY equ 0xFF000002 |
RT_INP_FULL equ 0xFF000003 |
RT_OUT_FULL equ 0xFF000004 |
|
|
Флаги поля EVENT.state определены в gui/event.inc. |
EVENT_SIGNALED equ 0x20000000 ;Бит 29 событие активно/неактивно; |
EVENT_WATCHED equ 0x10000000 ;бит 28, поток-владелец ожидает активации события; |
MANUAL_RESET equ 0x40000000 ;бит 30, не деактивировать событие автоматически по получении; |
MANUAL_DESTROY equ 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 . |
--------------------------------------------------------------------------------------------- |