249 lines
12 KiB
Plaintext
249 lines
12 KiB
Plaintext
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
|