glib-unix: Add O_NONBLOCK support to g_unix_open_pipe()

Add support for it, but don’t use it anywhere yet — this is an API
addition, but currently doesn’t cause any functional changes. It’ll be
used in the next commit.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
This commit is contained in:
Philip Withnall 2023-03-23 00:55:00 +00:00
parent 56c013cb6e
commit 5c65437d73
4 changed files with 60 additions and 24 deletions

View File

@ -249,7 +249,7 @@ watcher_init (void)
gint pipe_fds[2]; gint pipe_fds[2];
/* fork a child to clean up when we are killed */ /* fork a child to clean up when we are killed */
if (!g_unix_open_pipe_internal (pipe_fds, TRUE)) if (!g_unix_open_pipe_internal (pipe_fds, TRUE, FALSE))
{ {
errsv = errno; errsv = errno;
g_warning ("pipe() failed: %s", g_strerror (errsv)); g_warning ("pipe() failed: %s", g_strerror (errsv));

View File

@ -398,8 +398,8 @@ stack_trace (const char * const *args)
stack_trace_done = FALSE; stack_trace_done = FALSE;
signal (SIGCHLD, stack_trace_sigchld); signal (SIGCHLD, stack_trace_sigchld);
if (!g_unix_open_pipe_internal (in_fd, TRUE) || if (!g_unix_open_pipe_internal (in_fd, TRUE, FALSE) ||
!g_unix_open_pipe_internal (out_fd, TRUE)) !g_unix_open_pipe_internal (out_fd, TRUE, FALSE))
{ {
perror ("unable to open pipe"); perror ("unable to open pipe");
_exit (0); _exit (0);

View File

@ -74,11 +74,16 @@ g_unix_set_error_from_errno (GError **error,
* *
* Similar to the UNIX pipe() call, but on modern systems like Linux * Similar to the UNIX pipe() call, but on modern systems like Linux
* uses the pipe2() system call, which atomically creates a pipe with * uses the pipe2() system call, which atomically creates a pipe with
* the configured flags. The only supported flag currently is * the configured flags.
* %FD_CLOEXEC. If for example you want to configure %O_NONBLOCK, that
* must still be done separately with fcntl().
* *
* This function does not take %O_CLOEXEC, it takes %FD_CLOEXEC as if * As of GLib 2.78, the supported flags are `FD_CLOEXEC` and `O_NONBLOCK`. Prior
* to GLib 2.78, only `FD_CLOEXEC` was supported if you wanted to configure
* `O_NONBLOCK` then that had to be done separately with `fcntl()`.
*
* It is a programmer error to call this function with unsupported flags, and a
* critical warning will be raised.
*
* This function does not take `O_CLOEXEC`, it takes `FD_CLOEXEC` as if
* for fcntl(); these are different on Linux/glibc. * for fcntl(); these are different on Linux/glibc.
* *
* Returns: %TRUE on success, %FALSE if not (and errno will be set). * Returns: %TRUE on success, %FALSE if not (and errno will be set).
@ -90,11 +95,12 @@ g_unix_open_pipe (int *fds,
int flags, int flags,
GError **error) GError **error)
{ {
/* We only support FD_CLOEXEC */ /* We only support FD_CLOEXEC and O_NONBLOCK */
g_return_val_if_fail ((flags & (FD_CLOEXEC)) == flags, FALSE); g_return_val_if_fail ((flags & (FD_CLOEXEC | O_NONBLOCK)) == flags, FALSE);
if (!g_unix_open_pipe_internal (fds, if (!g_unix_open_pipe_internal (fds,
(flags & FD_CLOEXEC) != 0)) (flags & FD_CLOEXEC) != 0,
(flags & O_NONBLOCK) != 0))
return g_unix_set_error_from_errno (error, errno); return g_unix_set_error_from_errno (error, errno);
return TRUE; return TRUE;

View File

@ -41,15 +41,22 @@ G_BEGIN_DECLS
static inline gboolean static inline gboolean
g_unix_open_pipe_internal (int *fds, g_unix_open_pipe_internal (int *fds,
gboolean close_on_exec) gboolean close_on_exec,
gboolean nonblock)
{ {
#ifdef HAVE_PIPE2 #ifdef HAVE_PIPE2
do do
{ {
int ecode; int ecode;
int flags = 0;
if (close_on_exec)
flags |= O_CLOEXEC;
if (nonblock)
flags |= O_NONBLOCK;
/* Atomic */ /* Atomic */
ecode = pipe2 (fds, close_on_exec ? O_CLOEXEC : 0); ecode = pipe2 (fds, flags);
if (ecode == -1 && errno != ENOSYS) if (ecode == -1 && errno != ENOSYS)
return FALSE; return FALSE;
else if (ecode == 0) else if (ecode == 0)
@ -62,21 +69,44 @@ g_unix_open_pipe_internal (int *fds,
if (pipe (fds) == -1) if (pipe (fds) == -1)
return FALSE; return FALSE;
if (!close_on_exec) if (close_on_exec)
return TRUE;
if (fcntl (fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
fcntl (fds[1], F_SETFD, FD_CLOEXEC) == -1)
{ {
int saved_errno = errno; if (fcntl (fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
fcntl (fds[1], F_SETFD, FD_CLOEXEC) == -1)
{
int saved_errno = errno;
close (fds[0]); close (fds[0]);
close (fds[1]); close (fds[1]);
fds[0] = -1; fds[0] = -1;
fds[1] = -1; fds[1] = -1;
errno = saved_errno; errno = saved_errno;
return FALSE; return FALSE;
}
}
if (nonblock)
{
#ifdef O_NONBLOCK
int flags = O_NONBLOCK;
#else
int flags = O_NDELAY;
#endif
if (fcntl (fds[0], F_SETFL, flags) == -1 ||
fcntl (fds[1], F_SETFL, flags) == -1)
{
int saved_errno = errno;
close (fds[0]);
close (fds[1]);
fds[0] = -1;
fds[1] = -1;
errno = saved_errno;
return FALSE;
}
} }
return TRUE; return TRUE;