Дата последней правки 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. Ожидающий поток замораживается путем перевода APPDATA.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. Ожидающий поток замораживается путем перевода APPDATA.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: Бесконечно ожидает любое событие в очереди событий текущего потока. Поток замораживается путем перевода APPDATA.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, но с обёрткой. Бесконечно ожидает любое событие в очереди событий текущего потока. Ожидающий поток замораживается путем перевода APPDATA.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 . ---------------------------------------------------------------------------------------------