>>>>> "DS" == Dan Sugalski <[EMAIL PROTECTED]> writes:
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? :)
Sure, go ahead.
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)
Nope, anchor. It's not the event loop--that's elsewhere. The anchor layer (as well as the pre and post processing layers) may execute asynchronously, in their own thread.
It's the one unchangeable layer in a stream, the one between the pre and post processing layers. It anchors things, hence the name. (Or so my thinking goes, at least)
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.
When the code requests a signal we put a stream in place for that signal, which becomes the event source for it. You're not requesting a single IO action--you're creating a new event source. Different things. I need to make that a lot clearer.
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.
Each side is a separate thing in that case, if I'm understanding you correctly.
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?
Then the stream may take requests in whatever order it wants. If someone wanted to implement an elevator algorithm for a filehandle (which'd be kind of silly, the OS is usually better for that) or pre-scan the stream and satisfy read requests with prior write requests that overlap, well... they could. The IO requests would potentially get satisfied out of order, which can make for really confusing behaviour if you're not expecting it.
is this a way to get the disable/enable feature i want?
Nope. For that you pause the stream.
DS> Request/Event status DS> ====================
and of course enabled/disabled. if i say it often enough, maybe you get dizzy and patch it in. :)
Nope, not going to happen. :) Events aren't disabled--streams are disabled.
DS> Event/Request classes DS> =====================
why would a signal event be delivered if i didn't request it?
You've requested that a class of signal events, in general, be delivered when they occur.
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.
Right, all of which set up event sources.
The difference is this. With a solicited request you've said "Do this one very specific thing. When you're done, run this very specific function with this specific piece of data". You can use the request object to see where it is in the stream, what state it's in, and potentially kill it if you've decided you don't want that one specific thing to happen.
An unsolicited request, on the other hand, is one where you've said "When the general class of events X happens, send me an event" and the system has. You don't know in advance that one specific thing is going to happen, and only get the event after the fact. You can't associate one specific sub and specific piece of data with it before it happens because you don't know that it's going to happen until after it does.
Solicited events happen because of something your program asks to have happen, while unsolicited events are essentially interrupts.
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.
Each event stream has a set of event handlers associated with it. If you want a callback for SIGUSR, for example, you'd push that layer onto the SIGUSR stream's event layer list.
and even user data could be wanted.
Then either a postprocessing layer or an event layer on the signal's stream would have to add it .
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.
Yeah, but just sigio, and only in a few systems. Doesn't matter, though--you can't get access to SIGIO and SIGALRM from user code. Parrot steals those. :) (Well, OK, unless the embedding program steals 'em first)
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.
But a very bad one. Exceptions aren't resumable, and you may find you've walked much too far out. You also can't be sure where the exception's thrown, either.
i think some wording to that effect would be good. is there any way to pass event data in an exception?
Only if the code that throws the exception embeds the event in it.
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?
Yes.
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.
Which we need anyway, for event levels.
why is this needed?
In the cases where you don't want to deal with the events but don't want them thrown out either.
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?
Per event source.
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?
It could be a noop, but in that case nothing would happen if you read or wrote to the stream inless you've
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)?
These actually are editing errors. I cut-n-pasted from the IO doc I was working on without taking into account the split into pre/post/event layers. I'll fix that in V2.
DS> Synchronously write the data to the filehandle
DS> seek Pevent, Pfilehandle, Iwhere[, Pcallback, Puserdata]
why is this needed?
It isn't, strictly speaking--it could be a single generic "IOCommand" op.
and what would a seek callback do?
Callback? It's mostly in there for orthogonality, as all requests can have a callback and user data associated with them.
seek isn't blocking in general
Well... it is if you've queued up a dozen or more write or read requests.
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?
Orthogonality. That and every time I think "Why the *hell* would someone need that?" someone comes along with a reason that's both good and scares me. Since the system supports it, it's exposed.
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?
Nope.
if the data was from a file can it be just discarded and a seek pointer moved?
Nope. It gets queued up for pending read requests.
that fails if you read data and the file was modified, and then you un_read data.
Sorta. I didn't put the details of unreading in this draft. I'll fix that for v2.
--
Dan
--------------------------------------"it's like this"------------------- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk