Sophie

Sophie

distrib > Mageia > 1 > i586 > by-pkgid > d92aa75c2d384ff9f513aed09a46f703 > files > 138

parrot-doc-3.1.0-2.mga1.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Parrot  - PDD 22: I/O</title>
        <link rel="stylesheet" type="text/css"
            href="../../../resources/parrot.css"
            media="all">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    </head>
    <body>
        <div id="wrapper">
            <div id="header">

                <a href="http://www.parrot.org">
                <img border=0 src="../../../resources/parrot_logo.png" id="logo" alt="parrot">
                </a>
            </div> <!-- "header" -->
            <div id="divider"></div>
            <div id="mainbody">
                <div id="breadcrumb">
                    <a href="../../../html/index.html">Home</a> &raquo; <a href="../../../html/pdds.html">Parrot Design Documents (PDDs)</a> &raquo; PDD 22: I/O
                </div>

<h1><a name="PDD_22:_I/O"
>PDD 22: I/O</a></h1>

<h2><a name="Abstract"
>Abstract</a></h2>

<p>Parrot&#39;s I/O subsystem.</p>

<h2><a name="Version"
>Version</a></h2>

<p>$Revision$</p>

<h2><a name="Definitions"
>Definitions</a></h2>

<p>A &#34;stream&#34; allows input or output operations on a source/destination such as a file,
keyboard,
or text console.
Streams are also called &#34;filehandles&#34;,
though only some of them have anything to do with files.</p>

<h2><a name="Description"
>Description</a></h2>

<dl>
<dt><a name="&#45;_Parrot_I/O_objects_support_both_streams_and_network_I/O."
>&#45; Parrot I/O objects support both streams and network I/O.</a></dt>

<dt><a name="&#45;_Parrot_has_both_synchronous_and_asynchronous_I/O_operations."
>&#45; Parrot has both synchronous and asynchronous I/O operations.</a></dt>

<dt><a name="&#45;_Asynchronous_operations_must_interact_safely_with_Parrot&#39;s_other_concurrency_models."
>&#45; Asynchronous operations must interact safely with Parrot&#39;s other concurrency models.</a></dt>
</dl>

<h2><a name="Implementation"
>Implementation</a></h2>

<h3><a name="Platform_Implementation"
>Platform Implementation</a></h3>

<p>Parrot uses a series of macros and conditional compilation to generate code to handle IO on various platforms.
There is a &#34;portable&#34; version of the IO system that is used for most systems that use a common POSIX API for IO,
and there are platform&#45;specific files that can be used for systems that do not subscribe,
or don&#39;t subscribe faithfully,
to POSIX.</p>

<p>A series of macros and conditional compilation are used to determine which files get added to the build,
and which functions are called to implement each operation.</p>

<h3><a name="Concurrency_Model_for_Asynchronous_I/O"
>Concurrency Model for Asynchronous I/O</a></h3>

<p>Currently,
Parrot only implements synchronous I/O operations.
Initially,
the asynchronous operations will be implemented separately from the synchronous ones.
There may be an implementation that uses one variant to implement the other someday,
but it&#39;s not an immediate priority.</p>

<p>Synchronous opcodes are differentiated from asynchronous opcodes by the presence of a callback argument in the asynchronous calls.
Asynchronous calls that don&#39;t supply callbacks (perhaps if the user wants to manually check later if the operation succeeded) are enough of a fringe case that they don&#39;t need opcodes.
They can access the functionality via methods on ParrotIO objects.</p>

<p>Asynchronous operations use a lightweight concurrency model.
At the user level,
Parrot follows the callback function model of asynchronous I/O.
At the interpreter level,
each asynchronous operation registers a task with the interpreter&#39;s concurrency scheduler.
The registered task could represent a simple Parrot asynchronous I/O operation,
a platform&#45;native asynchronous I/O call,
or even synchronous code in a full Parrot thread (rare but possibly useful for prototyping new features,
or for mock objects in testing).</p>

<p>Communication between the calling code and the asynchronous operation task is handled by a shared status object.
The operation task updates the status object whenever the status changes,
and the calling code can check the status object at any time.
The status object contains a reference to the returned result of an asynchronous I/O call.
In order to allow sharing of the status object,
asynchronous ops both pass the status object to the callback PMC,
and return it to the calling code.</p>

