Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote std.process.Config.preExecFunction to a delegate #8989

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions changelog/std.process.Config.preExecDelegate.dd
@@ -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.
50 changes: 49 additions & 1 deletion std/process.d
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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;
}
}

Expand Down