[Issue 24305] New: std.process.execute requires locking passed FILE * handles in order to create the process

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Dec 28 02:58:57 UTC 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 at puremagic.com
          Reporter: schveiguy at 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

--


More information about the Digitalmars-d-bugs mailing list