<p>The lightweight tasks typically used by the asynchronous I/O system capture no state other than the arguments passed to the I/O call,
and share no variables with the calling code other than the status object.</p>

<h3><a name="FileHandle_PMC_API"
>FileHandle PMC API</a></h3>

<p>Methods</p>

<dl>
<dt><a name="new"
><b><code>new</b></code></a></dt>
<pre>  $P0 = new [ 'FileHandle' ]
</pre>Creates a new I/O stream object.
[Note that this is usually performed via the <code>open</code> opcode.]
<dt><a name="open"
><b><code>open</b></code></a></dt>
<pre>  $P0 = $P1.'open'()
  $P0 = $P1.'open'($S2)
  $P0 = $P1.'open'($S2, $S3)
</pre>Opens a stream on an existing I/O stream object,
and returns a status object.
With no arguments,
it can be used to reopen a previously opened I/O stream.
$S2 is a file path and $S3 is an optional mode for the stream (read,
write,
read/write,
etc),
using the same format as the <code>open</code> opcode: &#39;r&#39; for read,
&#39;w&#39; for write,
&#39;a&#39; for append,
and &#39;p&#39; for pipe.
When the optional mode argument is not passed,
the default is read mode.
When the mode is set to write or append,
a file is created without warning if none exists.
When the mode is read (without write),
a nonexistent file is an error.The asynchronous version takes a PMC callback as an additional final argument.
When the open operation is complete,
it invokes the callback with a single argument: a status object containing the opened stream object.
<dt><a name="close"
><b><code>close</b></code></a></dt>
<pre>  $P0 = $P1.'close'()
  $P0 = $P1.'close'($P2)
</pre>Closes an I/O stream,
but leaves destruction of the I/O object to the GC.
The <code>close</code> method returns a PMC status object.The asynchronous version takes an additional final PMC callback argument $P1.
When the close operation is complete,
it invokes the callback,
passing it a status object.
[There&#39;s not really much advantage in this over just leaving the object for the GC to clean&#45;up,
but it does give you the option of executing an action when the stream has been closed.]
<dt><a name="print"
><b><code>print</b></code></a></dt>
<pre>  $P0 = $P1.'print'($I2)
  $P0 = $P1.'print'($N2)
  $P0 = $P1.'print'($S2)
  $P0 = $P1.'print'($P2)
  $P0 = $P1.'print'($I2, $P3)
  $P0 = $P1.'print'($N2, $P3)
  $P0 = $P1.'print'($S2, $P3)
  $P0 = $P1.'print'($P2, $P3)
</pre>Writes an integer,
float,
string,
or PMC value to an I/O stream object.
Returns a PMC status object.The asynchronous version takes an additional final PMC callback argument $P2.
When the print operation is complete,
it invokes the callback,
passing it a status object.
<dt><a name="read"
><b><code>read</b></code></a></dt>
<pre>  $S0 = $P1.'read'($I2)
  $P0 = $P1.'read'($I2, $P3)
</pre>Retrieves a specified number of bytes ($I2) from a stream $P1 into a string $S0.
By default it reads in bytes,
but the FileHandle object can be configured to read in code points instead,
by setting the character set and encoding on the filehandle object.
If there are fewer bytes remaining in the stream than specified in the read request,
it returns the remaining bytes (with no error).The asynchronous version takes an additional final PMC callback argument $P3,
and only returns a status object $P0.
When the read operation is complete,
it invokes the callback,
passing it a status object.
The status object contains the return value: a string that may be in bytes or codepoints depending on the read mode of the I/O object.
[The callback doesn&#39;t need to know the read mode of the original operation,
as the information about the character encoding of the return value is contained in the string.]
<dt><a name="readline"
><b><code>readline</b></code></a></dt>
<pre>  $S0 = $P1.'readline'()
  $P0 = $P1.'readline'($P2)
</pre>Retrieves a single line from a stream $P1 into a string $S1.
Calling <code>readline</code> flags the stream as operating in line&#45;buffer mode (see the <code>buffer_type</code> method below).
The <code>readline</code> operation respects the read mode of the I/O object the same as <code>read</code> does.
Newlines are not removed from the end of the string.The asynchronous version takes an additional final PMC callback argument $P2,
and only returns a status object $P0.
When the readline operation is complete,
it invokes the callback,
passing it a status object and a string of bytes.
<dt><a name="readall"
><b><code>readall</b></code></a></dt>
<pre>  $S0 = $P1.'readall'()
  $P0 = $P1.'readall'($P2)

  $S0 = $P1.'readall'($S2)
  $P0 = $P1.'readall'($S2, $P3)
