The comments on the first draft that still apply have been
incorporated in this draft. I fully expect to make a second one as
there's quite a bit of IO that's still unspecified, but I wanted to
get this out for folks to think about.
++++++++++++++++++++++++++Snip Here++++++++++++++++++
Events and IO
=============
Parrot has a unified event and IO system--indeed events are nothing
but satisfied IO requests. (Or, alternately, IO requests are nothing
but solicited events with external data)
Basic Architecture
==================
The event and IO system revolves around streams, requests, and
events. Requests travel through streams and out the other end as
events.
Each stream in the event and IO system has the same structure. There
are zero or more pre-processing layers, a single "anchor" layer which
ultimately satisfies the request, one or more post-processing layers,
then the IO request becomes a notification that the request has been
satisfied and goes through the event handling layers.
The preprocessing, anchor, and post-processing layers are isolated
from the requesting thread, and layer code shouldn't count on access
to any information external to it. The event handling layers execute
in the context of the thread processing the event, and may count on
that thread's resources.
The system is simple--you make a request to a stream. The request
runs through the preprocessing layers which mangle it as they see
fit. The request then hits the anchor layer, which actually satisfies
the request. The anchor layer then passes the satisfied requests
through the post processing layers. When post-processing is done the
completed request is posted as an event, at which point a thread
watching the event queue will eventually process it by calling the
event layers. At this point the event is completed.
Non-IO things such as signals and OS events (assuming we can get to
them safely) behave the same way. The only difference is that the IO
request is originated by the anchor layer (which monitors the
external event source) and flows through the postprocessing and event
handling layers, but not the preprocessing layers.
At the moment each filehandle has a single set of IO layers which
handle all read, write, and command requests. This may change if it
turns out to be untenable, but split streams are a pain to keep
synchronized.
Note that any layer along the way may defer the IO request. A
deferred request stays deferred until something resumes it, at which
point it continues through the IO layers. Deferring is normally done
by the anchor layer, if it is done at all. A deferred IO request is
not considered completed and will block processing of any more events
through an IO stream if that stream guarantees ordered request
processing.
Layer and Callback functions
============================
Since IO layers and event callbacks are identical, they have the same
signature. That signature is:
(Sreturndata, Icommand) =
layersub(Pevent, Slayerdata, Scallbackdata, Icommand)
The returndata from a layer is passed into the next layer as its
layerdata parameter, and the returned command status is passed onto
the next layer as its command parameter. This way a layer can alter
what the next layer in the chain sees.
The commands are:
* 1 - Event
* 2 - Read request
* 3 - Write request
* 4 - Command request. The layerdata holds the command itself
* 5 - Reset stream
* 6 - Close stream
Negative command arguments indicate that the command request has had
an error or exception of some kind. Layers may pull out the error
or exception status to determine what they should do. A layer may
change the error status of the request by just setting it, while it
may change the exception status by throwing an exception of its
own. Requests have a single exception associated with them, the last
exception thrown by a layer in the stream.
Request/Event status
====================
Requests and events have one of the following statuses:
* Unprocessed - The request has been issued but not yet touched
* Preprocess - The request is in the preprocessing layers
* Handling - The request is being dealt with by the anchor layer
* Postprocess - The request is in the postprocessing layers
* Completing - The request is done and waiting for event handling
* Done - All the event handlers have run on the event
* Historical - The event has been waited for so any pending
exceptions have been delivered
Event/Request classes
=====================
There are two classses of events and IO requests: solicited and
unsolicited.
A solicited event or request is one that a user program has
explicitly asked for. They are unique, and are generated as a result
of user code making a request for something to happen, for example a
read from a disk file or a one-shot timer.
An unsolicited event, on the other hand, is one that parrot generates
as the result of something happening external to itself, or as the
result of some recurring event happening. Signals and GUI events, for
example, are unsolicted as are recurring timer events.
There are four big differences between solicited and unsolicited
events:
1) A solicited event goes through a stream's preprocessing
layers. Unsolicited events and requests do not.
2) A solicted event may be cancelled from user code, as the user code
will have the request object as soon as the request is
made. Unsolicited events are only available to user code after the
fact--that is, user code only knows they exist after they have
happened.
3) A solicited event may have a callback and user data associated
with it, an unsolicited event may not.
4) Any exception associated with a solicited event will be thrown
when the event is waited on. An unsolicited event's exception is
thrown as soon as the event is drained from the event queue.
Interfacing with System Events
==============================
It is possible, given the nature of fighting event loops, that parrot
may not be able to integrate its event system with the system event
loop.
Event Source Methods
====================
The following methods are required of any event source that
implements the EventSource protocol:
pause
Stop the event source from emitting events. Any event that would be
triggered (signals, for example) are instead discarded. It is
generally considered unwise to pause event sources attached to IO devices.
hold
Like pause, except the events are held rather than discarded.
cancel
Permanently stop the event source.
unpause
Undo a pause or hold on the event source. If any events are pending
because of a prior hold, those events are then posted to the even tqueue.
Event Ops
=========
The opcodes in this section are a combination of event requests and
event handling ops. It doesn't include the IO ops--those are separate.
Most of the event request ops have two forms, one of which takes a
callback PMC and user data PMC.
checkevent
Explicitly check to see if there are any events pending in the event queue and,
if so process one.
drainqueue
Wait forever, draining the event queue as it fills. This op only
exits if it encounters a QUEUE_DONE event in the queue.
wait Pevent
Wait for the specified event to complete. If the event has already
completed the op doesn't wait. If there is a pending exception it is
thrown. This opcode will drain the pending event queue.
getstat Istatus, Pevent
Returns the status of the event, noting whether it has been completed
yet and, if so, what happened.
getdata Pdata, Pevent
getdata Sdata, Pevent
Get the data associated with the event, if there is any. What the data is
depends on what generated the event. (For filehandle reads this will
be the data read from the filehandle)
getuser Puserdata, Pevent
Get the user data that was passed into this event.
cancel Pevent
Cancel the request, if possible.
post Pevent
Post an event to the event queue for later handling
sethandler Ieventclass, Phandlersub
Set the default handler for the specified class of events.
seteventlevel Ieventlevel
Set the current event level. Events of a lower level than this won't
be processed.
IO Ops
======
These are the ops that control IO. Note that the synchronous versions
of the ops are just simple wrappers around the asynchronous
versions. For example, this:
readw mydata, Filehandle, 500
is equivalent to the sequence
read tempevent, Filehandle, 500
wait tempevent
getdata mydata, tempevent
but is provided for convenience for those languages which are so
averse to asynchronous IO that they don't want to even acknowledge
its existence.
newhandle Pfilehandle, Panchorsub
Create a new filehandle. C<anchorsub> is the subroutine that anchors
the filehandle chain.
pushhandler Pfilehandle, Phandlersub, Ireadwritecontrol
pophandler Pfilehandle
addhandler Pfilehandle, Phandlersub, Ioffset, Ireadwritecontrol
removehandler Pfilehandle, Phandlersub, Ioffset, Ireadwritecontrol
read Pevent, Pfilehandle, Ihowmuch[, Pcallback, Puserdata]
Request a read of data from the filehandle.
readw Pdata, Pfilehandle, Ihowmuch
Synchronously read C<howmuch> data from the filehandle.
write Pevent, Pfilehandle, Pdata[, Pcallback, Puserdata]
Write the data to the filehandle.
writew Pfilehandle, Pdata
Synchronously write the data to the filehandle
seek Pevent, Pfilehandle, Iwhere[, Pcallback, Puserdata]
Submit a request to seek to the specified position in the file.
tell Pevent, Pfilehandle[, Pcallback, Puserdata]
Submit a request for the current position in the filehandle.
un_read Pfilehandle, Pdata
Undo a read request, pushing Pdata back onto the filehandle. (Note
the _ in the op name)
--
Dan
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk
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 ------ u...@stemsystems.com -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
I don't think that there is much difference between these two types of
events. You don't get signals if you don't do the appropriate sigaction
call. You ask the OS for an one-shot timer or for a recurring one, so
you'll get one or more events. That's all known.
> There are four big differences between solicited and unsolicited
> events:
That's adding some unneeded restrictions IMHO.
> 3) A solicited event may have a callback and user data associated
> with it, an unsolicited event may not.
E.g. this looks like that you can't run a user handler on a repeated
timer.
> IO Ops
Uri did already comment on seek/tell. Some of the *handler ops probably
need some more explanation.
leo
The difference there is that a solicited event is one you have asked
for *and* received an event/request object for, so you can identify
the request/event as it makes its way through a stream. You can't do
that with the unsolicited ones, since you don't know they exist until
they've shown up.
I think I need to make clearer the difference between events and
event sources, since that's a source of confusion with Uri too.
> > There are four big differences between solicited and unsolicited
>> events:
>
>That's adding some unneeded restrictions IMHO.
Then it needs some more explanation, since they're not so much
restrictions as statements of fact which fall out of the design.
> > 3) A solicited event may have a callback and user data associated
>> with it, an unsolicited event may not.
>
>E.g. this looks like that you can't run a user handler on a repeated
>timer.
That's one of the things that's missing. You can, but only in a
general sense--that is, you can have a handler that is run for every
event of a particular class, and since timers are a class, well...
there you go.
> > IO Ops
>
>Uri did already comment on seek/tell. Some of the *handler ops probably
>need some more explanation.
Yep, there's a lot that needs fleshing out, but I figured a first
draft of the skeleton would be worthwhile. Working on draft 2.
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.
> Event Ops
> =========
>
> The opcodes in this section are a combination of event requests and
> event handling ops. It doesn't include the IO ops--those are separate.
>
> Most of the event request ops have two forms, one of which takes a
> callback PMC and user data PMC.
>
> checkevent
>
> Explicitly check to see if there are any events pending in the event
> queue and, if so process one.
So, for GUI events, could calling into parrot and doing the following
from the OS event handler work to synchronously dispatch an event?
... parrot-ify a mouse-moved event into $P5 ...
post $P5
checkevent
Hm. No. If there's already an event in the queue, then that won't
work... :( Maybe this change, instead:
polleventq(out Pevent)
Shifts one event off of the queue into Pevent, or nulls Pevent.
dispatch(in Pevent)
Invokes the registered event handler(s) for Pevent.
Which makes checkevent really this:
polleventq Py
isnull Py, .NO_EVENT
dispatch Py
.NO_EVENT:
—
Gordon Henriksen
IT Manager
ICLUBcentral Inc.
gor...@iclub.com
For that I think you'd want:
post $P5
wait $P5
> Gordon Henriksen wrote:
>
> > So, for GUI events, could calling into parrot and doing the
> > following from the OS event handler work to synchronously dispatch
> > an event?
> >
> > ... parrot-ify a mouse-moved event into $P5 ...
> > post $P5
> > checkevent
> >
> > Hm. No.
>
> For that I think you'd want:
>
> post $P5
> wait $P5
I suppose that would work, since the "wait" would block the main OS
thread. It does cause unnecessary context switches, though.
What happens in this case if the parrot eventloop is stopped? Does the
GUI thread block indefinitely in the "wait" op? That would keep the
program open even though parrot seemingly wanted to shut down.
Just decoupling the event queue and dispatch mechanisms seems cleaner to
my eye.
--
Well... sort of. Wait will drain the event queue until the event
you're waiting on has been completed.
> It does cause unnecessary context switches, though.
Nah. There may not even be any threads involved.
>What happens in this case if the parrot eventloop is stopped?
That's a good question, and I'm not sure what the right answer is.
I think, though, that "You lose" is the best we're going to do. If
you've blocked one or more events from being handled but are waiting
for them to be handled before continuing then you're doomed, and
there's not much to be done about it.
Perhaps that's a better thing to use to describe them, then. I
understand the intuitive difference between expected/unexpected or
solicited/unsolicited, but upon closer examination that particular
difference gets really fuzzy. Perhaps registered/unregistered? You
really want to say that you have a handle ("event"? "object"?)
associated with your solicited event, but I don't know how to turn
that into an adjective. Preallocated? Prepared? Identified? Labeled?
Named? Tracked? Hey, that last one might work.