>>>>> "DS" == Dan Sugalski <[EMAIL PROTECTED]> writes:
DS> Events and IO DS> ============= DS> Parrot has a unified event and IO system--indeed events are nothing DS> but satisfied IO requests. (Or, alternately, IO requests are nothing DS> but solicited events with external data) that is a very nice way to word what i have assumed for a long time. mind if i steal it? :) DS> Basic Architecture DS> ================== DS> The event and IO system revolves around streams, requests, and DS> events. Requests travel through streams and out the other end as DS> events. DS> Each stream in the event and IO system has the same structure. There DS> are zero or more pre-processing layers, a single "anchor" layer which DS> ultimately satisfies the request, one or more post-processing layers, DS> then the IO request becomes a notification that the request has been DS> satisfied and goes through the event handling layers. s/anchor/execution/g ? s/anchor/blocking/g ? (since this is the layer that should block until some event occurs). s/anchor/event loop/g ? (since this is where the core event loop runs) DS> The preprocessing, anchor, and post-processing layers are isolated DS> from the requesting thread, and layer code shouldn't count on access DS> to any information external to it. The event handling layers execute DS> in the context of the thread processing the event, and may count on DS> that thread's resources. DS> The system is simple--you make a request to a stream. The request DS> runs through the preprocessing layers which mangle it as they see DS> fit. The request then hits the anchor layer, which actually satisfies DS> the request. The anchor layer then passes the satisfied requests DS> through the post processing layers. When post-processing is done the DS> completed request is posted as an event, at which point a thread DS> watching the event queue will eventually process it by calling the DS> event layers. At this point the event is completed. DS> Non-IO things such as signals and OS events (assuming we can get to DS> them safely) behave the same way. The only difference is that the IO DS> request is originated by the anchor layer (which monitors the DS> external event source) and flows through the postprocessing and event DS> handling layers, but not the preprocessing layers. there may be some preprocessing when the initial request is sent it. there is no need to watch SIGUSR until the user code requests it. and that request could come from different sources so there could be some munging needed then. DS> At the moment each filehandle has a single set of IO layers which DS> handle all read, write, and command requests. This may change if it DS> turns out to be untenable, but split streams are a pain to keep DS> synchronized. what if the handles themselves are split as with a a pseudo-tty? but you could just do an event for the master and slave sides in that case. DS> Note that any layer along the way may defer the IO request. A DS> deferred request stays deferred until something resumes it, at which DS> point it continues through the IO layers. Deferring is normally done DS> by the anchor layer, if it is done at all. A deferred IO request is DS> not considered completed and will block processing of any more events DS> through an IO stream if that stream guarantees ordered request DS> processing. and what happens if the order is not guaranteed? is this a way to get the disable/enable feature i want? DS> Request/Event status DS> ==================== DS> Requests and events have one of the following statuses: DS> * Unprocessed - The request has been issued but not yet touched DS> * Preprocess - The request is in the preprocessing layers DS> * Handling - The request is being dealt with by the anchor layer DS> * Postprocess - The request is in the postprocessing layers DS> * Completing - The request is done and waiting for event handling DS> * Done - All the event handlers have run on the event DS> * Historical - The event has been waited for so any pending DS> exceptions have been delivered and of course enabled/disabled. if i say it often enough, maybe you get dizzy and patch it in. :) DS> Event/Request classes DS> ===================== DS> There are two classses of events and IO requests: solicited and DS> unsolicited. DS> A solicited event or request is one that a user program has DS> explicitly asked for. They are unique, and are generated as a result DS> of user code making a request for something to happen, for example a DS> read from a disk file or a one-shot timer. DS> An unsolicited event, on the other hand, is one that parrot generates DS> as the result of something happening external to itself, or as the DS> result of some recurring event happening. Signals and GUI events, for DS> example, are unsolicted as are recurring timer events. DS> There are four big differences between solicited and unsolicited DS> events: DS> 1) A solicited event goes through a stream's preprocessing DS> layers. Unsolicited events and requests do not. DS> 2) A solicted event may be cancelled from user code, as the user code DS> will have the request object as soon as the request is DS> made. Unsolicited events are only available to user code after the DS> fact--that is, user code only knows they exist after they have DS> happened. why would a signal event be delivered if i didn't request it? similarly for gui events. you would need to request hooks into the gui system in order to get mouse events. cli programs don't need gui stuff but a gui program solicits those events by linking in the gui lib. so parrot will need to either wrap those libs or come up with some other way to handle a mix of i/o and gui events. the gui libs already do that so wrapping makes sense. DS> 3) A solicited event may have a callback and user data associated DS> with it, an unsolicited event may not. then how does the user code handle a signal? i would want a callback. and even user data could be wanted. some signals (sigio?) can have attached (in some wierd way) data such as the async i/o results. the user callback should get that passed to it. DS> 4) Any exception associated with a solicited event will be thrown DS> when the event is waited on. An unsolicited event's exception is DS> thrown as soon as the event is drained from the event queue. then the exception is the implicit way to do a callback. i think some wording to that effect would be good. is there any way to pass event data in an exception? DS> The following methods are required of any event source that DS> implements the EventSource protocol: DS> pause DS> Stop the event source from emitting events. Any event that would be DS> triggered (signals, for example) are instead discarded. It is DS> generally considered unwise to pause event sources attached to IO devices. would this be an enable/disable thing? and disabling i/o events can make sense in some ways. ok, say you have a listen socket but only want to allow 1 (or N) connections. you disable listen events (which is really a read event on the listen socket) and when you can handle more connections, you reenable it. this is simpler and less work than cancelling the event/request and creating it again. DS> hold DS> Like pause, except the events are held rather than discarded. not sure how you would get this done. seems to need a queue layer around the actual event loop. why is this needed? DS> cancel DS> Permanently stop the event source. DS> unpause DS> Undo a pause or hold on the event source. If any events are pending DS> because of a prior hold, those events are then posted to the even tqueue. are those on a per event basis or on a whole event loop system? DS> IO Ops DS> ====== DS> newhandle Pfilehandle, Panchorsub DS> Create a new filehandle. C<anchorsub> is the subroutine that anchors DS> the filehandle chain. could that be a no-op sub? or is that just a simple pass-through? DS> pushhandler Pfilehandle, Phandlersub, Ireadwritecontrol DS> pophandler Pfilehandle DS> addhandler Pfilehandle, Phandlersub, Ioffset, Ireadwritecontrol DS> removehandler Pfilehandle, Phandlersub, Ioffset, Ireadwritecontrol so those two are splicing a handler into the list and push/pop can be written using them (at least internally)? DS> Synchronously write the data to the filehandle DS> seek Pevent, Pfilehandle, Iwhere[, Pcallback, Puserdata] why is this needed? and what would a seek callback do? seek isn't blocking in general as it just mungs the file offset in the inode (or whatever). any i/o to the new spot could be disk bound as it may need to seek then but the seek call shouldn't cause that. this feels like the old low level disk driver stuff where you could get an interrupt when the head has finished moving and the disk has rotated to the right point. with buffering on disks, that has mostly gone away (or rather, moved to firmware). DS> Submit a request to seek to the specified position in the file. DS> tell Pevent, Pfilehandle[, Pcallback, Puserdata] this is even odder. why would tell need a callback? DS> Submit a request for the current position in the filehandle. DS> un_read Pfilehandle, Pdata DS> Undo a read request, pushing Pdata back onto the filehandle. (Note DS> the _ in the op name) any max size of that call or total amounts you can push back? if the data was from a file can it be just discarded and a seek pointer moved? that fails if you read data and the file was modified, and then you un_read data. <SUBLIMINAL> put in enable/disable on events work harder. complain less. </SUBLIMINAL> overall i like it. very clean and consistant and clear. just my few nits to fix and you're set to go. 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