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