The new std.process is ready for review

Steven Schveighoffer schveiguy at yahoo.com
Mon Mar 11 10:54:05 PDT 2013


On Mon, 11 Mar 2013 01:24:17 -0400, Marco Leise <Marco.Leise at gmx.de> wrote:

> Am Sun, 10 Mar 2013 21:10:24 -0400
> schrieb "Steven Schveighoffer" <schveiguy at yahoo.com>:
>
>> I think we can find a mix.  Since fork gives you a convenient location  
>> to
>> close all open file descriptors, we should do so by default.  But if you
>> want standard posix behavior and you want to rely on F_CLOEXEC, you  
>> should
>> be able to do that with a flag to spawnProcess.  We already have a  
>> Config
>> parameter that is already used to control stream closing behavior.  We
>> should extend that.
>>
>> [...]
>>
>> However, I don't agree with your solution.  We should not be  
>> infiltrating
>> std.process hacks into all creation of streams.
>
> I don't see it as introducing std.process hacks everywhere but
> fixing Phobos file handle semantics in a clean way. Just try to
> look at it from that perspective.

Any time you are fixing an OS flaw in user code, it's a hack :)

>> Not only is that
>> difficult to maintain, but it decouples the purpose of code from the
>> actual implementation by quite a bit.
>
> Windows has a flag in both locations as well: When you create
> the (file) handle and when you create a sub process. And a
> common file handle/descriptor property in all OSs is
> whether it is inheritable. Whereas no such common ground
> exists for spawning processes.

What I mean is, this is an issue with spawning child processes.  It  
belongs in a function that spawns child processes.

>> A process may never even spawn a child process,
>
> No harm done in that case.
>
>> or it may call functions that create pipes/threads that
>> DON'T set F_CLOEXEC.  Maybe the 3rd party library didn't get that memo.
>
> Yes and yes. Its not a BUG to do that deliberately and
> cleanly supported by Windows as you can open stuff with
> bInheritHandle set in SECURITY_ATTRIBUTES, duplicating
> that behavior.
>
> Consider these changes of perspective:
>
> * A hardcore Posix fanatic could just as well argue that
>   Windows code forgetting to set bInheritHandle for all opened
>   files is at fault. Since inheritance should be the default.

I don't think that would be a good solution either (setting all handles to  
inherit on Windows).  IMO, D should be as compatible as possible with the  
target OS.  This means:

a) libraries written in other languages which D deals with are not run in  
an environment that is unexpected (e.g. all handles are unexpectedly  
marked CLOEXEC).
b) D's code can run without expecting to have special conditions.

> * You mentioned libs opening file descriptors without Phobos.
>   By the same thinking someone could spawn child processes
>   without Phobos - still inheriting the open descriptors.

With your solution, they would have to open all their handles WITHOUT  
using phobos.  Likely a huge pain.

>> I see no issue with std.process handling the historic flaws in process
>> creation, that is where it belongs IMO.
>
> But it also - as a file handle/descriptor property - belongs
> to creating those.

The property specifically deals with creating processes.  It's not a  
handle property, it's just stored with the handle because it requires one  
flag per handle, and the space is there.

Technically, even Windows has this wrong.  Because they don't give a place  
for you to do the "right thing" per execution of CreateProcess (like fork  
does), it's possible to have a race where you inadvertently inherit  
handles you don't mean to.

example:

thread 1 wants to spawn a process, creates pipes for the standard handles,  
sets the appropriate ends to inheritable
thread 2 wants to spawn a process, creates pipes for the standard handles,  
sets the appropriate ends to inheritable
thread 1 spawns his process, which assigns it's pipes to the standard  
handles, but also it has inherited thread 2's pipes!

This is like Vladimir's problem, but involves a race, so it will only  
happen once in a blue moon!  Unfortunately, we have no recourse for this...

>
>> What's nice about it is, with the "close all open descriptors" method,
>> it handles all these cases quite well.  We should also give the user
>> a "roll your own" option where it doesn't close these descriptors for
>> you, you must set F_CLOEXEC manually.
>
> Assuming this is the compromise - with the Windows code path
> using bInheritHandles for CreateProcess - this still leaves us
> with Phobos creating inheritable handles on Posix and
> non-inheritable ones on Windows. Where it should be opt-in on
> both.

I don't agree.  It should do the default that the OS provides.  Variations  
are available by using OS-specific functions.

> I've placed some example implementations from other languages
> in the other thread...

It's good that there is precedent for your idea.  But I don't agree with  
the design regardless of whether other implementations have done it.

-Steve


More information about the Digitalmars-d mailing list