mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 07:56:17 +01:00
gsocket: Use SOCK_NONBLOCK to avoid a fcntl() syscall where possible
If the libc and kernel support `SOCK_NONBLOCK`, we can specify that in the `socket()` flags, and avoid a subsequent call to `fcntl()` to set `O_NONBLOCK`. For modern Linux distributions, this will save a syscall when creating a socket. Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
This commit is contained in:
parent
0be2555704
commit
8b0cf41d88
@ -587,7 +587,38 @@ g_socket_details_from_fd (GSocket *socket)
|
|||||||
socket_strerror (errsv));
|
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 nonblocking: %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
|
gint
|
||||||
g_socket (gint domain,
|
g_socket (gint domain,
|
||||||
gint type,
|
gint type,
|
||||||
@ -596,13 +627,13 @@ g_socket (gint domain,
|
|||||||
{
|
{
|
||||||
int fd, errsv;
|
int fd, errsv;
|
||||||
|
|
||||||
#ifdef SOCK_CLOEXEC
|
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
||||||
fd = socket (domain, type | SOCK_CLOEXEC, protocol);
|
fd = socket (domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
|
||||||
errsv = errno;
|
errsv = errno;
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
return fd;
|
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))
|
if (fd < 0 && (errsv == EINVAL || errsv == EPROTOTYPE))
|
||||||
#endif
|
#endif
|
||||||
fd = socket (domain, type, protocol);
|
fd = socket (domain, type, protocol);
|
||||||
@ -644,9 +675,13 @@ g_socket (gint domain,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Ensure the socket is non-blocking. */
|
||||||
|
socket_set_nonblock (fd);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returned socket has SOCK_CLOEXEC | SOCK_NONBLOCK set. */
|
||||||
static gint
|
static gint
|
||||||
g_socket_create_socket (GSocketFamily family,
|
g_socket_create_socket (GSocketFamily family,
|
||||||
GSocketType type,
|
GSocketType type,
|
||||||
@ -696,44 +731,22 @@ g_socket_constructed (GObject *object)
|
|||||||
GSocket *socket = G_SOCKET (object);
|
GSocket *socket = G_SOCKET (object);
|
||||||
|
|
||||||
if (socket->priv->fd >= 0)
|
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 it’s non-blocking */
|
||||||
|
g_socket_details_from_fd (socket);
|
||||||
|
socket_set_nonblock (socket->priv->fd);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
/* create the fd from socket->priv info */
|
{
|
||||||
socket->priv->fd = g_socket_create_socket (socket->priv->family,
|
/* create the fd from socket->priv info; this sets it non-blocking by construction */
|
||||||
socket->priv->type,
|
socket->priv->fd = g_socket_create_socket (socket->priv->family,
|
||||||
socket->priv->protocol,
|
socket->priv->type,
|
||||||
&socket->priv->construct_error);
|
socket->priv->protocol,
|
||||||
|
&socket->priv->construct_error);
|
||||||
|
}
|
||||||
|
|
||||||
if (socket->priv->fd != -1)
|
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
|
#ifdef SO_NOSIGPIPE
|
||||||
/* See note about SIGPIPE below. */
|
/* See note about SIGPIPE below. */
|
||||||
g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL);
|
g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user