# Copyright (C) 2001-2007, Parrot Foundation. # $Id: pdd24_events.pod 39011 2009-05-21 11:11:13Z jkeenan $ =head1 PDD 24: Events =head2 Abstract This document defines the requirements and implementation strategy for Parrot's event subsystem. =head2 Version $Revision: 39011 $ =head2 Description =over 4 =item - Events are objects =item - Events are typed =item - Events can be fatal or non-fatal =item - Event handlers are code objects =item - Event handlers can be final or non-final =back =head2 Definitions An event is a notification that something has happened: the user has manipulated a GUI element, an I/O request has completed, a signal has been triggered, or a timer has expired. Most systems these days have an event handler (often two or three, which is something of a problem), because handling events is so fundamental to modern GUI programming. =head2 Implementation Parrot's event handling system is integrated with the central concurrency scheduler. When an event is created (by a GUI element, etc), it is added to concurrency task list. By default, events have a higher priority in the task list than asynchronous I/O operations or threaded code operations. At predetermined points in the execution cycle (between low-level discrete operations for safety, behind the scenes during "blocking" operations, at the same operational lulls where GC runs are performed, etc), the task list is queried, and tasks are dispatched. Events are dispatched to event handlers. Event handlers are registered with the concurrency scheduler. When dispatching an event, the concurrency scheduler compares the type of the event to the type of the event handler and selects the closest match. An exact type match is always highest ranked, then a parent type, and finally a general handler designed to handle all types. In addition to the type of an event, an event handler may check the data attribute of an event and decide whether to accept or decline that event based on its data. (For example, a "key press" may contain a data attribute value specifying that it's a "key 'a' press".) In the simple case, the concurrency scheduler runs within the single interpreter thread. In more complex cases (particularly on multi-processor machines), the concurrency scheduler runs in its own thread. In the multi-threaded case, each individual thread may register an event handler with the concurrency scheduler, and the event that matches the registered handler will be dispatched to the thread that registered it. In the most complex case, each thread runs a lightweight concurrency scheduler that coordinates with the central scheduler (so, for example, the mini-scheduler can decide when to run an event handler dispatched by the central scheduler). An event handler may mark itself as a final event handler, removing the event from the task list, or it may be a non-final handler, leaving the event in the task list for another thread to collect. Most events are non-fatal, so if a handler isn't found for them when they're extracted from the task list, they just expire and drop out of the task list. Events can also be fatal, in which case the interpreter will exit if a handler isn't found (essentially the same effect as an exception). When a non-final event handler leaves an event in the task list, it will expire if no further relevant event handlers can be found for the event. The operation to query the concurrency scheduler and find if it has any tasks to process is as cheap as possible, so it may be queried at regular intervals. =head3 Event API An event is a Task PMC object that contains a type, data for the event, and a priority. The type of an event is only used to match the event with an event handler, but is notionally similar to the class of an object. The data for the event is a PMC and could be any data passed to the event handler by the code that originates the event. The priority of an event affects when it is processed by the task list. Higher priority events are processed before lower priority events. Age is also a relevant factor, when two events have the same priority, the older one is processed first. An event handler or the scheduler may also be set to ignore events below a certain threshold of priority. When the central scheduler ignores an event because of its priority level, the event remains in the task list until the priority threshold changes. An instance of the Task PMC acting as an event uses 4 internal attributes, which are: =over 4 =item 1 The type of the task, which is "event" =item 2 The subtype of this particular event =item 3 The priority of the event =item 4 A PMC containing any additional data associated with the event, which may be used by the event handler. =back In addition to the attributes, an event uses a private PMC flag to mark itself as fatal or non-fatal. =head4 Event Vtable Entries =over 4 =item get_string STRING * get_string() Returns a simple string name for the event, suitable for printing in error messages. =item get_pmc PMC * get_pmc() Returns the data attribute of the event, or PMCNULL if the event has no data. =item isa INTVAL isa(STRING *) Returns true or false if the event is of the type passed in the string parameter, or has a parent of that type. =back =head3 Event Handler API An event handler contains a code object, as well as metainformation about where it was registered. More specifically, it contains a continuation object, capturing the full state of the interpreter where it was created. In many cases, this has no more effect than guaranteeing that the event handler code executes within the appropriate context of the thread that registered the handler. Because events are handled in mainline code, they don't have the restrictions commonly associated with interrupt-level code. It's safe and acceptable for an event handler to throw an exception, allocate memory, or manipulate thread or global state safely. Event handlers can even acquire locks if they need to, though it's not a good idea to have an event handler blocking on lock acquisition. An instance of the EventHandler PMC has 3 internal attributes, which are: =over 4 =item 1 The type of event it handles =item 2 A minimum threshhold of priority, below which it will ignore the event even if it is the right type. The default threshhold is 0, accepting all event priorities. =item 3 The core code object of the event handler. =item 4 A pointer to the interpreter that registered the event handler. The default is the interpreter in which the event handler was created. =back The interpreter pointer may be a proxy that simply provides the interface of an interpreter object, and knows how to communicate with its remote interpreter object (in threaded or clustering concurrency). =head4 Event Handler Vtable Entries =over 4 =item init_pmc void init_pmc(PMC *) Initializes the PMC, either with a single sub object for the core code, or with a hash object containing arguments for the code object, type, priority threshold, and interpreter object for the handler. =item set_string_native void set_string_native(STRING *) Set the type of event this handler responds to. {{NOTE: These basic attribute setting operations could be set_attr_str and get_attr_str instead.}} =item get_string STRING* get_string() Retrieve the type of event this handler responds to. =item set_integer_native set_integer_native(INTVAL) Set the minimum threshhold of priority. =item set_pmc(PMC *) Set the interpreter object for this event handler. =item invoke opcode_t * invoke(void *) Invoke the event handler. =back =head3 Opcodes The following opcodes are used with the event system: =over 4 =item new =begin PIR_FRAGMENT $P1 = new 'Event' $P1 = new 'EventHandler' $P1 = new 'EventHandler', $P2 =end PIR_FRAGMENT Creates a new event or event handler. =item schedule =begin PIR_FRAGMENT $P0 = new 'Event' # set attributes schedule $P0 =end PIR_FRAGMENT Register an event with the concurrency scheduler. If the concurrency scheduler for this interpreter (thread/clustered instance) is linked to another "primary" concurrency scheduler, this will pass along the event to the primary. All details about the event (its type, whether it's fatal or non-fatal, whether it's a timer, etc) are stored within the event PMC. {{NOTE: other possibilities 'raise' and 'fire' by KJS}} =item addhandler =begin PIR_FRAGMENT $P0 = new 'EventHandler' # set attributes addhandler $P0 =end PIR_FRAGMENT Register an event handler with the concurrency scheduler. If the concurrency scheduler for this interpreter (thread/clustered instance) is linked to another "primary" concurrency scheduler, this will pass along the event handler to the primary. =back =head3 Event Type Hierarchy Parrot defines a core set of event types. Users may also define their own event types. An event type of 'allevents' is effectively the parent of all event types, and will respond to any event in the task list that isn't handled by other event handlers in a final way. allevents ioevent packetsent packetreceived fileopened fileclosed readcomplete keyevent keydown keypress keyup mouseevent click doubleclick mousedown mouseup mousemove mouseenter mouseleave windowevent blur focus scroll textselect resize minimize maximize restore signal alarm interrupt childdie =head3 Signals Signals are a special form of event. Parrot presents them as mildly special, as a remnant of Perl's Unix heritage, but under the hood they're not treated any differently from events generated by other sources. Signals can be divided into two categories, those handled by the operating system, and those passed on to the process. OS-handled signals are things like SIGKILL, which kills a process, or SIGSEGV, which indicates that the process has tried to access memory that isn't part of your process. Because these signals are handled before they reach the process, there's no way for Parrot to catch them. Signals Parrot can handle include things like SIGCHLD, indicating that a child process has died, or SIGINT, indicating that the user has hit C<^C> on the keyboard, or SIGALRM, the timer expiration signal. Parrot turns these signals into events and puts them in the event task list, and will be processed and dispatched to an event handler in order of priority and age just like other events. =head3 Timers A timer is a special kind of event with a time delay. A timer can act as any builtin or custom event type. Timers can be be flagged as repeating. Parrot provides builtin timers for greater portability. Some platforms provide their own implementations of timers, which may be used when performance on a particular platform is more important than portability. =head2 Attachments None. =head2 Footnotes None. =head2 References src/events.c L<http://www.seas.upenn.edu/~lipeng/homepage/unify.html> L<http://developer.apple.com/documentation/Carbon/Conceptual/Carbon_Event_Manager/Concept/chapter_2_section_2.html> L<http://www.quirksmode.org/js/events_compinfo.html> =cut __END__ Local Variables: fill-column:78 End: