www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 24305] New: std.process.execute requires locking passed FILE

https://issues.dlang.org/show_bug.cgi?id=24305

          Issue ID: 24305
           Summary: std.process.execute requires locking passed FILE *
                    handles in order to create the process
           Product: D
           Version: D2
          Hardware: All
                OS: Mac OS X
            Status: NEW
          Severity: major
          Priority: P1
         Component: phobos
          Assignee: nobody puremagic.com
          Reporter: schveiguy gmail.com

running std.process.execute on a Mac (at least with ARM probably with all
flavors) requires locking the three passed in file handles *before* forking the
process. This is because `fileno` is a locking operation on MacOS.

This means that e.g. if one thread is executing a `readln`, and a second thread
would like to execute a process where stdin is not redirected, but stdout and
stderr are, then the process execution will hang waiting to acquire the lock on
stdin.

The solution would be either to wait until the fork is executed before managing
the stdin/stdout/stderr redirects, or by maybe checking the handles against the
standard handles to see if they are the same pointer before using `fileno`.

An example which causes the hang is:

```d
void main()
{
    import std.stdio : readln, writeln;
    import std.string : strip;
    import std.process : execute;
    import core.thread;
    bool done = false;
    auto t = new Thread(
      ()
      {
          string getInput() {
              writeln("Please enter something:");
              return readln().strip;
          }
          string line = getInput();
          while (line != "quit")
          {
              writeln("You entered ", line);
              line = getInput();
          }
          done = true;
      });
    t.start();

    while (!done) {
        auto result = ["echo", "Hello World"].execute;
        if (result.status != 0)
            throw new Exception("echo failed");
        writeln(result.output);
    }
    writeln("ByeBye");
}
```

On Linux, this prints Hello World every 1 second, while waiting for input. On
MacOS, this just waits for input, prints the input, and occasionally prints
Hello World. The main thread pauses waiting for the lock of stdin before
executing any processes.

reduced from the test case from the forums:
https://forum.dlang.org/post/um160d$130k$1 digitalmars.com

--
Dec 27 2023