From ed37970a0405b5681bcd6449d4dc1b4f9080c4fa Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 3 May 2011 09:52:10 -0400 Subject: [PATCH] g_unix_set_fd_nonblocking: New API to control file descriptor blocking state And use it in relevant places in GLib. https://bugzilla.gnome.org/show_bug.cgi?id=649225 --- gio/gcancellable.c | 27 +++++-------------------- gio/gsocket.c | 17 ++++++++-------- glib/glib-unix.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ glib/glib-unix.h | 4 ++++ glib/glib.symbols | 1 + glib/gmain.c | 2 +- 6 files changed, 69 insertions(+), 32 deletions(-) diff --git a/gio/gcancellable.c b/gio/gcancellable.c index c37baff51..32f508118 100644 --- a/gio/gcancellable.c +++ b/gio/gcancellable.c @@ -21,11 +21,10 @@ */ #include "config.h" -#ifdef HAVE_UNISTD_H -#include +#include "glib.h" +#ifdef G_OS_UNIX +#include "glib-unix.h" #endif -#include -#include #include #ifdef G_OS_WIN32 #include @@ -193,22 +192,6 @@ g_cancellable_class_init (GCancellableClass *klass) } #ifndef G_OS_WIN32 -static void -set_fd_nonblocking (int fd) -{ -#ifdef F_GETFL - glong fcntl_flags; - fcntl_flags = fcntl (fd, F_GETFL); - -#ifdef O_NONBLOCK - fcntl_flags |= O_NONBLOCK; -#else - fcntl_flags |= O_NDELAY; -#endif - - fcntl (fd, F_SETFL, fcntl_flags); -#endif -} static void set_fd_close_exec (int fd) @@ -235,8 +218,8 @@ g_cancellable_open_pipe (GCancellable *cancellable) /* Make them nonblocking, just to be sure we don't block * on errors and stuff */ - set_fd_nonblocking (priv->cancel_pipe[0]); - set_fd_nonblocking (priv->cancel_pipe[1]); + g_unix_set_fd_nonblocking (priv->cancel_pipe[0], TRUE, NULL); + g_unix_set_fd_nonblocking (priv->cancel_pipe[1], TRUE, NULL); set_fd_close_exec (priv->cancel_pipe[0]); set_fd_close_exec (priv->cancel_pipe[1]); diff --git a/gio/gsocket.c b/gio/gsocket.c index d0219c111..4b5f18a28 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -29,6 +29,10 @@ #include "gsocket.h" +#ifdef G_OS_UNIX +#include "glib-unix.h" +#endif + #include #include #include @@ -240,22 +244,17 @@ static void set_fd_nonblocking (int fd) { #ifndef G_OS_WIN32 - glong arg; + GError *error = NULL; #else gulong arg; #endif #ifndef G_OS_WIN32 - if ((arg = fcntl (fd, F_GETFL, NULL)) < 0) + if (!g_unix_set_fd_nonblocking (fd, TRUE, &error)) { - g_warning ("Error getting socket status flags: %s", socket_strerror (errno)); - arg = 0; + g_warning ("Error setting socket nonblocking: %s", error->message); + g_clear_error (&error); } - - arg = arg | O_NONBLOCK; - - if (fcntl (fd, F_SETFL, arg) < 0) - g_warning ("Error setting socket status flags: %s", socket_strerror (errno)); #else arg = TRUE; diff --git a/glib/glib-unix.c b/glib/glib-unix.c index cf4748bd5..5a0f7f777 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -135,6 +135,56 @@ g_unix_pipe_flags (int *fds, return TRUE; } +/** + * g_unix_set_fd_nonblocking: + * @fd: A file descriptor + * @nonblock: If %TRUE, set the descriptor to be non-blocking + * @error: a #GError + * + * Control the non-blocking state of the given file descriptor, + * according to @nonblock. On most systems this uses %O_NONBLOCK, but + * on some older ones may use %O_NDELAY. + * + * Returns: %TRUE if successful + */ +gboolean +g_unix_set_fd_nonblocking (gint fd, + gboolean nonblock, + GError **error) +{ +#ifdef F_GETFL + glong fcntl_flags; + fcntl_flags = fcntl (fd, F_GETFL); + + if (fcntl_flags == -1) + return g_unix_set_error_from_errno (error); + + if (nonblock) + { +#ifdef O_NONBLOCK + fcntl_flags |= O_NONBLOCK; +#else + fcntl_flags |= O_NDELAY; +#endif + } + else + { +#ifdef O_NONBLOCK + fcntl_flags &= ~O_NONBLOCK; +#else + fcntl_flags &= ~O_NDELAY; +#endif + } + + if (fcntl (fd, F_SETFL, fcntl_flags) == -1) + return g_unix_set_error_from_errno (error); + return TRUE; +#else + return g_unix_set_error_from_errno_saved (error, EINVAL); +#endif +} + + /** * g_unix_signal_source_new: * @signum: A signal number diff --git a/glib/glib-unix.h b/glib/glib-unix.h index 55aaf25ec..de38c542a 100644 --- a/glib/glib-unix.h +++ b/glib/glib-unix.h @@ -61,6 +61,10 @@ gboolean g_unix_pipe_flags (int *fds, int flags, GError **error); +gboolean g_unix_set_fd_nonblocking (gint fd, + gboolean nonblock, + GError **error); + GSource *g_unix_signal_source_new (int signum); guint g_unix_signal_add_watch_full (int signum, diff --git a/glib/glib.symbols b/glib/glib.symbols index bc1c32395..12b743020 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1983,6 +1983,7 @@ g_hostname_to_unicode #ifdef G_OS_UNIX g_unix_pipe_flags g_unix_error_quark +g_unix_set_fd_nonblocking g_unix_signal_source_new g_unix_signal_add_watch_full #endif diff --git a/glib/gmain.c b/glib/gmain.c index f31405aa8..efcdcc3c9 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -4638,7 +4638,7 @@ init_unix_signal_wakeup_state_unlocked (void) if (!g_unix_pipe_flags (unix_signal_wake_up_pipe, FD_CLOEXEC, &error)) g_error ("Cannot create UNIX signal wake up pipe: %s\n", error->message); - fcntl (unix_signal_wake_up_pipe[1], F_SETFL, O_NONBLOCK | fcntl (unix_signal_wake_up_pipe[1], F_GETFL)); + g_unix_set_fd_nonblocking (unix_signal_wake_up_pipe[1], TRUE, NULL); /* We create a helper thread that polls on the wakeup pipe indefinitely */ if (g_thread_create (unix_signal_helper_thread, NULL, FALSE, &error) == NULL)