</pre>Retrieves the entire contents from a stream $P1 into a string $S0.
On a previously opened stream,
<code>readall</code> will read the entire contents of the file,
and return them as a string.
It will respect the read mode of the I/O object the same as <code>read</code> does.On an unopened stream,
if a string file path is passed in $S2,
<code>readall</code> will open a stream on the file,
read the contents and close it again.The asynchronous version takes an additional final PMC callback argument ($P2 or $P3),
and only returns a status object $P0.
When the readall operation is complete,
it invokes the callback,
passing it a status object and a string.
<dt><a name="record_separator"
><b><code>record_separator</b></code></a></dt>
<pre>  $S0 = $P1.'record_separator'()
  $P0.'record_separator'($S1)
</pre>Accessor (get and set) for the I/O stream&#39;s record separator attribute.
The default value is a newline (CR,
LF,
CRLF,
etc.
depending on the platform).
<dt><a name="buffer_type"
><b><code>buffer_type</b></code></a></dt>
<pre>  $S0 = $P1.'buffer_type'()
  $P0.'buffer_type'($S1)
</pre>Accessor (get and set) for the I/O stream&#39;s buffer type attribute.
The attribute is set or returned as a string value of &#39;unbuffered&#39; (bytes sent as soon as possible),
&#39;line&#45;buffered&#39; (bytes sent when record separator is encountered),
or &#39;full&#45;buffered&#39; (bytes sent when the buffer is full).
<dt><a name="buffer_size"
><b><code>buffer_size</b></code></a></dt>
<pre>  $I0 = $P1.'buffer_size'()
  $P0.'buffer_size'($I1)
</pre>Accessor (get and set) for the I/O stream&#39;s buffer size attribute.
The size is specified in bytes (positive integer value),
though the buffer may hold a varying number of characters when dealing with an encoding of multi&#45;byte codepoints.
The code that implements the handling of a particular character set must provide the logic that marks the buffer as &#34;full&#34; when it can&#39;t hold the next codepoint even if there are empty bytes in the buffer.Setting the buffer size turns on full buffering mode for the I/O stream.
The set buffer size is taken as a minimum,
the I/O subsystem may round it up to a standard block size.The buffer is automatically flushed when the buffer size is changed.
If the new size was larger than the existing data in the buffer,
a size change would be non&#45;disruptive,
but if the new size was smaller,
resizing it without flushing would truncate the buffer.
<dt><a name="mode"
><b><code>mode</b></code></a></dt>
<pre>  $S0 = $P1.'mode'()
</pre>Accessor (get only) for the I/O stream&#39;s read mode.
This returns the mode string used to open the I/O stream.
<dt><a name="encoding"
><b><code>encoding</b></code></a></dt>
<pre>  $S0 = $P1.'encoding'()
  $P0.'encoding'($S1)
</pre>Accessor (get and set) for the I/O stream&#39;s encoding attribute.
Currently,
the only valid value to set is &#39;utf8&#39; which turns on UTF&#45;8 reading/writing mode for the stream.
The default behavior is fixed&#45;width 8&#45;bit characters.
<dt><a name="get_fd"
><b><code>get_fd</b></code></a></dt>
<pre>  $I0 = $P1.'get_fd'()
</pre>For stream objects that are simple wrappers around a Unix filehandle,
<code>get_fd</code> retrieves the Unix integer file descriptor of the object.
This method will simply return &#45;1 on stream objects that aren&#39;t Unix filehandles.No asynchronous version.</dl>

<h3><a name="Status_Object_PMC_API"
>Status Object PMC API</a></h3>

<dl>
<dt><a name="get_integer_(vtable)"
><b><code>get_integer</b></code> (vtable)</a></dt>
<pre>  $I0 = $P1
</pre>Returns an integer status for the status object,
1 for successful completion,
&#45;1 for an error,
and 0 while still running.
[Discuss: This is largely to preserve current expectations of &#45;1 for an error.
If we move away from that,
is there a better representation?]
<dt><a name="get_bool_(vtable)"
><b><code>get_bool</b></code> (vtable)</a></dt>
<pre>  if $P0 goto L1
  # ...
  L1:
