1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-04-18 09:46:33 +02:00

split: prefer posix_spawn to fork and execl

* NEWS: Mention the change.
* bootstrap.conf (gnulib_modules): Add posix_spawn,
posix_spawnattr_setsigdefault, posix_spawn_file_actions_addclose,
posix_spawn_file_actions_adddup2, and posix_spawn_file_actions_init.
* src/split.c: Include spawn.h.
(create): Use posix_spawn instead of fork and execl.
This commit is contained in:
Collin Funk
2025-10-23 01:11:50 -07:00
parent 1dabab7027
commit ca8b928665
3 changed files with 65 additions and 37 deletions

3
NEWS
View File

@@ -54,6 +54,9 @@ GNU coreutils NEWS -*- outline -*-
- supports a multi-byte --delimiter character
- no longer processes input indefinitely in the presence of write errors
'split' now uses posix_spawn() to invoke the shell command specified by
--filter more efficiently.
wc -l now operates 10% faster on hosts that support AVX512 instructions.

View File

@@ -213,9 +213,14 @@ gnulib_modules="
pipe-posix
pipe2
posix-shell
posix_spawn
posix_spawnattr_destroy
posix_spawnattr_init
posix_spawnattr_setflags
posix_spawnattr_setsigdefault
posix_spawn_file_actions_addclose
posix_spawn_file_actions_adddup2
posix_spawn_file_actions_init
posix_spawnp
posixtm
posixver

View File

@@ -27,6 +27,7 @@
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <spawn.h>
#include "system.h"
#include "alignalloc.h"
@@ -497,50 +498,69 @@ create (char const *name)
}
else
{
int fd_pair[2];
pid_t child_pid;
char const *shell_prog = getenv ("SHELL");
if (shell_prog == nullptr)
shell_prog = "/bin/sh";
if (setenv ("FILE", name, 1) != 0)
error (EXIT_FAILURE, errno,
_("failed to set FILE environment variable"));
if (verbose)
fprintf (stdout, _("executing with FILE=%s\n"), quotef (name));
int result;
int fd_pair[2];
pid_t child_pid;
posix_spawnattr_t attr;
posix_spawn_file_actions_t actions;
sigset_t set;
sigemptyset (&set);
if (default_SIGPIPE)
sigaddset (&set, SIGPIPE);
if ( (result = posix_spawnattr_init (&attr))
|| (result = posix_spawnattr_setflags (&attr,
(POSIX_SPAWN_USEVFORK
| POSIX_SPAWN_SETSIGDEF)))
|| (result = posix_spawnattr_setsigdefault (&attr, &set))
|| (result = posix_spawn_file_actions_init (&actions))
)
error (EXIT_FAILURE, result, _("posix_spawn initialization failed"));
if (pipe (fd_pair) != 0)
error (EXIT_FAILURE, errno, _("failed to create pipe"));
child_pid = fork ();
if (child_pid == 0)
{
/* This is the child process. If an error occurs here, the
parent will eventually learn about it after doing a wait,
at which time it will emit its own error message. */
int j;
/* We have to close any pipes that were opened during an
earlier call, otherwise this process will be holding a
write-pipe that will prevent the earlier process from
reading an EOF on the corresponding read-pipe. */
for (j = 0; j < n_open_pipes; ++j)
if (close (open_pipes[j]) != 0)
error (EXIT_FAILURE, errno, _("closing prior pipe"));
if (close (fd_pair[1]))
error (EXIT_FAILURE, errno, _("closing output pipe"));
if (fd_pair[0] != STDIN_FILENO)
{
if (dup2 (fd_pair[0], STDIN_FILENO) != STDIN_FILENO)
error (EXIT_FAILURE, errno, _("moving input pipe"));
if (close (fd_pair[0]) != 0)
error (EXIT_FAILURE, errno, _("closing input pipe"));
}
if (default_SIGPIPE)
signal (SIGPIPE, SIG_DFL);
execl (shell_prog, last_component (shell_prog), "-c",
filter_command, (char *) nullptr);
error (EXIT_FAILURE, errno, _("failed to run command: \"%s -c %s\""),
shell_prog, filter_command);
}
if (child_pid < 0)
error (EXIT_FAILURE, errno, _("fork system call failed"));
/* We have to close any pipes that were opened during an
earlier call, otherwise this process will be holding a
write-pipe that will prevent the earlier process from
reading an EOF on the corresponding read-pipe. */
for (int i = 0; i < n_open_pipes; ++i)
if ((result = posix_spawn_file_actions_addclose (&actions,
open_pipes[i])))
break;
if ( result
|| (result = posix_spawn_file_actions_addclose (&actions, fd_pair[1]))
|| (fd_pair[0] != STDIN_FILENO
&& ( (result = posix_spawn_file_actions_adddup2 (&actions,
fd_pair[0],
STDIN_FILENO))
|| (result = posix_spawn_file_actions_addclose (&actions,
fd_pair[0]))))
)
error (EXIT_FAILURE, result, _("posix_spawn setup failed"));
char const *shell_prog = getenv ("SHELL");
if (shell_prog == nullptr)
shell_prog = "/bin/sh";
char const *const argv[] = { last_component (shell_prog), "-c",
filter_command, nullptr };
result = posix_spawn (&child_pid, shell_prog, &actions, &attr,
(char * const *) argv, environ);
if (result != 0)
error (EXIT_FAILURE, errno, _("failed to run command: \"%s -c %s\""),
shell_prog, filter_command);
if (close (fd_pair[0]) != 0)
error (EXIT_FAILURE, errno, _("failed to close input pipe"));
filter_pid = child_pid;