PDD24 Events review

Stephen Weeks tene at allalone.org
Sat Dec 13 21:36:33 UTC 2008


Here are some basic comments on implementation level of PDD24

> =head1 NAME
> 
> docs/pdds/pdd24_events.pod - Parrot Events
> 
> =head1 ABSTRACT
> 
> This document defines the requirements and implementation strategy for
> Parrot's event subsystem.
> 
> =head1 VERSION
> 
> $Revision$
> 
> =head1 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
> 
> =head1 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.
> 
> =head1 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".)

How does an event handler decline to accept an event?

> 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.

How to do this?  EventHandler.pmc doesn't have an attribute for this.
'final' doesn't appear in EventHandler.pmc at all.

> 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.

How do we mark events non-fatal?  Task.pmc doesn't have an attribute for this.
'fatal' does not appear in Task.pmc at all.

> 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.
> 
> =head2 Event API
> 
> An event is a 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 Event PMC has 3 internal attributes, which are:
> 
> =over 4
> 
> =item 1
> 
> The type of the event
> 
> =item 2
> 
> The priority of the event
> 
> =item 3
> A PMC containing any additional data associated with the event, which may be
> used by the event handler.
> 
> =back

Task.pmc has these as well as id, birthtime, subtype, status, interp, codeblock, and cb_data.

> 
> In addition to the attributes, an event uses a private PMC flag to mark itself
> as fatal or non-fatal.

This seems to not be the case.

> 
> =head3 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.

Not implemented.

> 
> =item get_pmc
> 
>   PMC * get_pmc()
> 
> Returns the data attribute of the event, or PMCNULL if the event has no data.

Not implemented.  Additionally, get_attr_str won't return the 'data' attribute for "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.

Not implemented.

> =back
> 
> =head2 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:

4

> 
> =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).
> 
> =head3 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

also get_attr_str

> 
> =head2 Opcodes
> 
> The following opcodes are used with the event system:
> 
> =over 4
> 
> =item new
> 
>   $P1 = new 'Event'
>   $P1 = new 'EventHandler'
>   $P1 = new 'EventHandler', $P2
> 
> Creates a new event or event handler.
> 
> =item schedule
> 
>   $P0 = new 'Event'
>   # set attributes
>   schedule $P0
> 
> 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}}

I like 'schedule'

> 
> =item addhandler
> 
>   $P0 = new 'EventHandler'
>   # set attributes
>   addhandler $P0
> 
> 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.

The basic case works.  Unsure about the interpreter linking stuff, though.

> 
> =back
> 
> =head2 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

As far as I can tell, this hierarchy is not defined anywhere.

> 
> =head2 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.

The definitions here are great, but it doesn't define how signals are actually handled here at all.  There's no spec here.  How are signals handled specially?
Look at comment in src/events.c:703.  There's something suggested there, but NYI.


> 
> =head2 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.

There's src/events.c:Parrot_new_timer_event which creates a parrot_event struct instead of a Task pmc, and isn't actually called from anywhere at all.  That's all i can find, though.  I'm marking this NYI.

> 
> =head1 ATTACHMENTS
> 
> None.
> 
> =head1 FOOTNOTES
> 
> None.
> 
> =head1 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:


More information about the parrot-dev mailing list