</pre>Returns a boolean status for the status object,
<code>true</code> for successful completion or while still running,
<code>false</code> for an error.
<dt><a name="return"
><b><code>return</b></code></a></dt>
<pre>  $P0 = $P1.'return'()
</pre>Retrieves the return value of the asynchronous operation from the status object.
Returns a NULL PMC while still running,
or if the operation had no return value.
<dt><a name="error"
><b><code>error</b></code></a></dt>
<pre>  $P0 = $P1.'error'()
</pre>Retrieves the error object from the status object,
if the execution of the asynchronous operation terminated with an error.
The error object is derived from Exception,
and can be thrown from the callback.
If there was no error,
or the asynchronous operation is still running,
returns a null PMC.
<dt><a name="throw"
><b><code>throw</b></code></a></dt>
<pre>  $P0.'throw'()
</pre>Throw an exception from the status object if it contains an error object,
otherwise do nothing.</dl>

<h3><a name="I/O_Iterator_PMC_API"
>I/O Iterator PMC API</a></h3>

<p>[Implementation NOTE: this may either be the default Iterator object applied to a FileHandle or Socket object,
a separate Iterator object for I/O objects,
or an Iterator role applied to I/O objects.]</p>

<dl>
<dt><a name="new"
><b><code>new</b></code></a></dt>
<pre>    new $P0, [ 'Iterator' ], $P1
</pre>Create a new iterator object $P0 from I/O object $P1.
<dt><a name="shift"
><b><code>shift</b></code></a></dt>
<pre>      shift $S0, $P1
</pre>Retrieve the next line/block $S0 from the I/O iterator $P1.
The amount of data retrieved in each iteration is determined by the I/O object&#39;s <code>buffer_type</code> setting: unbuffered,
line&#45;buffered,
or fully&#45;buffered.
<dt><a name="get_bool_(vtable)"
><b><code>get_bool</b></code> (vtable)</a></dt>
<pre>  unless $P0 goto iter_end
</pre>Returns a boolean value for the iterator,
<code>true</code> if there is more data to pull from the I/O object,
<code>false</code> if the iterator has reached the end of the data.
[NOTE: this means that an iterator always checks for the next line/block of data when it retrieves the current one.]</dl>

<h3><a name="I/O_Opcodes"
>I/O Opcodes</a></h3>

<p>The signatures for the asynchronous operations are nearly identical to the synchronous operations,
but the asynchronous operations take an additional argument for a callback,
and the only return value from the asynchronous operations is a status object.
When the callbacks are invoked,
they are passed the status object as their sole argument.
Any return values from the operation are stored within the status object.</p>

<p>The listing below says little about whether the opcodes return error information.
For now assume that they can either return a status object,
or return nothing.
Error handling is discussed more thoroughly below in <a href='#Error_Handling'>&#34;Error Handling&#34;</a>.</p>

<h3><a name="I/O_Stream_Opcodes"
>I/O Stream Opcodes</a></h3>

<h4><a name="Opening_and_closing_streams"
>Opening and closing streams</a></h4>

<dl>
<dt><a name="open"
><b><code>open</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  $P0 = open $S1
  $P0 = open $S1, $S2
  $P0 = open $P1
  $P0 = open $P1, $S2
</pre>Opens a stream object based on a file path in $S1 and returns it.
The stream object defaults to read/write mode.
The optional string argument $S2 specifies the mode of the stream (read,
write,
append,
read/write,
etc.).
Currently the mode of the stream is set with a string argument similar to Perl 5 syntax,
but a language&#45;agnostic mode string is preferable,
using &#39;r&#39; for read,
&#39;w&#39; for write,
&#39;a&#39; for append,
and &#39;p&#39; for pipe.The asynchronous version takes a PMC callback as an additional final argument.
When the open operation is complete,
it invokes the callback with a single argument: a status object containing the opened stream object.
<dt><a name="close"
><b><code>close</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  close $P0
  close $P0, $P1
</pre>Closes a stream object.
It takes a single string object argument and returns a status object.The asynchronous version takes an additional final PMC callback argument.
When the close operation is complete,
it invokes the callback,
passing it a status object.</dl>

