I've been doing some prepping and I put together some quick and very
dirty prototypes yesterday and think I have a plan about how to make
this work. My plan involves a few changes to PDD22, so I want to get
some feedback about all that before I do anything.

1) I don't want to have an asynchronous version of the "open" opcode.

2) We're going to need to open streams in either synchronous or
asynchronous mode. I'm proposing we use an "n" mode flag for
non-blocking and a "b" flag for blocking. This way we can use existing
methods "read" and "write", etc to do what we want.

3) Add an "is_async" method to stream objects to return whether the
stream was opened async or not

4) We can call a non-asynchronous opcode with an asynchronous stream,
and vice-versa, though the PDD suggests that we cannot (or should
not).
4a) Calling a non-blocking op with a synchronous stream performs the
synchronous operation, calls the callback immediately, and returns a
status object that already reads "complete". Relatedly, this kind of
behavior is how we will simulate AIO on systems that don't support it.
4b) Calling a blocking op on an async stream launches the request but
doesn't return a status object to track it. Launch it and forget it.

5) We're going to create an IO polling mechanism to keep track of
requests. The polling mechanism will be polled from the scheduler, in
addition to being polled manually. When a request is completed, the
associated callback Task is scheduled. The PDD doesn't disagree with
this, it just doesn't mention any implementation details like this.

I'd also very much like to hear some feedback about how people expect
to actually USE this system from PIR.  Here are some examples that I
am envisioning, but I want to hear if other people think they are
useful:

$P0 = open "filename", "nr"  # open in "non-blocking" mode
$P1 = read $P0, 10, $P2     # read with a callback ($P2) and a request
status object ($P1)
check: unless $P1 goto check  # block until the operation completes
$S0 = $P1.'return_value'()    # Get the string

$P0 = open "filename", "br" # open in "blocking" mode
$P1 = read $P0, 10, $P2    # the stream is blocking. Do the read, call
the callback, return a "complete" status object
check: unless $P1 goto check # Already complete, basically does nothing
$S0 = $P1.'return_value'()    # Get the string

$P0 = open "filename", "nw" # open in "non-blocking" mode
$P1 = write $P0, "hello", $P2 # Write with a callback and a status object
check: unless $P1 goto check
$I0 = $P1.'return_value'()        # get number of bytes written

Also, some error handling:

$P0 = open "filename", "nr"  # open in "non-blocking" mode
$P1 = read $P0, 10, $P2     # read with a callback ($P2) and a request
status object ($P1)
check: unless $P1 goto check  # block until the operation completes
$P1.'throw'()  # Throw exception if there's an error, nothing otherwise

Or,

$P0 = open "filename", "nr"  # open in "non-blocking" mode
$P1 = read $P0, 10, $P2     # read with a callback ($P2) and a request
status object ($P1)
check: unless $P1 goto check  # block until the operation completes
$I0 = $P1.'status'()             # -1 = error, 0 = pending, 1 = success
if $I0 == 1 goto success
$S0 = $P1.'error'()              # get the error message string
say $S0
success:

Also, the callback functions will take a single parameter, the status
object. In this way we don't need to poll the request status, we can
let the callback tell us when it's done:

.sub iocallback
.param pmc iostatus
$I0 = iostatus.'status'()
... # do something with the status result here.
.end

So, I would really like to get some feedback here, to make sure I am
looking at this in a reasonable way, and that it's meeting the needs
of the potential users.

--Andrew Whitworth
_______________________________________________
http://lists.parrot.org/mailman/listinfo/parrot-dev

Reply via email to