>>>>> "DS" == Dan Sugalski <[EMAIL PROTECTED]> writes:
DS> Event Classes DS> ============= DS> There are two main classes of events, which we'll call expected and DS> unexpected. DS> An expected event is one that your program is specifically expecting DS> to get as a result of a request for asynchronous action, and each DS> expected event has a corresponding event handle. User code can wait DS> for an expected event to complete, cancel an expected event, and DS> query the status of an expected event. Expected events may also be DS> either complete or incomplete. An incomplete event is one whose DS> requested action hasn't yet happened, while a complete event ^^^^^ ????? DS> Unexpected events, on the other hand, happen for reasons outside of DS> your program. Signals, GUI events, and exceptions for asynchronous DS> files (which may not be delivered as signals on many platforms) are DS> examples of unexpected events. Unexpected events, by their nature, are DS> always complete, since they aren't generated until an action actually DS> occurs. DS> Some event sources may be either expected or unexpected. Network DS> connections are an example of this--you may have a network filehandle DS> set either as an expected event source, where your program must DS> explicitly ask for data, or set as an unexpected event source, where DS> a monitoring thread captures data as it is received and generates DS> events for the captured data. i disagree with the two classes. how can you handle an unexpected event without know it could happen? effectively all events are expected, some are more expected than others. :) the only way to get mouse movements (which is really translated to some i/o or socket event by the windowing system) is to ask for them. same with signals. if you don't ask to handle a signal, it uses the default (usually IGNORE or whatever). you need a handler for each possible event so effectively all events you can handle are expected. DS> Callbacks and User Data DS> ======================= DS> Each expected event can have a callback routine and piece of user DS> data associated with it. When the event request is satisfied (The IO DS> operation completes or the timer fires, for example) the callback DS> associated with it is invoked. The user data, as well as the event DS> data, if there is any, is passed into the callback. the event handle(r) itself also is passed to the callback. you say event data there and maybe you mean event structure/object? so let me clarify. the callback is passed the event itself, optionally any data read for the event, and optionally any private data passed into the event (this is usually the object or user id for this event). DS> Callback signatures are fixed, and of the form: DS> (Preturndata, Icommandstatus) = DS> callbacksub(Pevent, Peventdata, Puserdata, Icommand) DS> The callback is passed in the event PMC, the PMC for the event data, DS> and the PMC for the user data, if any. (Either or both of these can DS> be the Null PMC if there is no user or event data) Command is always DS> 0 for callback handling. (Callbacks and IO layer functions are DS> identical. More detail in the IO section) how about renaming userdata to iodata since that is what it is. eventdata could be left alone or actually renamed to userdata since it is the data passed in to the event call and the user expects it to come back so the code can identify the event and associate it with an object/structure. DS> If a callback function throws an exception the exception itself is DS> deferred. Expected events defer the exception until the event is DS> waited on, while unexpected events throw their excecption when their DS> event functions are done processing. (This does mean that expected DS> events may have their exceptions effectively ignored if the event is DS> never waited on) you need to clarify expected vs unexpected more. i wrote above they should all be expected. i don't see how this section would change that. DS> Events and Exceptions DS> ===================== DS> Event handlers are generally discouraged from throwing exceptions, DS> however it is sometimes necessary. Exceptions are handled differently DS> by expected and unexpected events. DS> With an expected event, if an event handler is terminated by an DS> unhandled exception, that exception is attached to the event itself, DS> and when user-level code C<wait>s on the event, the exception is DS> thrown then. huh? if you are in an event handler, you have seen the event (and are presumably in user level code), so why would you wait for it again? DS> Unexpected events whose handlers throw exceptions are handled somewhat DS> differently. In that case, the exception is thrown as soon as the DS> event is drained from the event queue. This may or may not happen DS> immediately, depending on how the event in question is currently being DS> handled. If the event is processed in a separate event handling thread DS> then the event is put in the main thread's event queue and the DS> exception will be thrown when the main thread drains the queue and DS> hits the event. If the event is currently being processed in the main DS> thread (because there is no event-handling thread, or this event DS> isn't being handled by one) then as soon as the event is drained from DS> the event queue the exception is thrown. DS> How events are handled DS> ====================== DS> There are three steps in event handling. DS> First, an event is triggered. This puts the event into the event DS> queue, but otherwise does nothing. (This operation is interrupt-safe, DS> though there issues in obtaining event PMCs at interrupt level in DS> some cases) DS> Next, a queue runner pulls an event out of the event queue and calls DS> its handlers. These are a combination of any event class handlers as DS> well as an event-specific callback, if there is one. This operation DS> happens as normal user-level code, though it may be done DS> significantly after the event itself is put in the queue, and may not DS> happen in the same thread as the event was requested from. [NB: I'm DS> not sure what to do about event handling threads and shared data yet] DS> Finally, for expected events, something can wait on the event to get DS> the event's data and status. This can be done before the event has DS> completed, in which case the operation will wait (draining the event DS> queue of pending events) DS> Note that the queue runner will automatically wait on any unexpected DS> event that it completes. This puts the event in the done state and DS> will throw any exception that the event handlers may have DS> generated. Expected events, however, will be left alone until DS> user-level code explicitly waits on it. so you separate expected vs unexpected as really user level handlers vs parrot internal handlers. why not call them all expected and internal. only those with user level stuff get a user level callback or wakeup on a wait. i don't see why the handling is so different. DS> Event States DS> ============ DS> Events have five states. They are: DS> * Quiescent - The event object has been newly allocated but hasn't DS> been associated with anything yet and can't be triggered call that 'new' instead. or maybe disabled (but that means the event has been associated with something already so new is better)? DS> * Waiting - The operation the event triggers on hasn't yet DS> happened this will be confusing with the 'wait' operation. i would call it 'watching' (from event.pm) or something similar (maybe 'active' or 'enabled'?) DS> * Triggered - The operation the event triggers on has happened, but DS> the event's handlers haven't been called yet DS> * Ready - The event has been processed by its handlers but hasn't yet DS> been waited on to flush out any exception it might have. DS> * Done - The event has flushed any pending exceptions and can now DS> only be queried for its status and data you also can use a 'stopped/disabled' state. in many cases you want an active event but stopped for a while. a good example is a write event on a an empty socket. if enabled, it will trigger all the time since the socket is always writeable and that will suck up the cpu. what i do is make write events disabled by default and you enable then when you have data to actually write. when the user space write buffer is empty you disable the event again. this is much cleaner than creating/destroying events. so my state list is: new enabled disabled triggered ready done when an event is done, who/what flushes the event itself from the system, normal GC? DS> getdata Pdata, Pevent DS> getdata Sdata, Pevent DS> Get the data associated with the event, if there is any. What the DS> data is depends on what generated the event. (For filehandle reads DS> this will be the data read from the filehandle) but won't that data already be passed in the callback? another point is that event i/o data should be passed by reference and treated as readonly to save copying all over the place. DS> cancel Pevent DS> Cancel the event, if possible. add enable/disable here. DS> settimer Pevent, Nseconds[, Pcallback, Puserdata] DS> settimer Pevent, Iseconds[, Pcallback, Puserdata] DS> Set a timer to go off in C<seconds> seconds. DS> setalarm Pevent, Nabs_time[, Pcallback, Puserdata] DS> setalarm Pevent, Iabs_time[, Pcallback, Puserdata] DS> Set a timer to go off at the absolute time specified. DS> setinterval Ninterval_seconds[, Pcallback, Puserdata] DS> setinterval Iinterval_seconds[, Pcallback, Puserdata] DS> Set an interval timer that goes off every interval_second seconds. are all those times (in Nseconds) are floats with fractional seconds? i don't think there is a need for all those variants. why would alarm need any special opcode when it is just a timer with a delay of abs_time - NOW? let the coder handle that and lose the extra op codes. also the interval can be folded in as a extra arg to the timer (either a repeat flag or an interval). the initial seconds can be the first delay and then reused for intervals or the interval value can take over: settimer Pevent, Idelay_seconds, Iinterval_seconds[, Pcallback, Puserdata] if interval_seconds is set (>0), use it for a repeating timer. if delay_seconds is set (>0), it is the first interval. so now all you have is two signatures (for float or integer seconds). you could have a mix of float delay and integer interval but that just makes 4 signatures. DS> C Interface DS> =========== DS> Because many events are actually generated from within C code, the DS> following API is exposed for use: DS> INTVAL Parrot_ping_event(Parrot_Interp Interpreter, INTVAL type); DS> Note that an event of type C<type> has just occurred. Returns either DS> 0 on success or 1 on failure. This function may fail if the target DS> interpreter is unable to post an event to its event queue. This DS> normally happens because there are no event PMCs available to DS> allocate for the event. clarify. who 'notes'? maybe call it 'check_event'? how is this different than post_event? overall a good start. looking forward to seeing a clean fast event core. uri -- Uri Guttman ------ [EMAIL PROTECTED] -------- http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org