<h4><a name="Retrieving_existing_streams"
>Retrieving existing streams</a></h4>

<p>These opcodes do not have asynchronous variants.</p>

<ul>
<li><code>getstdin</code>,
<code>getstdout</code>,
and <code>getstderr</code> return a stream object for standard input,
standard output,
and standard error,
respectively.</li>

<li><code>fdopen</code> converts an existing and already open UNIX integer file descriptor into a stream object.
It also takes a string argument to specify the mode.</li>
</ul>

<h4><a name="Writing_to_streams"
>Writing to streams</a></h4>

<dl>
<dt><a name="print"
><b><code>print</b></code></a></dt>
<pre>  print $I0
  print $N0
  print $S0
  print $P0
  print $P0, $I1
  print $P0, $N1
  print $P0, $S1
  print $P0, $P1
  print $P0, $I1, $P2
  print $P0, $N1, $P2
  print $P0, $S1, $P2
  print $P0, $P1, $P2
</pre>Writes an integer,
float,
string,
or PMC value to a stream.
It writes to standard output by default,
but optionally takes a PMC argument to select another stream to write to.The asynchronous version takes an additional final PMC callback argument.
When the print operation is complete,
it invokes the callback,
passing it a status object.
<dt><a name="printerr"
><b><code>printerr</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  printerr $I0
  printerr $N0
  printerr $S0
  printerr $P0
</pre>Writes an integer,
float,
string,
or PMC value to standard error.There is no asynchronous variant of <code>printerr</code>.
[It&#39;s just a shortcut.
If they want an asynchronous version,
they can use <code>print</code>.]</dl>

<h4><a name="Reading_from_streams"
>Reading from streams</a></h4>

<dl>
<dt><a name="read"
><b><code>read</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  $S0 = read $I1
  $S0 = read $P1, $I2
  $P0 = read $P1, $I2, $P3
</pre>Retrieves a specified number of bytes,
$I2,
from a stream,
$P2,
into a string,
$S0.
[Note this is bytes,
not codepoints.] By default it reads from standard input,
but it also takes an alternate stream object source as an optional argument.The asynchronous version takes an additional final PMC callback argument,
and only returns a status object.
When the read operation is complete,
it invokes the callback,
passing it a status object and a string of bytes.
<dt><a name="readline"
><b><code>readline</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  $S0 = readline $P1
  $P0 = readline $P1, $P2
</pre>Retrieves a single line from a stream into a string.
Calling <code>readline</code> flags the stream as operating in line&#45;buffer mode.The asynchronous version takes an additional final PMC callback argument,
and only returns a status object.
When the readline operation is complete,
it invokes the callback,
passing it a status object and a string of bytes.
<dt><a name="peek"
><b><code>peek</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  $S0 = peek
  $S0 = peek $P1
