[Mono-list] Questions on Mono.Unix.Pipes

Jonathan Pryor jonpryor at vt.edu
Tue Dec 18 03:13:15 UTC 2012


On Dec 17, 2012, at 12:05 PM, mickeyf <mickey at thesweetoasis.com> wrote:
> I have been using this with some success, but I am relatively new to Linux, and the mono documentation that I have found is missing or incomplete.

Is it?

	http://docs.go-mono.com/?link=T%3aMono.Unix.UnixPipes
	http://docs.go-mono.com/?link=M%3aMono.Unix.UnixPipes.CreatePipes()
	http://docs.go-mono.com/?link=T%3aMono.Unix.UnixStream

Granted, there aren't any unit tests or "full" examples using it, but there's certainly documentation... Of course, there's always source:

	https://github.com/mono/mono/blob/master/mcs/class/Mono.Posix/Mono.Unix/UnixPipes.cs

> The Linux manual pages docs on pipes are clearly referring to a different animal than this.

UnixPipes wraps the "pipe" construct documented in the pipe(2) man page. pipe(2) opens a pair of file descriptors for reading and writing; UnixPipes.CreatePipes() calls pipe(2), wraps the reading file descriptor in the UnixPipes.Reading field, and wraps the writing file descriptor in the UnixPipes.Writing field.

> It appears that I can read a pipe as mypipes.readend.Read(buffer_to_read_to, read_position, bytes_to_read).

Correct. However, you may be misinterpreting "read_position"; "read_position" is the offset within buffer_to_read_to at which to start writing bytes_to_read bytes worth of data. It does _not_ imply any form of seeking at all.

For example, given:

	byte[] buffer = new byte [3];
	stream.Read (buffer, 1, 2);

After `stream.Read()`, buffer[0] will always be 0x00, because it will never have been written to. The `1` specifies the position within `buffer` to start writing, that's all, and has nothing to do with the underlying Stream.

See also:

	http://msdn.microsoft.com/en-us/library/system.io.stream.read.aspx
> offset
> Type: System.Int32
> The zero-based byte offset in buffer at which to begin storing the data read from the current stream.

> I understand that I can't actually fseek using read_position,

You're dealing with pipes; you want POSIX functions, not libc functions. (Granted, in C-land you could use fdopen(3), then use fseek(3)...) Consequently, the appropriate seek function is lseek(2), which errors out with ESPIPE when  using pipes:

	[ESPIPE] Fildes is associated with a pipe, socket, or FIFO. 

No seeking on pipes. It's POSIX.

> but it seems that if I do not read the entire bytes_to_read, I can then continue to adjust read_position to read the remaining data.

I believe you're misunderstanding the `offset` parameter in the Stream.Read(buffer, offset, count) method.

> 2) Since I can't find documentation specific to this, it's not clear what the return values from Read will be when I can't actually read anything.

UnixStream needs to conform to the System.IO.Stream contract, which MSDN documents:

	http://msdn.microsoft.com/en-us/library/system.io.stream.read.aspx
> Return Value
> Type: System.Int32
> The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.


> Does -1 indicate error, or simply "no data available"? What about 0?

-1 should not be returned, ever. (If read(2) returns -1, UnixStream.Read() translates that into an exception.) If 0 is returned, then End-Of-Stream has been reached. If "no data is available", the Read() method will _block_ until data is available.

> 3) Can I set the write end to disable O_NONBLOCK,

Syscall.fcntl() can be used to set O_NONBLOCK.

> and does this guarantee that both the write and the read are atomic and that all bytes will in fact be read in a single read on the read end of the pipe?

As far as I am aware, _nothing_ can guarantee that. I could be wrong.

> Or, since what I really want to do is guarantee that a entire (privately defined) data packet as written by my C library code is read by my mono app, perhaps there is an entirely different, and better way to do this? Sockets?

As far as I am aware, no Stream-like API will support this, including sockets. Data structure "boundaries" need to be dealt with at a higher level, e.g. having a "protocol" that sends a length "packet" before sending the data. This would allow the reader to read (and block reading, or read until it has read) ~4 bytes, examine the length, and then read the specified amount of data.

 - Jon



More information about the Mono-list mailing list