I/O with file descriptors

Reading

The POSIX.1 read(2) syscall

Read data from an Fd and convert it to a ByteString.
Throws an exception if this is an invalid descriptor, or EOF has
been reached.

This is essentially equivalent to the POSIX.1 read(2) system
call; the differences are that we allocate a byte buffer for the
ByteString (and then pass its underlying Ptr Word8 and
ByteCount components to fdReadBuf), and that we detect EOF
and throw an IOError.

Read data from an Fd and convert it to a ByteString.
Throws an exception if this is an invalid descriptor, or EOF has
been reached.

This version takes a kind of stateful predicate for whether and
how long to keep retrying. Assume the function is called as
fdReads f z0 fd n0. We will attempt to read n0 bytes from
fd. If we fall short, then we will call f len z where len
is the total number of bytes read so far and z is the current
state (initially z0). If it returns Nothing then we will
give up and return the current buffer; otherwise we will retry
with the new state, continuing from where we left off.

For example, to define a function that tries up to n times,
we can use:

The benefit of doing this instead of the naive approach of calling
fdRead repeatedly is that we only need to allocate one byte
buffer, and trim it once at the end--- whereas the naive approach
would allocate a buffer, trim it to the number of bytes read,
and then concatenate with the previous one (another allocation,
plus copying everything over) for each time around the loop.

The XPG4.2 pread(2) syscall

Read data from a specified position in the Fd and convert
it to a ByteString, without altering the position stored
in the Fd. Throws an exception if this is an invalid descriptor,
or EOF has been reached.

This is essentially equivalent to the XPG4.2 pread(2) system
call; the differences are that we allocate a byte buffer for the
ByteString (and then pass its underlying Ptr Word8 and
ByteCount components to fdPreadBuf), and that we detect EOF
and throw an IOError.

Read data from a specified position in the Fd and convert
it to a ByteString, without altering the position stored
in the Fd. Throws an exception if this is an invalid descriptor,
or EOF has been reached. This is a pread(2) based version of
fdReads; see that function for more details.

Writing

The POSIX.1 write(2) syscall

Write a ByteString to an Fd. The return value is the
total number of bytes actually written. This is exactly equivalent
to the POSIX.1 write(2) system call; we just convert the
ByteString into its underlying Ptr Word8 and ByteCount
components for passing to fdWriteBuf.

The total number of bytes written, the number of bytes
written from the first of the remaining strings, the
remaining (unwritten) strings.

Write a sequence of ByteStrings to an Fd. The return
value is a triple of: the total number of bytes written, the
number of bytes written from the first of the remaining strings,
and the remaining (unwritten) strings. We return this triple
instead of a pair adjusting the head of the remaining strings
(i.e., removing the bytes already written) in case there is some
semantic significance to the way the input is split into chunks.

This version consumes the list lazily and will call the write(2)
system call once for each ByteString. This laziness allows the
early parts of the list to be garbage collected and prevents
needing to hold the whole list of ByteStrings in memory at
once. Compare against fdWritev.

The XPG4.2 writev(2) syscall

Write a sequence of ByteStrings to an Fd. The return
value is the total number of bytes written. Unfortunately the
writev(2) system call does not provide enough information to
return the triple that fdWrites does.

This version will force the spine of the list, convert each
ByteString into an iovec, and then call the writev(2)
system call. This means we only make one system call, which
reduces the overhead of performing context switches. But it also
means that we must store the whole list of ByteStrings in
memory at once, and that we must perform some allocation and
conversion. Compare against fdWrites.

The XPG4.2 pwrite(2) syscall

Write data from memory to a specified position in the Fd,
but without altering the position stored in the Fd. This is
exactly equivalent to the XPG4.2 pwrite(2) system call; we
just convert the ByteString into its underlying Ptr Word8
and ByteCount components for passing to fdPwriteBuf.