December 28, 2023
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

--