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 | |
| 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.
| -rw-r--r-- | src/Makefile.in | 4 | ||||
| -rw-r--r-- | src/callproc.c | 148 |
2 files changed, 150 insertions, 2 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 19304cca040..06922379412 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -239,6 +239,8 @@ LCMS2_CFLAGS = @LCMS2_CFLAGS@ | |||
| 239 | 239 | ||
| 240 | LIBZ = @LIBZ@ | 240 | LIBZ = @LIBZ@ |
| 241 | 241 | ||
| 242 | LIB_POSIX_SPAWN = @LIB_POSIX_SPAWN@ | ||
| 243 | |||
| 242 | ## system-specific libs for dynamic modules, else empty | 244 | ## system-specific libs for dynamic modules, else empty |
| 243 | LIBMODULES = @LIBMODULES@ | 245 | LIBMODULES = @LIBMODULES@ |
| 244 | ## dynlib.o emacs-module.o if modules enabled, else empty | 246 | ## dynlib.o emacs-module.o if modules enabled, else empty |
| @@ -535,7 +537,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \ | |||
| 535 | $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ | 537 | $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ |
| 536 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ | 538 | $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LCMS2_LIBS) \ |
| 537 | $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ | 539 | $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ |
| 538 | $(JSON_LIBS) $(LIBGMP) | 540 | $(JSON_LIBS) $(LIBGMP) $(LIB_POSIX_SPAWN) |
| 539 | 541 | ||
| 540 | ## FORCE it so that admin/unidata can decide whether this file is | 542 | ## FORCE it so that admin/unidata can decide whether this file is |
| 541 | ## up-to-date. Although since charprop depends on bootstrap-emacs, | 543 | ## up-to-date. Although since charprop depends on bootstrap-emacs, |
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 (); |