Merge pull request #8989 from chloekek/std.process.Config.preExecFunction-delegate

Promote `std.process.Config.preExecFunction` to a delegate
This commit is contained in:
Dennis 2024-04-28 23:01:54 +02:00 committed by GitHub
commit 8e6f77231a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 74 additions and 1 deletions

View file

@ -0,0 +1,25 @@
Add `std.process.Config.preExecDelegate`
$(LINK2 $(ROOT_DIR)phobos/std_process.html#.Config.preExecDelegate, `std.process.Config.preExecDelegate`)
is just like
$(LINK2 $(ROOT_DIR)phobos/std_process.html#.Config.preExecFunction, `std.process.Config.preExecFunction`),
but can capture an environment, for example:
-------
import core.sys.linux.sys.prctl : PR_SET_PDEATHSIG, prctl;
import std.process : Config, execute;
void runProgram(int pdeathsig)
{
execute(
["program"],
config: Config(
preExecDelegate: () @trusted =>
prctl(PR_SET_PDEATHSIG, pdeathsig, 0, 0, 0) != -1,
),
);
}
-------
`preExecFunction` is retained for backwards compatibility. If both
`preExecFunction` and `preExecDelegate` are given, both are called.

View file

@ -1102,6 +1102,14 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
}
}
if (config.preExecDelegate !is null)
{
if (config.preExecDelegate() != true)
{
abortOnError(forkPipeOut, InternalError.preExec, .errno);
}
}
// Execute program.
core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
@ -1187,7 +1195,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
errorMsg = "Failed to allocate memory";
break;
case InternalError.preExec:
errorMsg = "Failed to execute preExecFunction";
errorMsg = "Failed to execute preExecFunction or preExecDelegate";
break;
case InternalError.noerror:
assert(false);
@ -1271,6 +1279,29 @@ version (Posix)
assert(received);
}
version (Posix)
@system unittest
{
__gshared int j;
foreach (i; 0 .. 3)
{
auto config = Config(
preExecFunction: function() @trusted {
j = 1;
return true;
},
preExecDelegate: delegate() @trusted {
// j should now be 1, as preExecFunction is called before
// preExecDelegate is.
_Exit(i + j);
return true;
},
);
auto pid = spawnProcess(["false"], config: config);
assert(wait(pid) == i + 1);
}
}
/*
Implementation of spawnProcess() for Windows.
@ -2186,13 +2217,30 @@ struct Config
Please note that the code in this function must only use
async-signal-safe functions.)
If $(LREF preExecDelegate) is also set, it is called last.
On Windows, this member is not available.
*/
bool function() nothrow @nogc @safe preExecFunction;
/**
A delegate that is called before `exec` in $(LREF spawnProcess).
It returns `true` if succeeded and otherwise returns `false`.
$(RED Warning:
Please note that the code in this function must only use
async-signal-safe functions.)
If $(LREF preExecFunction) is also set, it is called first.
On Windows, this member is not available.
*/
bool delegate() nothrow @nogc @safe preExecDelegate;
}
else version (Posix)
{
bool function() nothrow @nogc @safe preExecFunction;
bool delegate() nothrow @nogc @safe preExecDelegate;
}
}