Kernel Event/ru

From KolibriOS wiki
Revision as of 21:29, 7 August 2013 by Punk Joker (talk | contribs) (Created page with "Дата последней правки 26/07/2013. Подсистема событий ядра может понадобиться при написании драйвер...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Дата последней правки 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 .