diff --git a/kernel/trunk/docs/events_subsystem.ru.txt b/kernel/trunk/docs/events_subsystem.ru.txt new file mode 100644 index 0000000000..3d03db5cac --- /dev/null +++ b/kernel/trunk/docs/events_subsystem.ru.txt @@ -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 = 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 . +--------------------------------------------------------------------------------------------- diff --git a/kernel/trunk/docs/events_subsystem.txt b/kernel/trunk/docs/events_subsystem.txt index 8479b520d9..272ca6e482 100644 --- a/kernel/trunk/docs/events_subsystem.txt +++ b/kernel/trunk/docs/events_subsystem.txt @@ -1,232 +1,248 @@ -Дата последней правки 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 . ---------------------------------------------------------------------------------------------- +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' + .destroy dd ? ; internal destructor + .fd dd ? ; next object in list + .bk dd ? ; prev object in list + .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 +} + +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 + RT_OUT_FULL = 0xFF000004 + + +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 + +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 ? ; + 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 + +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. + +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. + +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. + +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 + ClearEvent + SendEvent + DestroyEvent + WaitEvent + WaitEventTimeout + GetEvent + For user applications sysfn 68.14 (a wrapper to GetEvent) + +-------------------------------------------------------------------------------- +CreateEvent: + 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: + 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: + 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: + 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: + 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: + 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: + 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: + 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