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:
3
NEWS
3
NEWS
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
94
src/split.c
94
src/split.c
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user