<div dir="ltr"><div dir="ltr"><div><div>Hi, I'm poking through the pieces of the System.Core/System.IO.Pipes code looking to build out anonymous pipes. I have at least a basic working Unix implementation now. Though i imagine Win32 and Named pipes have been broken (if they ever worked) in the process, and there is undoubtedly some cleanup work required. I'd like to get some feedback from people more knowledgeable than myself about mono at this point so i can try and wrap this project up into a pull request.<br>
<br>My initial test case is this example from MSDN: <a href="http://msdn.microsoft.com/en-us/library/bb546102.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/bb546102.aspx</a><br>

<br></div><div>Handle Inheritance<br>-------------------------<br></div><div>Presently, Process.Start() arbitrarily closes all handles
 in the fork()'d process, except stdin / stdout / stderr. There exists a
 todo comment in this same code (io-layer/processes.c) pointing out that
 (when inherit_handles is TRUE, which it is) that something should be 
done differently than when not...<br>

<br><pre><div>                <span>if</span> <span>(</span><span><i>inherit_handles</i></span> <span>!=</span> <span>TRUE</span><span>)</span> <span>{</span></div>
</pre>
        <pre><div>                  <span>/* FIXME: do something here */</span>
</div></pre>
        <pre><div>          <span>}</span>
</div></pre><br>Without a far more expansive knowledge of mono i can't 
make a very well informed decision about the liberties i can take in addressing this. <br>The cleanest solution might be to use FD_CLOEXEC on all the existing fd's and (at least in process.Start case) the handles that should be cleaned up would be closed automatically / inherited automatically. Are there compatibility reasons this cannot be done? Has there been any consideration for this that could be drawn upon?<br>
>From information i do have, it seems like these pipe handles could also be flagged as 'inheritable' in the internal handle registry and then after fork() mono could leave those
 open, while closing everything else.<br><br></div><div>In addition to this basic test case, i'm not currently aware of how anonymous pipes should behave when you invoke Process.Start() several times with an anonymous pipe. Without using FD_CLOEXEC it would be difficult and messy to (in a 'execd' child process) to identify all the pipe handles at startup and register them in the mono handle registry as inheritable again (so that Process.Start in that child process would pass these handles on again to its children). If anonymous pipes are supposed to support this, it lends further support for the FD_CLOEXEC solution.<br>
</div><div>

<br>API Methods Difficult To Implement In Unix<br>-------------------------<br>There doesn't seem to be a clear specification for the anonymous pipe feature and i've so far had to make some little assumptions / inferences based on the documentation on MSDN. That said, the posix anonymous pipe standard lacks a few features which are pertinent to the API for anonymous pipe streams. In particular there are two conflicting features:<br>
<br>     * <a href="http://msdn.microsoft.com/en-us/library/system.io.pipes.pipestream.waitforpipedrain.aspx">WaitForPipeDrain</a>() defined on the AnonymousPipeStream requires some ability to peak into an anonymous pipe and wait for the pipe's buffer to become empty<br>
</div><div>     * Write / Read / etc... is supposed to throw an IOException if the other end of the pipe stream has been closed (i have interpreted the wording 'pipe is broken' from the msdn docs to mean this, although there is a chance i am mis-interpreting this too)<br>
<br></div><div>These two features conflict when trying to implement them in unix through minor hacks / workarounds. <br><br>I can implement WaitForPipeDrain() by leaving the read end of the pipe handle open in the writer process, and calling poll(3) on the read end repeatedly until the POLL_IN flag is gone.<br>
<br></div><div>I can detect that the pipe is broken by closing the read end on the writer, (and the write end on the reader) and calling poll(3), throwing this "pipe broken" error when a POLLERR /. POLLHUP is issued. One of these two flags will be set if all handles to the other end of the pipe have been closed.<br>
<br></div><div>In order to implement both of these conflicting features i actually need to create two pipes (one where i can leave the read end open on the writer process, and one where i can close it). This is not very nice in the case that system resources might be at a premium, however i haven't been able to devise any other way to get both features either. Would there be any major objection to implementing it like this (which as i have noted seems to be the only way)?<br>
<br></div><div>Using two separate pipes like this, the GetClientHandleAsString() method is going to be significantly different from the win32 version. When the client is supposed to be the writer, the client handle as string must contain three separate fds. When the client is the reader two fd's must be passed. I don't see any reason that this would bother anybody, but if it's relevant let me know!<br>
<br></div><div>Compatibility<br>-------------------------<br></div><div>I can create pipes and manipulate them without adding any new library references but i do depend on using the poll(3) function more heavily than it seems to be presently (it's only exposed for Network Sockets presently). Are there any portability / compatibility considerations with poll(3) that might need to be addressed?<br>
<br></div><div>Versioning<br>-------------------------<br></div><div>I'm not familiar with how versioning between .NET 1/2/3/etc... is being handled. Anonymous pipes are introduced in .NET 3.5. Do these classes need to be hidden to older versions, etc... Maybe there is a wiki page i haven't found discussing some of this?<br>
<br></div><div>I have added several new internal calls to the MonoIO utility, specifically for poll(3) and pipe handle manipulation. Does adding internal calls require any versioning considerations?<br></div><div><br>Testing<br>
-------------------------<br></div><div>In order to write a test suite for anonymous pipes i need to start new processes and i will need to use some sort of IPC mechanism to communicate certain errors back to the test process. This seems like a rather unique challenge compared to most of the testing needed for mono.<br>
<br></div><div>Has any of this multi-process unit testing been done before in mono, or are there any considerations that might be relevant?<br><br></div></div></div></div>