Subversion Repositories Kolibri OS

Rev

Rev 3843 | Rev 7587 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. Дата последней правки 26/07/2013.
  2. Подсистема событий ядра может понадобиться при написании драйверов и сервисов, работающих в режиме ядра.
  3. Она не имеет отношения к подсистеме событий пользовательского интерфейса.
  4. С точки зрения ядра событие - объект ядра и принадлежит создавшему его потоку.
  5.  
  6. struc EVENT
  7. {
  8.    .magic       dd ?    ; 'EVNT'
  9.    .destroy     dd ?    ; internal destructor
  10.    .fd          dd ?    ; next object in list
  11.    .bk          dd ?    ; prev object in list
  12.    .pid         dd ?    ; owner id. идентификатор владельца (потока)
  13.    .id          dd ?    ; event uid. уникальный идентификатор события (просто номерок)
  14.    .state       dd ?    ; internal flags; см. далее.
  15.    .code        dd ?    ; старший байт класс события, ; следующий байт приоритет
  16.                         ; (будет использоваться только внутри ядра, при чтении всегда 0),
  17.                         ; Чем больше численное значение двойного слова тем важнее событие.
  18.                         ; два младших байта код события.
  19.                 rd 5    ; .data - точная структура этого поля не определена и зависит
  20.                         ; от поля .code. (Здесь можно передавать какие-то свои данные,
  21.                         ; при необходимости :)
  22.    .size     =  $ - .magic
  23.    .codesize =  $ - .code
  24. }
  25.  
  26. События реального времени получили класс 0хFF. Пока определёны только:
  27. EVENT.code=                             ;(Используется в звуковой подсистеме).
  28.         RT_INP_EMPTY      = 0xFF000001
  29.         RT_OUT_EMPTY      = 0xFF000002
  30.         RT_INP_FULL       = 0xFF000003
  31.         RT_OUT_FULL       = 0xFF000004
  32.  
  33.  
  34. Флаги поля EVENT.state определены в gui/event.inc.
  35.         EVENT_SIGNALED   = 0x20000000 ;бит 29  событие активно/неактивно;
  36.         EVENT_WATCHED    = 0x10000000 ;бит 28, поток-владелец ожидает активации события;
  37.         MANUAL_RESET     = 0x40000000 ;бит 30, не деактивировать событие автоматически по получении;
  38.         MANUAL_DESTROY   = 0x80000000 ;бит 31, не возвращать событие в список свободных по получении.
  39.  
  40. На момент ревизии 3732 (и далее по тексту то же) определение находится в \kernel\trunk\const.inc
  41. и выглядит так:
  42.  
  43. struct  APPOBJ                  ; common object header
  44.         magic           dd ?    ;
  45.         destroy         dd ?    ; internal destructor
  46.         fd              dd ?    ; next object in list
  47.         bk              dd ?    ; prev object in list
  48.         pid             dd ?    ; owner id
  49. ends
  50.  
  51. struct  EVENT           APPOBJ
  52.         id              dd ?   ;event uid
  53.         state           dd ?   ;internal flags
  54.         code            dd ?
  55.                         rd 5   ; .data
  56. ends
  57.  
  58. Код находится в gui/event.inc.
  59. Сами события как обьекты существуют в памяти ядра в виде двусвязного списка (см. поля .bk и .fd).
  60. При инициализации ядро резервирует память и создает 512 таких обьектов, помещая их в список FreeEvents
  61. (свободных событий). При нехватке событий (все заняты, а нужно ещё) ядро создает ещё 512 свободных
  62. и т.д. Каждый поток имеет свои (двусвязные) списки (в которые может быть помещено событие):
  63. ObjList - список объектов ядра, ассоциированных с этим потоком;
  64. EventList - список событий ядра для потока.
  65. Сами события, физически, при перемещении между списками и смене очередности в списке не перемещаются
  66. и не копируются. Это происходит только благодаря модификации полей .fd и .bk. Принцип работы списков,
  67. как очередей - FIFO. Использутся неблокирующая отправка и блокирующее получение. Адресация - прямая
  68. (у события всегда есть поток-владелец), по идентификатору потока.
  69.  
  70. Жизненый цикл событий определяется флагами при создании. По умолчанию ядро использует значения
  71. MANUAL_RESET = 0 и MANUAL_DESTROY = 0. Такое событие является "одноразовым", и автоматически освобождается
  72. ядром, возвращаясь в список свободных событий после получения.
  73. Событие с флагом MANUAL_DESTROY = 1 после получения переходит в неактивное состояние, но остаётся в списке
  74. объектов потока и может использоваться снова. Событие с флагами MANUAL_DESTROY =1 и MANUAL_RESET = 1
  75. остаётся активным после получения и может быть сброшено вызовом ClearEvent.
  76.  
  77. Пример (вариант) жизненного цикла события из звуковой подсистемы:
  78. Для зукового буфера (их может быть несколько) драйвер создает событие в списке ObjList с помощью
  79. CreateEvent и флагом MANUAL_DESTROY. Далее драйвер вызывает WaitEvent для этого события (ожидает флага
  80. EVENT_SIGNALED в событии) и блокируется, в ожидании запроса на пополнение буфера. Запрос отправляется
  81. с помощью RaiseEvent из другого потока. Отправка (RaiseEvent) и получение (WaitEvent) циклически
  82. повторяются при опустошении буфера. При остановке воспроизведения драйвер деактивирует событие с помощью
  83. ClearEvent.
  84.  
  85. Вообще говоря, структура события приведена здесь только лишь для понимания принципов работы подсистемы.
  86. Самостоятельная работа с полями не приветствуется, ввиду возможных в будущем проблем с совместимостью.
  87. Работа должна производится только через API (функции подсистемы), с доступом только к тем полям, доступ к
  88. которым предоставляет функция. При этом пару "указатель на событие" и "уникальный идентификатор события"
  89. следует рассматривать как один 64-х битный уникальный идентификатор. (Если вы вызвали CreateEvent, напимер,
  90. его нужно запомнить где-нибудь [если это нужно] для дальнейшей работы с событием).
  91.  
  92. Функции для работы с событиями экспортитуемые ядром:
  93. (для драйверов и т.п.; вызываются в режиме ядра)
  94.  
  95.         CreateEvent
  96.         RaiseEvent
  97.         ClearEvent
  98.         SendEvent
  99.         DestroyEvent
  100.         WaitEvent
  101.         WaitEventTimeout
  102.         GetEvent
  103.         Для пользовательских приложений Ф68.14 (GetEvent с обёрткой)
  104.  
  105. ---------------------------------------------------------------------------------------------
  106. CreateEvent:
  107.         Создаёт новое событие в очереди ObjList текущего потока.
  108.         Устанавливает:
  109.                 EVENT.destroy   <= внутренний деструктор по умолчанию;
  110.                 EVENT.pid       <= текущий Process id;
  111.                 EVENT.id        <= уникальный идентификатор;
  112.                 EVENT.state     <= ecx - флаги;
  113.                 EVENT.code      <= [esi], (если esi=0, то не копирует), размер 6*dword;
  114.         Возвращает:
  115.                 eax - указатель на событие или 0 при ошибке.
  116.                 edx - Event.id.
  117.         Портит: eax,ebx,edx,ecx,esi,edi    
  118. ---------------------------------------------------------------------------------------------        
  119. RaiseEvent:
  120.         Активирует уже существующее событие (может принадлежать другому потоку) установкой
  121.         флага EVENT_SIGNALED. Если необходимо, -  устанавливает данные EVENT.code.
  122.         Если флаг EVENT_SIGNALED в самом событии уже активен - больше ничего не делает.
  123.         Если EVENT_SIGNALED не установлен в самом событии, то он будет установлен, кроме случая
  124.                 {EVENT_WATCHED в edx=1 и EVENT_WATCHED в событии=0}.
  125.         Т.е. при установке EVENT_WATCHED в edx, проверяется, ожидает ли поток-владелец активации
  126.         события.
  127.         Кроме EVENT_SIGNALED в событии никакие другие флаги не модифицируются.
  128.         Принимает:
  129.                 eax     - указатель на событие;
  130.                 ebx     - id, уникальный идентификатор события;
  131.                 edx     - флаги для операции (формат EVENT.state);
  132.                 EVENT.code  <= [esi], (если esi=0, то не копирует), размер 6*dword;
  133.         Возвращает: ?
  134.         Портит: eax,ebx,edx,ecx,esi,edi .
  135. ---------------------------------------------------------------------------------------------        
  136. ClearEvent:
  137.         Перемещает событие в список ObjList потока-владельца. (Возможно оно там и находилось.)
  138.         Сбрасывает флаги EVENT_SIGNALED, EVENT_WATCHED. С остальными полями (.code, .id),
  139.         ничего не делает.
  140.         Принимает:
  141.                 eax     - указатель на событие;
  142.                 ebx     - id, уникальный идентификатор события.
  143.         Возвращает: ?
  144.         Портит: eax,ebx,ecx,edi .
  145. ---------------------------------------------------------------------------------------------        
  146. SendEvent:
  147.         Создаёт новое событие в списке событий целевого потока. Устанавливает в событии
  148.         флаг EVENT_SIGNALED.
  149.         Принимает:
  150.                 EVENT.pid       <= eax     - pid, идентификатор целевого потока;
  151.                 EVENT.code      <= [esi], (если esi=0, то не копирует), размер 6*dword;
  152.         Возвращает:
  153.                 eax - указатель на событие или 0 при ошибке.
  154.                 edx - Event.id. уникальный идентификатор.
  155.         Портит: eax,ebx,ecx,esi,edi .
  156. ---------------------------------------------------------------------------------------------        
  157. DestroyEvent:
  158.         Переносит EVENT в список FreeEvents, чистит поля .magic,.destroy,.pid,.id.
  159.         Событие может принадлежать другому потоку.
  160.         Принимает:
  161.                 eax     - указатель на событие;
  162.                 ebx     - id, уникальный идентификатор события.
  163.         Возвращает:
  164.                 eax     - 0 при ошибке, не 0 при успехе.
  165.         Портит: eax,ebx,ecx .
  166. ---------------------------------------------------------------------------------------------        
  167. WaitEvent:
  168.         Бесконечно ожидает установки флага EVENT_SIGNALED в конкретном событии, принадлежащем
  169.         вызывающему WaitEvent потоку. Сигнализирующий поток устанавливат этот флаг через
  170.         RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5.
  171.         Перед заморозкой устанавливается флаг EVENT_WATCHED в событии.
  172.         Если в полученном событии НЕ установлен MANUAL_RESET, то:
  173.                 {EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются.
  174.                  При неактивном  MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent),
  175.                  а при активном - перемещается в список ObjList текущего слота.}
  176.         Принимает:
  177.                 eax     - указатель на событие;
  178.                 ebx     - id, уникальный идентификатор события.
  179.         Возвращает: ?
  180.         Портит: eax,ebx,edx,ecx,esi,edi .
  181. ---------------------------------------------------------------------------------------------                
  182. WaitEventTimeout:
  183.         Ожидает с таймаутом установки флага EVENT_SIGNALED в конкретном событии, принадлежащем
  184.         вызывающему WaitEventTimeout потоку. Сигнализирующий поток устанавливат этот флаг через
  185.         RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5.
  186.         Перед заморозкой устанавливается флаг EVENT_WATCHED в событии.
  187.         Если в полученном событии НЕ установлен MANUAL_RESET, то:
  188.                 {EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются.
  189.                  При неактивном  MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent),
  190.                  а при активном - перемещается в список ObjList текущего слота.}
  191.         Принимает:
  192.                 eax     - указатель на событие;
  193.                 ebx     - id, уникальный идентификатор события.
  194.                 ecx     - время ожидания в тиках системного таймера.
  195.         Возвращает:
  196.                 eax     - 0 - таймаут, если событие не активировалось, или
  197.                           не 0, если было активировано.
  198.         Портит: eax,ebx,edx,ecx,esi,edi .
  199. ---------------------------------------------------------------------------------------------        
  200. GetEvent:
  201.         Бесконечно ожидает любое событие в очереди событий текущего потока. Поток замораживается
  202.         путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword)
  203.         по получении копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере.
  204.         Если в полученном событии НЕ установлен MANUAL_RESET, то:
  205.                 {EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются.
  206.                  При неактивном  MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent),
  207.                  а при активном - перемещается в список ObjList текущего слота.}
  208.         Принимает:
  209.                 edi     - указатель на буфер, куда копировать данные.
  210.         Возвращает:
  211.                 буфер, содержащий следующую информацию:
  212.                 +0: (EVENT.code) dword: идентификатор последующих данных сигнала
  213.                 +4: (EVENT.data, поле формально не определено) данные принятого
  214.                 сигнала (5*dword), формат которых определяется первым dword-ом.    
  215.         Портит: eax,ebx,edx,ecx,esi,edi .
  216. --------------------------------------------------------------------------------------------
  217. Ф 68.14 для приложений:         ;это тот же GetEvent, но с обёрткой.
  218.         Бесконечно ожидает любое событие в очереди событий текущего потока. Ожидающий поток
  219.         замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword)
  220.         копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере.
  221.         Принимает:
  222.                 eax     - 68 - номер функции
  223.                 ebx     - 14 - номер подфункции
  224.                 ecx     - указатель на буфер для информации (размер 6*dword)
  225.         Возвращает:
  226.                 буфер, на который указывает ecx, содержит следующую информацию:
  227.                 +0: (EVENT.code) dword: идентификатор последующих данных сигнала
  228.                 +4: (EVENT.data, поле формально не определено) данные принятого
  229.                 сигнала (5*dword), формат которых определяется первым dword-ом.
  230.         Портит:
  231.                 eax .
  232. ---------------------------------------------------------------------------------------------
  233.