diff options
| author | Philipp Stephani | 2020-12-26 12:20:51 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2020-12-26 12:20:51 +0100 |
| commit | e24f15c562e39f051dc963f9b3744b9a12b4c839 (patch) | |
| tree | 9cae1005f6aaf3931c38f6e8be4049de13cf3e60 /src/callproc.c | |
| parent | 3497c02d936ccb99fd61daf4409343d13cc88630 (diff) | |
| download | emacs-scratch/posix-spawn.tar.gz emacs-scratch/posix-spawn.zip | |
Revert "Revert "Use posix_spawn if possible.""scratch/posix-spawn
This reverts commit e387371497d313f05b94e3bf42fe6685184605d1.
Diffstat (limited to 'src/callproc.c')
| -rw-r--r-- | src/callproc.c | 148 |
1 files changed, 147 insertions, 1 deletions
diff --git a/src/callproc.c b/src/callproc.c index 3ecd6880274..a5056531e0b 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -27,6 +27,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 27 | 27 | ||
| 28 | #include <sys/file.h> | 28 | #include <sys/file.h> |
| 29 | #include <fcntl.h> | 29 | #include <fcntl.h> |
| 30 | #include <spawn.h> | ||
| 30 | 31 | ||
| 31 | #include "lisp.h" | 32 | #include "lisp.h" |
| 32 | 33 | ||
| @@ -1228,12 +1229,156 @@ int | |||
| 1228 | emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | 1229 | emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, |
| 1229 | char **argv, char **envp, const char *cwd, const char *pty) | 1230 | char **argv, char **envp, const char *cwd, const char *pty) |
| 1230 | { | 1231 | { |
| 1232 | /* `posix_spawn' is available on all Unix systems, either natively | ||
| 1233 | or through Gnulib. Gnulib defines `posix_spawn' on Windows as | ||
| 1234 | well, but doesn't implement it yet. So we fall back to our own | ||
| 1235 | code on Windows. Because Gnulib always defines `posix_spawn', we | ||
| 1236 | don't need to use conditional compilation here. */ | ||
| 1237 | |||
| 1238 | #ifdef DOS_NT | ||
| 1239 | enum { can_use_posix_spawn = false }; | ||
| 1240 | #else | ||
| 1241 | enum { can_use_posix_spawn = true }; | ||
| 1242 | #endif | ||
| 1243 | |||
| 1244 | /* `posix_spawn' doesn't yet support setting up pseudoterminals, so | ||
| 1245 | we fall back to `vfork' if we're supposed to use a | ||
| 1246 | pseudoterminal. */ | ||
| 1247 | |||
| 1248 | bool use_posix_spawn = can_use_posix_spawn && pty == NULL; | ||
| 1249 | |||
| 1250 | posix_spawn_file_actions_t actions; | ||
| 1251 | posix_spawnattr_t attributes; | ||
| 1252 | |||
| 1253 | if (use_posix_spawn) | ||
| 1254 | { | ||
| 1255 | /* Initialize optional attributes before blocking. */ | ||
| 1256 | bool destroy_actions = false; | ||
| 1257 | bool destroy_attributes = false; | ||
| 1258 | |||
| 1259 | int error = posix_spawn_file_actions_init (&actions); | ||
| 1260 | if (error != 0) | ||
| 1261 | goto posix_spawn_init_failed; | ||
| 1262 | destroy_actions = true; | ||
| 1263 | |||
| 1264 | error = posix_spawnattr_init (&attributes); | ||
| 1265 | if (error != 0) | ||
| 1266 | goto posix_spawn_init_failed; | ||
| 1267 | destroy_attributes = true; | ||
| 1268 | |||
| 1269 | error = posix_spawn_file_actions_adddup2 (&actions, std_in, | ||
| 1270 | STDIN_FILENO); | ||
| 1271 | if (error != 0) | ||
| 1272 | goto posix_spawn_init_failed; | ||
| 1273 | |||
| 1274 | error = posix_spawn_file_actions_adddup2 (&actions, std_out, | ||
| 1275 | STDOUT_FILENO); | ||
| 1276 | if (error != 0) | ||
| 1277 | goto posix_spawn_init_failed; | ||
| 1278 | |||
| 1279 | error = posix_spawn_file_actions_adddup2 (&actions, | ||
| 1280 | std_err < 0 ? std_out | ||
| 1281 | : std_err, | ||
| 1282 | STDERR_FILENO); | ||
| 1283 | if (error != 0) | ||
| 1284 | goto posix_spawn_init_failed; | ||
| 1285 | |||
| 1286 | error = posix_spawn_file_actions_addchdir (&actions, cwd); | ||
| 1287 | if (error != 0) | ||
| 1288 | goto posix_spawn_init_failed; | ||
| 1289 | |||
| 1290 | error = posix_spawnattr_setflags (&attributes, | ||
| 1291 | POSIX_SPAWN_SETPGROUP | ||
| 1292 | | POSIX_SPAWN_SETSIGDEF | ||
| 1293 | | POSIX_SPAWN_SETSIGMASK); | ||
| 1294 | if (error != 0) | ||
| 1295 | goto posix_spawn_init_failed; | ||
| 1296 | |||
| 1297 | error = posix_spawnattr_setpgroup (&attributes, 0); | ||
| 1298 | if (error != 0) | ||
| 1299 | goto posix_spawn_init_failed; | ||
| 1300 | |||
| 1301 | sigset_t sigdefault; | ||
| 1302 | sigemptyset (&sigdefault); | ||
| 1303 | |||
| 1304 | #ifdef DARWIN_OS | ||
| 1305 | /* Work around a macOS bug, where SIGCHLD is apparently | ||
| 1306 | delivered to a vforked child instead of to its parent. See: | ||
| 1307 | https://lists.gnu.org/r/emacs-devel/2017-05/msg00342.html | ||
| 1308 | */ | ||
| 1309 | sigaddset (&sigdefault, SIGCHLD); | ||
| 1310 | #endif | ||
| 1311 | |||
| 1312 | sigaddset (&sigdefault, SIGINT); | ||
| 1313 | sigaddset (&sigdefault, SIGQUIT); | ||
| 1314 | #ifdef SIGPROF | ||
| 1315 | sigaddset (&sigdefault, SIGPROF); | ||
| 1316 | #endif | ||
| 1317 | |||
| 1318 | /* Emacs ignores SIGPIPE, but the child should not. */ | ||
| 1319 | sigaddset (&sigdefault, SIGPIPE); | ||
| 1320 | /* Likewise for SIGPROF. */ | ||
| 1321 | #ifdef SIGPROF | ||
| 1322 | sigaddset (&sigdefault, SIGPROF); | ||
| 1323 | #endif | ||
| 1324 | |||
| 1325 | error | ||
| 1326 | = posix_spawnattr_setsigdefault (&attributes, &sigdefault); | ||
| 1327 | if (error != 0) | ||
| 1328 | goto posix_spawn_init_failed; | ||
| 1329 | |||
| 1330 | /* Stop blocking SIGCHLD in the child. */ | ||
| 1331 | sigset_t oldset; | ||
| 1332 | error = pthread_sigmask (SIG_SETMASK, NULL, &oldset); | ||
| 1333 | if (error != 0) | ||
| 1334 | goto posix_spawn_init_failed; | ||
| 1335 | error = posix_spawnattr_setsigmask (&attributes, &oldset); | ||
| 1336 | if (error != 0) | ||
| 1337 | goto posix_spawn_init_failed; | ||
| 1338 | |||
| 1339 | goto next; | ||
| 1340 | |||
| 1341 | posix_spawn_init_failed: | ||
| 1342 | if (destroy_actions) | ||
| 1343 | posix_spawn_file_actions_destroy (&actions); | ||
| 1344 | if (destroy_attributes) | ||
| 1345 | posix_spawnattr_destroy (&attributes); | ||
| 1346 | eassert (0 < error); | ||
| 1347 | return error; | ||
| 1348 | } | ||
| 1349 | |||
| 1231 | sigset_t oldset; | 1350 | sigset_t oldset; |
| 1232 | int pid; | 1351 | int pid; |
| 1352 | int vfork_error; | ||
| 1233 | 1353 | ||
| 1354 | next: | ||
| 1234 | block_input (); | 1355 | block_input (); |
| 1235 | block_child_signal (&oldset); | 1356 | block_child_signal (&oldset); |
| 1236 | 1357 | ||
| 1358 | if (use_posix_spawn) | ||
| 1359 | { | ||
| 1360 | vfork_error = posix_spawn (&pid, argv[0], &actions, &attributes, | ||
| 1361 | argv, envp); | ||
| 1362 | if (vfork_error != 0) | ||
| 1363 | pid = -1; | ||
| 1364 | |||
| 1365 | int error = posix_spawn_file_actions_destroy (&actions); | ||
| 1366 | if (error != 0) | ||
| 1367 | { | ||
| 1368 | errno = error; | ||
| 1369 | emacs_perror ("posix_spawn_file_actions_destroy"); | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | error = posix_spawnattr_destroy (&attributes); | ||
| 1373 | if (error != 0) | ||
| 1374 | { | ||
| 1375 | errno = error; | ||
| 1376 | emacs_perror ("posix_spawnattr_destroy"); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | goto fork_done; | ||
| 1380 | } | ||
| 1381 | |||
| 1237 | #ifndef WINDOWSNT | 1382 | #ifndef WINDOWSNT |
| 1238 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | 1383 | /* vfork, and prevent local vars from being clobbered by the vfork. */ |
| 1239 | pid_t *volatile newpid_volatile = newpid; | 1384 | pid_t *volatile newpid_volatile = newpid; |
| @@ -1375,8 +1520,9 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, | |||
| 1375 | 1520 | ||
| 1376 | /* Back in the parent process. */ | 1521 | /* Back in the parent process. */ |
| 1377 | 1522 | ||
| 1378 | int vfork_error = pid < 0 ? errno : 0; | 1523 | vfork_error = pid < 0 ? errno : 0; |
| 1379 | 1524 | ||
| 1525 | fork_done: | ||
| 1380 | /* Stop blocking in the parent. */ | 1526 | /* Stop blocking in the parent. */ |
| 1381 | unblock_child_signal (&oldset); | 1527 | unblock_child_signal (&oldset); |
| 1382 | unblock_input (); | 1528 | unblock_input (); |