</pre>[<code>peek</code>,
<code>seek</code>,
<code>tell</code>,
and <code>poll</code> are all candidates for moving from opcodes to FileHandle object methods.]<code>peek</code> retrieves the next byte from a stream into a string,
but doesn&#39;t remove it from the stream.
By default it reads from standard input,
but it also takes a stream object argument for an alternate source.There is no asynchronous version of <code>peek</code>.
[Does anyone have a line of reasoning why one might be needed?
The concept of &#34;next byte&#34; seems to be a synchronous one.]</dl>

<h4><a name="Retrieving_and_setting_stream_properties"
>Retrieving and setting stream properties</a></h4>

<dl>
<dt><a name="seek"
><b><code>seek</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  seek $P0, $I1, $I2
  seek $P0, $I1, $I2, $I3
  seek $P0, $I1, $I2, $P3
  seek $P0, $I1, $I2, $I3, $P4
</pre>Sets the current file position of a stream object,
$P0,
to an integer byte offset,
$I1,
from an integer starting position,
$I2,
(0 for the start of the file,
1 for the current position,
and 2 for the end of the file).
It also has a 64&#45;bit variant that sets the byte offset by two integer arguments,
$I1 and $I2,
(one for the first 32 bits of the 64&#45;bit offset,
and one for the second 32 bits).
[The two&#45;register emulation for 64&#45;bit integers may be deprecated in the future.]The asynchronous version takes an additional final PMC callback argument.
When the seek operation is complete,
it invokes the callback,
passing it a status object and the stream object it was called on.
<dt><a name="tell"
><b><code>tell</b></code></a></dt>
<pre>  .loadlib 'io_ops'
  ...
  $I0 = tell $P1
  ($I0, $I1) = tell $P2
</pre>Retrieves the current file position of a stream object.
It also has a 64&#45;bit variant that returns the byte offset as two integers (one for the first 32 bits of the 64&#45;bit offset,
and one for the second 32 bits).
[The two&#45;register emulation for 64&#45;bit integers may be deprecated in the future.]No asynchronous version.
<dt><a name="poll"
><b><code>poll</b></code></a></dt>
<pre>  $I0 = poll $P1, $I2, $I3, $I4
</pre>Polls a stream or socket object for particular types of events (an integer flag) at a frequency set by seconds and microseconds (the final two integer arguments).
[At least,
that&#39;s what the documentation in src/io/io.c says.
In actual fact,
the final two arguments seem to be setting the timeout,
exactly the same as the corresponding argument to the system version of <code>poll</code>.]See the system documentation for <code>poll</code> to see the constants for event types and return status.This opcode is inherently synchronous (poll is &#34;synchronous I/O multiplexing&#34;),
but it can retrieve status information from a stream or socket object whether the object is being used synchronously or asynchronously.</dl>

<h3><a name="Filesystem_Opcodes"
>Filesystem Opcodes</a></h3>

<p>[Okay,
I&#39;m seriously considering moving most of these to methods on the ParrotIO object.
More than that,
moving them into a role that is composed into the ParrotIO object when needed.
For the ones that have the form <code>opcodename io_object, arguments</code>,
I can&#39;t see that it&#39;s much less effort than <code>io_object.&#39;methodname&#39;(arguments)</code> for either manually writing PIR or generating PIR.
The slowest thing about I/O is I/O,
so I can&#39;t see that we&#39;re getting much speed gain out of making them opcodes.
The ones to keep as opcodes are <code>unlink</code>,
<code>rmdir</code>,
and <code>opendir</code>.]</p>

<ul>
<li><code>stat</code> retrieves information about a file on the filesystem.
It takes a string filename or an integer argument of a UNIX file descriptor [or an already opened stream object?],
and an integer flag for the type of information requested.
It returns an integer containing the requested information.
The following constants are defined for the type of information requested (see <em>runtime/parrot/include/stat.pasm</em>):</li>

<pre>  0    STAT_EXISTS
           Whether the file exists.
  1    STAT_FILESIZE
           The size of the file.
  2    STAT_ISDIR
           Whether the file is a directory.
  3    STAT_ISDEV
           Whether the file is a device such as a terminal or a disk.
  4    STAT_CREATETIME
           The time the file was created.
           (Currently just returns &#45;1.)
  5    STAT_ACCESSTIME
           The last time the file was accessed.
  6    STAT_MODIFYTIME
           The last time the file data was changed.
  7    STAT_CHANGETIME
           The last time the file metadata was changed.
  8    STAT_BACKUPTIME
           The last time the file was backed up.
           (Currently just returns &#45;1.)
  9    STAT_UID
           The user ID of the file.
  10   STAT_GID
           The group ID of the file.</pre>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the stat operation is complete, it invokes the callback, passing it a status object and an integer containing the status information.</p>

<li><code>unlink</code> deletes a file from the filesystem. It takes a single string argument of a filename (including the path).</li>

<p>The asynchronous version takes an additional final PMC callback argument. When the unlink operation is complete, it invokes the callback, passing it a status object.</p>

<li><code>rmdir</code> deletes a directory from the filesystem if that directory is empty. It takes a single string argument of a directory name (including the path).</li>

<p>The asynchronous version takes an additional final PMC callback argument. When the rmdir operation is complete, it invokes the callback, passing it a status object.</p>

<li><code>opendir</code> opens a stream object for a directory. It takes a single string argument of a directory name (including the path) and returns a stream object.</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the opendir operation is complete, it invokes the callback, passing it a status object and a newly created stream object.</p>

<li><code>readdir</code> reads a single item from an open directory stream object. It takes a single stream object argument and returns a string containing the path and filename/directory name of the current item. (i.e. the directory stream object acts as an iterator.)</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the readdir operation is complete, it invokes the callback, passing it a status object and the string result.</p>

<li><code>telldir</code> returns the current position of <code>readdir</code> operations on a directory stream object.</li>

<p>No asynchronous version.</p>

<li><code>seekdir</code> sets the current position of <code>readdir</code> operations on a directory stream object. It takes a stream object argument and an integer for the position. [The system <code>seekdir</code> requires that the position argument be the result of a previous <code>telldir</code> operation.]</li>

<p>The asynchronous version takes an additional final PMC callback argument. When the seekdir operation is complete, it invokes the callback, passing it a status object and the directory stream object it was called on.</p>

<li><code>rewinddir</code> sets the current position of <code>readdir</code> operations on a directory stream object back to the beginning of the directory. It takes a stream object argument.</li>

<p>No asynchronous version.</p>

<li><code>closedir</code> closes a directory stream object. It takes a single stream object argument.</li>

<p>The asynchronous version takes an additional final PMC callback argument. When the closedir operation is complete, it invokes the callback, passing it a status object.</p>
</ul>

<h3><a name="Network_I/O_Methods"
>Network I/O Methods</a></h3>

<p>Most of these methods take a default set of arguments the same as the standard UNIX interface. Many also take additional optional arguments. There are no network&#45;specific opcodes.</p>

<ul>
<li><code>socket</code> returns a new socket object from a given address family, socket type, and protocol number (all integers). The socket object&#39;s boolean value can be tested to see if the socket is open or closed.</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the socket operation is complete, it invokes the callback, passing it a status object and a new socket object.</p>

<li><code>sockaddr</code> returns a SockAddr object representing a socket address, generated from a port number (integer) and an address (string).</li>

<p>No asynchronous version.</p>

<li><code>connect</code> connects a socket object to an address.</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the socket operation is complete, it invokes the callback, passing it a status object and the socket object it was called on. [If you want notification when a connect operation is completed, you probably want to do something with that connected socket object.]</p>

<li><code>recv</code> receives a message from a connected socket object. It returns the message in a string.</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the recv operation is complete, it invokes the callback, passing it a status object and a string containing the received message.</p>

<li><code>send</code> sends a message string to a connected socket object.</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the send operation is complete, it invokes the callback, passing it a status object.</p>

<li><code>sendto</code> sends a message string to an address specified in an address object (first connecting to the address).</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the sendto operation is complete, it invokes the callback, passing it a status object.</p>

<li><code>bind</code> binds a socket object to the port and address specified by an address object (the packed result of <code>sockaddr</code>).</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the bind operation is complete, it invokes the callback, passing it a status object and the socket object it was called on. [If you want notification when a bind operation is completed, you probably want to do something with that bound socket object.]</p>

<li><code>listen</code> specifies that a socket object is willing to accept incoming connections. The integer argument gives the maximum size of the queue for pending connections.</li>

<p>There is no asynchronous version. <code>listen</code> marks a set of attributes on the socket object.</p>

<li><code>accept</code> accepts a new connection on a given socket object, and returns a newly created socket object for the connection.</li>

<p>The asynchronous version takes an additional final PMC callback argument, and only returns a status object. When the accept operation receives a new connection, it invokes the callback, passing it a status object and a newly created socket object for the connection. [While the synchronous <code>accept</code> has to be called repeatedly in a loop (once for each connection received), the asynchronous version is only called once, but continues to send new connection events until the socket is closed.]</p>

<li><code>shutdown</code> closes a socket object for reading, for writing, or for all I/O. It takes a socket object argument and an integer argument for the type of shutdown:</li>

<pre>  0    PIOSHUTDOWN_READ
           Close the socket object for reading.
  1    PIOSHUTDOWN_WRITE
           Close the socket object for writing.
  2    PIOSHUTDOWN
           Close the socket object.</pre>
</ul>

<h3><a name="Error_Handling"
>Error Handling</a></h3>

<p>Currently some of the networking opcodes (<code>connect</code>, <code>recv</code>, <code>send</code>, <code>poll</code>, <code>bind</code>, and <code>listen</code>) return an integer indicating the status of the call, &#45;1 or a system error code if unsuccessful. Other I/O opcodes (such as <code>accept</code>) have various different strategies for error notification, and others have no way of marking errors at all. We want to unify all I/O opcodes so they use a consistent strategy for error notification.</p>

<h4><a name="Synchronous_operations"
>Synchronous operations</a></h4>

<p>Synchronous I/O operations return an integer status code indicating success or failure in addition to their ordinary return value(s). This approach has the advantage of being lightweight: returning a single additional integer is cheap.</p>

<p>[Discuss: should synchronous operations take the same error handling strategy as asynchronous ones?]</p>

<h4><a name="Asynchronous_operations"
>Asynchronous operations</a></h4>

<p>Asynchronous I/O operations return a status object. The status object contains an integer status code, string status/error message, and boolean success value.</p>

<p>An error callback may be set on a status object, though it isn&#39;t required. This callback will be invoked if the asynchronous operation terminates in an error condition. The error callback takes one argument, which is the status object containing all information about the failed call. If no error callback is set, then the standard callback will be invoked, and the user will need to check for error conditions in the status object as the first operation of the handler code.</p>

<h4><a name="Exceptions"
>Exceptions</a></h4>

<p>At some point in the future, I/O objects may also provide a way to throw exceptions on error conditions. This feature will be enabled by calling a method on the I/O object to set an internal flag. The exception throwing will be implemented as a method call on the status object.</p>

<p>Note that exception handlers for asynchronous I/O operations will likely have to be set at a global scope because execution will have left the dynamic scope of the I/O call by the time the error occurs.</p>

<h3><a name="IPv6_Support"
>IPv6 Support</a></h3>

<p>The transition from IPv4 to IPv6 is in progress, though not likely to be complete anytime soon. Most operating systems today offer at least dual&#45;stack IPv6 implementations, so they can use either IPv4 or IPv6, depending on what&#39;s available. Parrot also needs to support either protocol. For the most part, the network I/O opcodes should internally handle either addressing scheme, without requiring the user to specify which scheme is being used.</p>

<p>IETF recommends defaulting to IPv6 connections and falling back to IPv4 connections when IPv6 fails. This would give us more solid testing of Parrot&#39;s compatibility IPv6, but may be too slow. Either way, it&#39;s a good idea to make setting the default (or selecting one exclusively) an option when compiling Parrot.</p>

<p>The most important issues for Parrot to consider with IPv6 are:</p>

<ul>
<li>Support 128 bit addresses. IPv6 addresses are colon&#45;separated hexadecimal numbers, such as <code>20a:95ff:fef5:7e5e</code>.</li>

<li>Any address parsing should be able to support the address separated from a port number or prefix/length by brackets: <code>[20a:95ff:fef5:7e5e]:80</code> and <code>[20a:95ff::]/64</code>.</li>

<li>Packed addresses, such as the result of the <code>sockaddr</code> opcode, should be passed around as an object (or at least a structure) rather than as a string.</li>
</ul>

<p>See the relevant IETF RFCs: &#34;Application Aspects of IPv6 Transition&#34; (<a href="http://www.ietf.org/rfc/rfc4038.txt">http://www.ietf.org/rfc/rfc4038.txt</a>) and &#34;Basic Socket Interface Extensions for IPv6&#34; (<a href="http://www.ietf.org/rfc/rfc3493.txt">http://www.ietf.org/rfc/rfc3493.txt</a>).</p>

<h2><a name="Links"
>Links</a></h2>

<p><a href='http://en.wikipedia.org/wiki/Asynchronous_I/O'><a href="http://en.wikipedia.org/wiki/Asynchronous_I/O">http://en.wikipedia.org/wiki/Asynchronous_I/O</a></a> for a relatively comprehensive list of asynchronous I/O implementation options.</p>

<h2><a name="References"
>References</a></h2>

<p><em>src/io/core.c</em>, <em>src/ops/io.ops</em>, <em>include/parrot/io.h</em>, <em>runtime/parrot/library/Stream/*</em>, <em>src/io/unix.c</em>, <em>src/io/win32.c</em>, Perl 5&#39;s IO::AIO, and POE</p>
            </div> <!-- "mainbody" -->
            <div id="divider"></div>
            <div id="footer">
	        Copyright &copy; 2002-2011, Parrot Foundation.
            </div>
        </div> <!-- "wrapper" -->
    </body>
</html>