[glib] gsocket: add g_socket_condition_timed_wait()
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] gsocket: add g_socket_condition_timed_wait()
- Date: Mon, 20 Feb 2012 23:29:54 +0000 (UTC)
commit 726257ab9721acd0699e54194e20e7f53e5a9688
Author: Dan Winship <danw gnome org>
Date: Mon Feb 13 17:20:04 2012 -0500
gsocket: add g_socket_condition_timed_wait()
https://bugzilla.gnome.org/show_bug.cgi?id=667755
docs/reference/gio/gio-sections.txt | 1 +
gio/gio.symbols | 1 +
gio/gsocket.c | 91 +++++++++++++++++++++++++++++-----
gio/gsocket.h | 5 ++
gio/tests/socket.c | 53 ++++++++++++++++++++-
5 files changed, 136 insertions(+), 15 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 71c597b..c9ed66b 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1852,6 +1852,7 @@ g_socket_is_connected
g_socket_create_source
g_socket_condition_check
g_socket_condition_wait
+g_socket_condition_timed_wait
g_socket_get_available_bytes
g_socket_set_listen_backlog
g_socket_get_listen_backlog
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 140eaab..9b609c1 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -949,6 +949,7 @@ g_socket_close
g_socket_shutdown
g_socket_condition_check
g_socket_condition_wait
+g_socket_condition_timed_wait
g_socket_connect
g_socket_create_source
g_socket_get_available_bytes
diff --git a/gio/gsocket.c b/gio/gsocket.c
index c6a9137..d46d497 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -3404,6 +3404,8 @@ g_socket_condition_check (GSocket *socket,
* the appropriate value (%G_IO_ERROR_CANCELLED or
* %G_IO_ERROR_TIMED_OUT).
*
+ * See also g_socket_condition_timed_wait().
+ *
* Returns: %TRUE if the condition was met, %FALSE otherwise
*
* Since: 2.22
@@ -3416,17 +3418,69 @@ g_socket_condition_wait (GSocket *socket,
{
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+ return g_socket_condition_timed_wait (socket, condition, -1,
+ cancellable, error);
+}
+
+/**
+ * g_socket_condition_timed_wait:
+ * @socket: a #GSocket
+ * @condition: a #GIOCondition mask to wait for
+ * @timeout: the maximum time (in microseconds) to wait, or -1
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: a #GError pointer, or %NULL
+ *
+ * Waits for up to @timeout microseconds for @condition to become true
+ * on @socket. If the condition is met, %TRUE is returned.
+ *
+ * If @cancellable is cancelled before the condition is met, or if
+ * @timeout (or the socket's #GSocket:timeout) is reached before the
+ * condition is met, then %FALSE is returned and @error, if non-%NULL,
+ * is set to the appropriate value (%G_IO_ERROR_CANCELLED or
+ * %G_IO_ERROR_TIMED_OUT).
+ *
+ * If you don't want a timeout, use g_socket_condition_wait().
+ * (Alternatively, you can pass -1 for @timeout.)
+ *
+ * Note that although @timeout is in microseconds for consistency with
+ * other GLib APIs, this function actually only has millisecond
+ * resolution, and the behavior is undefined if @timeout is not an
+ * exact number of milliseconds.
+ *
+ * Returns: %TRUE if the condition was met, %FALSE otherwise
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_condition_timed_wait (GSocket *socket,
+ GIOCondition condition,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gint64 start_time;
+
+ g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+
if (!check_socket (socket, error))
return FALSE;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
+ if (socket->priv->timeout &&
+ (timeout < 0 || socket->priv->timeout < timeout / G_USEC_PER_SEC))
+ timeout = socket->priv->timeout * 1000;
+ else if (timeout != -1)
+ timeout = timeout / 1000;
+
+ start_time = g_get_monotonic_time ();
+
#ifdef G_OS_WIN32
{
GIOCondition current_condition;
WSAEVENT events[2];
- DWORD res, timeout;
+ DWORD res;
GPollFD cancel_fd;
int num_events;
@@ -3441,16 +3495,14 @@ g_socket_condition_wait (GSocket *socket,
if (g_cancellable_make_pollfd (cancellable, &cancel_fd))
events[num_events++] = (WSAEVENT)cancel_fd.fd;
- if (socket->priv->timeout)
- timeout = socket->priv->timeout * 1000;
- else
+ if (timeout == -1)
timeout = WSA_INFINITE;
current_condition = update_condition (socket);
while ((condition & current_condition) == 0)
{
- res = WSAWaitForMultipleEvents(num_events, events,
- FALSE, timeout, FALSE);
+ res = WSAWaitForMultipleEvents (num_events, events,
+ FALSE, timeout, FALSE);
if (res == WSA_WAIT_FAILED)
{
int errsv = get_socket_errno ();
@@ -3472,6 +3524,13 @@ g_socket_condition_wait (GSocket *socket,
break;
current_condition = update_condition (socket);
+
+ if (timeout != WSA_INFINITE)
+ {
+ timeout -= (g_get_monotonic_time () - start_time) * 1000;
+ if (timeout < 0)
+ timeout = 0;
+ }
}
remove_condition_watch (socket, &condition);
if (num_events > 1)
@@ -3484,7 +3543,6 @@ g_socket_condition_wait (GSocket *socket,
GPollFD poll_fd[2];
gint result;
gint num;
- gint timeout;
poll_fd[0].fd = socket->priv->fd;
poll_fd[0].events = condition;
@@ -3493,14 +3551,19 @@ g_socket_condition_wait (GSocket *socket,
if (g_cancellable_make_pollfd (cancellable, &poll_fd[1]))
num++;
- if (socket->priv->timeout)
- timeout = socket->priv->timeout * 1000;
- else
- timeout = -1;
+ while (TRUE)
+ {
+ result = g_poll (poll_fd, num, timeout);
+ if (result != -1 || errno != EINTR)
+ break;
- do
- result = g_poll (poll_fd, num, timeout);
- while (result == -1 && get_socket_errno () == EINTR);
+ if (timeout != -1)
+ {
+ timeout -= (g_get_monotonic_time () - start_time) * 1000;
+ if (timeout < 0)
+ timeout = 0;
+ }
+ }
if (num > 1)
g_cancellable_release_fd (cancellable);
diff --git a/gio/gsocket.h b/gio/gsocket.h
index 1ad6a6f..d817328 100644
--- a/gio/gsocket.h
+++ b/gio/gsocket.h
@@ -145,6 +145,11 @@ gboolean g_socket_condition_wait (GSocket
GIOCondition condition,
GCancellable *cancellable,
GError **error);
+gboolean g_socket_condition_timed_wait (GSocket *socket,
+ GIOCondition condition,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error);
GSocket * g_socket_accept (GSocket *socket,
GCancellable *cancellable,
GError **error);
diff --git a/gio/tests/socket.c b/gio/tests/socket.c
index ecdb3be..7404bba 100644
--- a/gio/tests/socket.c
+++ b/gio/tests/socket.c
@@ -584,6 +584,56 @@ test_ipv6_v4mapped (void)
#endif
static void
+test_timed_wait (void)
+{
+ IPTestData *data;
+ GError *error = NULL;
+ GSocket *client;
+ GSocketAddress *addr;
+ gint64 start_time;
+ gint poll_duration;
+
+ data = create_server (G_SOCKET_FAMILY_IPV4, echo_server_thread, FALSE);
+ addr = g_socket_get_local_address (data->server, &error);
+
+ client = g_socket_new (G_SOCKET_FAMILY_IPV4,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ &error);
+ g_assert_no_error (error);
+
+ g_socket_set_blocking (client, TRUE);
+ g_socket_set_timeout (client, 1);
+
+ g_socket_connect (client, addr, NULL, &error);
+ g_assert_no_error (error);
+ g_object_unref (addr);
+
+ start_time = g_get_monotonic_time ();
+ g_socket_condition_timed_wait (client, G_IO_IN, 100000 /* 100 ms */,
+ NULL, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
+ g_clear_error (&error);
+ poll_duration = g_get_monotonic_time () - start_time;
+
+ g_assert_cmpint (poll_duration, >=, 100000);
+ g_assert_cmpint (poll_duration, <, 110000);
+
+ g_socket_close (client, &error);
+ g_assert_no_error (error);
+
+ g_thread_join (data->thread);
+
+ g_socket_close (data->server, &error);
+ g_assert_no_error (error);
+
+ g_object_unref (data->server);
+ g_object_unref (client);
+
+ g_slice_free (IPTestData, data);
+}
+
+static void
test_sockaddr (void)
{
struct sockaddr_in6 sin6, gsin6;
@@ -774,10 +824,11 @@ main (int argc,
g_test_add_func ("/socket/ipv4_async", test_ipv4_async);
g_test_add_func ("/socket/ipv6_sync", test_ipv6_sync);
g_test_add_func ("/socket/ipv6_async", test_ipv6_async);
- g_test_add_func ("/socket/close_graceful", test_close_graceful);
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
g_test_add_func ("/socket/ipv6_v4mapped", test_ipv6_v4mapped);
#endif
+ g_test_add_func ("/socket/close_graceful", test_close_graceful);
+ g_test_add_func ("/socket/timed_wait", test_timed_wait);
g_test_add_func ("/socket/address", test_sockaddr);
#ifdef G_OS_UNIX
g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]