aboutsummaryrefslogtreecommitdiffstats
path: root/src/callproc.c
diff options
context:
space:
mode:
authorPhilipp Stephani2020-12-26 12:20:51 +0100
committerPhilipp Stephani2020-12-26 12:20:51 +0100
commite24f15c562e39f051dc963f9b3744b9a12b4c839 (patch)
tree9cae1005f6aaf3931c38f6e8be4049de13cf3e60 /src/callproc.c
parent3497c02d936ccb99fd61daf4409343d13cc88630 (diff)
downloademacs-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.c148
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
1228emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err, 1229emacs_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 ();