Skip to content

Commit 8e6f772

Browse files
authored
Merge pull request #8989 from chloekek/std.process.Config.preExecFunction-delegate
Promote `std.process.Config.preExecFunction` to a delegate
2 parents 54eb95c + 7a280a9 commit 8e6f772

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Add `std.process.Config.preExecDelegate`
2+
3+
$(LINK2 $(ROOT_DIR)phobos/std_process.html#.Config.preExecDelegate, `std.process.Config.preExecDelegate`)
4+
is just like
5+
$(LINK2 $(ROOT_DIR)phobos/std_process.html#.Config.preExecFunction, `std.process.Config.preExecFunction`),
6+
but can capture an environment, for example:
7+
8+
-------
9+
import core.sys.linux.sys.prctl : PR_SET_PDEATHSIG, prctl;
10+
import std.process : Config, execute;
11+
12+
void runProgram(int pdeathsig)
13+
{
14+
execute(
15+
["program"],
16+
config: Config(
17+
preExecDelegate: () @trusted =>
18+
prctl(PR_SET_PDEATHSIG, pdeathsig, 0, 0, 0) != -1,
19+
),
20+
);
21+
}
22+
-------
23+
24+
`preExecFunction` is retained for backwards compatibility. If both
25+
`preExecFunction` and `preExecDelegate` are given, both are called.

std/process.d

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,14 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
11021102
}
11031103
}
11041104

1105+
if (config.preExecDelegate !is null)
1106+
{
1107+
if (config.preExecDelegate() != true)
1108+
{
1109+
abortOnError(forkPipeOut, InternalError.preExec, .errno);
1110+
}
1111+
}
1112+
11051113
// Execute program.
11061114
core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
11071115

@@ -1187,7 +1195,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
11871195
errorMsg = "Failed to allocate memory";
11881196
break;
11891197
case InternalError.preExec:
1190-
errorMsg = "Failed to execute preExecFunction";
1198+
errorMsg = "Failed to execute preExecFunction or preExecDelegate";
11911199
break;
11921200
case InternalError.noerror:
11931201
assert(false);
@@ -1271,6 +1279,29 @@ version (Posix)
12711279
assert(received);
12721280
}
12731281

1282+
version (Posix)
1283+
@system unittest
1284+
{
1285+
__gshared int j;
1286+
foreach (i; 0 .. 3)
1287+
{
1288+
auto config = Config(
1289+
preExecFunction: function() @trusted {
1290+
j = 1;
1291+
return true;
1292+
},
1293+
preExecDelegate: delegate() @trusted {
1294+
// j should now be 1, as preExecFunction is called before
1295+
// preExecDelegate is.
1296+
_Exit(i + j);
1297+
return true;
1298+
},
1299+
);
1300+
auto pid = spawnProcess(["false"], config: config);
1301+
assert(wait(pid) == i + 1);
1302+
}
1303+
}
1304+
12741305
/*
12751306
Implementation of spawnProcess() for Windows.
12761307
@@ -2186,13 +2217,30 @@ struct Config
21862217
Please note that the code in this function must only use
21872218
async-signal-safe functions.)
21882219
2220+
If $(LREF preExecDelegate) is also set, it is called last.
2221+
21892222
On Windows, this member is not available.
21902223
*/
21912224
bool function() nothrow @nogc @safe preExecFunction;
2225+
2226+
/**
2227+
A delegate that is called before `exec` in $(LREF spawnProcess).
2228+
It returns `true` if succeeded and otherwise returns `false`.
2229+
2230+
$(RED Warning:
2231+
Please note that the code in this function must only use
2232+
async-signal-safe functions.)
2233+
2234+
If $(LREF preExecFunction) is also set, it is called first.
2235+
2236+
On Windows, this member is not available.
2237+
*/
2238+
bool delegate() nothrow @nogc @safe preExecDelegate;
21922239
}
21932240
else version (Posix)
21942241
{
21952242
bool function() nothrow @nogc @safe preExecFunction;
2243+
bool delegate() nothrow @nogc @safe preExecDelegate;
21962244
}
21972245
}
21982246

0 commit comments

Comments
 (0)