Merge branch 'socket-nonblock' into 'main'

gsocket/inotify/gwakeup: Use SOCK_NONBLOCK and O_NONBLOCK to avoid fcntl() syscalls where possible

See merge request GNOME/glib!3347
This commit is contained in:
Philip Withnall
2023-04-14 15:49:52 +00:00
7 changed files with 123 additions and 67 deletions

View File

@@ -587,7 +587,38 @@ g_socket_details_from_fd (GSocket *socket)
socket_strerror (errsv));
}
/* Wrapper around socket() that is shared with gnetworkmonitornetlink.c */
static void
socket_set_nonblock (int fd)
{
#ifndef G_OS_WIN32
GError *error = NULL;
#else
gulong arg;
#endif
/* Always use native nonblocking sockets, as Windows sets sockets to
* nonblocking automatically in certain operations. This way we make
* things work the same on all platforms.
*/
#ifndef G_OS_WIN32
if (!g_unix_set_fd_nonblocking (fd, TRUE, &error))
{
g_warning ("Error setting socket to nonblocking mode: %s", error->message);
g_clear_error (&error);
}
#else
arg = TRUE;
if (ioctlsocket (fd, FIONBIO, &arg) == SOCKET_ERROR)
{
int errsv = get_socket_errno ();
g_warning ("Error setting socket status flags: %s", socket_strerror (errsv));
}
#endif
}
/* Wrapper around socket() that is shared with gnetworkmonitornetlink.c.
* It always sets SOCK_CLOEXEC | SOCK_NONBLOCK. */
gint
g_socket (gint domain,
gint type,
@@ -596,13 +627,13 @@ g_socket (gint domain,
{
int fd, errsv;
#ifdef SOCK_CLOEXEC
fd = socket (domain, type | SOCK_CLOEXEC, protocol);
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
fd = socket (domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
errsv = errno;
if (fd != -1)
return fd;
/* It's possible that libc has SOCK_CLOEXEC but the kernel does not */
/* It's possible that libc has SOCK_CLOEXEC and/or SOCK_NONBLOCK but the kernel does not */
if (fd < 0 && (errsv == EINVAL || errsv == EPROTOTYPE))
#endif
fd = socket (domain, type, protocol);
@@ -644,9 +675,13 @@ g_socket (gint domain,
}
#endif
/* Ensure the socket is non-blocking. */
socket_set_nonblock (fd);
return fd;
}
/* Returned socket has SOCK_CLOEXEC | SOCK_NONBLOCK set. */
static gint
g_socket_create_socket (GSocketFamily family,
GSocketType type,
@@ -696,44 +731,22 @@ g_socket_constructed (GObject *object)
GSocket *socket = G_SOCKET (object);
if (socket->priv->fd >= 0)
/* create socket->priv info from the fd */
g_socket_details_from_fd (socket);
{
/* create socket->priv info from the fd and ensure its non-blocking */
g_socket_details_from_fd (socket);
socket_set_nonblock (socket->priv->fd);
}
else
/* create the fd from socket->priv info */
socket->priv->fd = g_socket_create_socket (socket->priv->family,
socket->priv->type,
socket->priv->protocol,
&socket->priv->construct_error);
{
/* create the fd from socket->priv info; this sets it non-blocking by construction */
socket->priv->fd = g_socket_create_socket (socket->priv->family,
socket->priv->type,
socket->priv->protocol,
&socket->priv->construct_error);
}
if (socket->priv->fd != -1)
{
#ifndef G_OS_WIN32
GError *error = NULL;
#else
gulong arg;
#endif
/* Always use native nonblocking sockets, as Windows sets sockets to
* nonblocking automatically in certain operations. This way we make
* things work the same on all platforms.
*/
#ifndef G_OS_WIN32
if (!g_unix_set_fd_nonblocking (socket->priv->fd, TRUE, &error))
{
g_warning ("Error setting socket nonblocking: %s", error->message);
g_clear_error (&error);
}
#else
arg = TRUE;
if (ioctlsocket (socket->priv->fd, FIONBIO, &arg) == SOCKET_ERROR)
{
int errsv = get_socket_errno ();
g_warning ("Error setting socket status flags: %s", socket_strerror (errsv));
}
#endif
#ifdef SO_NOSIGPIPE
/* See note about SIGPIPE below. */
g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL);

View File

@@ -249,7 +249,7 @@ watcher_init (void)
gint pipe_fds[2];
/* 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;
g_warning ("pipe() failed: %s", g_strerror (errsv));

View File

@@ -377,6 +377,7 @@ ik_source_new (gboolean (* callback) (ik_event_t *event))
};
InotifyKernelSource *iks;
GSource *source;
gboolean should_set_nonblock = FALSE;
source = g_source_new (&source_funcs, sizeof (InotifyKernelSource));
iks = (InotifyKernelSource *) source;
@@ -384,17 +385,23 @@ ik_source_new (gboolean (* callback) (ik_event_t *event))
g_source_set_static_name (source, "inotify kernel source");
iks->unmatched_moves = g_hash_table_new (NULL, NULL);
iks->fd = inotify_init1 (IN_CLOEXEC);
iks->fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK);
if (iks->fd < 0)
iks->fd = inotify_init ();
{
should_set_nonblock = TRUE;
iks->fd = inotify_init ();
}
if (iks->fd >= 0)
{
GError *error = NULL;
g_unix_set_fd_nonblocking (iks->fd, TRUE, &error);
g_assert_no_error (error);
if (should_set_nonblock)
{
g_unix_set_fd_nonblocking (iks->fd, TRUE, &error);
g_assert_no_error (error);
}
iks->fd_tag = g_source_add_unix_fd (source, iks->fd, G_IO_IN);
}