mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 22:52:09 +01:00
gsocket: add g_socket_condition_timed_wait()
https://bugzilla.gnome.org/show_bug.cgi?id=667755
This commit is contained in:
parent
823f553e36
commit
726257ab97
@ -1852,6 +1852,7 @@ g_socket_is_connected
|
|||||||
g_socket_create_source
|
g_socket_create_source
|
||||||
g_socket_condition_check
|
g_socket_condition_check
|
||||||
g_socket_condition_wait
|
g_socket_condition_wait
|
||||||
|
g_socket_condition_timed_wait
|
||||||
g_socket_get_available_bytes
|
g_socket_get_available_bytes
|
||||||
g_socket_set_listen_backlog
|
g_socket_set_listen_backlog
|
||||||
g_socket_get_listen_backlog
|
g_socket_get_listen_backlog
|
||||||
|
@ -949,6 +949,7 @@ g_socket_close
|
|||||||
g_socket_shutdown
|
g_socket_shutdown
|
||||||
g_socket_condition_check
|
g_socket_condition_check
|
||||||
g_socket_condition_wait
|
g_socket_condition_wait
|
||||||
|
g_socket_condition_timed_wait
|
||||||
g_socket_connect
|
g_socket_connect
|
||||||
g_socket_create_source
|
g_socket_create_source
|
||||||
g_socket_get_available_bytes
|
g_socket_get_available_bytes
|
||||||
|
@ -3404,6 +3404,8 @@ g_socket_condition_check (GSocket *socket,
|
|||||||
* the appropriate value (%G_IO_ERROR_CANCELLED or
|
* the appropriate value (%G_IO_ERROR_CANCELLED or
|
||||||
* %G_IO_ERROR_TIMED_OUT).
|
* %G_IO_ERROR_TIMED_OUT).
|
||||||
*
|
*
|
||||||
|
* See also g_socket_condition_timed_wait().
|
||||||
|
*
|
||||||
* Returns: %TRUE if the condition was met, %FALSE otherwise
|
* Returns: %TRUE if the condition was met, %FALSE otherwise
|
||||||
*
|
*
|
||||||
* Since: 2.22
|
* Since: 2.22
|
||||||
@ -3416,17 +3418,69 @@ g_socket_condition_wait (GSocket *socket,
|
|||||||
{
|
{
|
||||||
g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
|
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))
|
if (!check_socket (socket, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||||
return FALSE;
|
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
|
#ifdef G_OS_WIN32
|
||||||
{
|
{
|
||||||
GIOCondition current_condition;
|
GIOCondition current_condition;
|
||||||
WSAEVENT events[2];
|
WSAEVENT events[2];
|
||||||
DWORD res, timeout;
|
DWORD res;
|
||||||
GPollFD cancel_fd;
|
GPollFD cancel_fd;
|
||||||
int num_events;
|
int num_events;
|
||||||
|
|
||||||
@ -3441,15 +3495,13 @@ g_socket_condition_wait (GSocket *socket,
|
|||||||
if (g_cancellable_make_pollfd (cancellable, &cancel_fd))
|
if (g_cancellable_make_pollfd (cancellable, &cancel_fd))
|
||||||
events[num_events++] = (WSAEVENT)cancel_fd.fd;
|
events[num_events++] = (WSAEVENT)cancel_fd.fd;
|
||||||
|
|
||||||
if (socket->priv->timeout)
|
if (timeout == -1)
|
||||||
timeout = socket->priv->timeout * 1000;
|
|
||||||
else
|
|
||||||
timeout = WSA_INFINITE;
|
timeout = WSA_INFINITE;
|
||||||
|
|
||||||
current_condition = update_condition (socket);
|
current_condition = update_condition (socket);
|
||||||
while ((condition & current_condition) == 0)
|
while ((condition & current_condition) == 0)
|
||||||
{
|
{
|
||||||
res = WSAWaitForMultipleEvents(num_events, events,
|
res = WSAWaitForMultipleEvents (num_events, events,
|
||||||
FALSE, timeout, FALSE);
|
FALSE, timeout, FALSE);
|
||||||
if (res == WSA_WAIT_FAILED)
|
if (res == WSA_WAIT_FAILED)
|
||||||
{
|
{
|
||||||
@ -3472,6 +3524,13 @@ g_socket_condition_wait (GSocket *socket,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
current_condition = update_condition (socket);
|
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);
|
remove_condition_watch (socket, &condition);
|
||||||
if (num_events > 1)
|
if (num_events > 1)
|
||||||
@ -3484,7 +3543,6 @@ g_socket_condition_wait (GSocket *socket,
|
|||||||
GPollFD poll_fd[2];
|
GPollFD poll_fd[2];
|
||||||
gint result;
|
gint result;
|
||||||
gint num;
|
gint num;
|
||||||
gint timeout;
|
|
||||||
|
|
||||||
poll_fd[0].fd = socket->priv->fd;
|
poll_fd[0].fd = socket->priv->fd;
|
||||||
poll_fd[0].events = condition;
|
poll_fd[0].events = condition;
|
||||||
@ -3493,14 +3551,19 @@ g_socket_condition_wait (GSocket *socket,
|
|||||||
if (g_cancellable_make_pollfd (cancellable, &poll_fd[1]))
|
if (g_cancellable_make_pollfd (cancellable, &poll_fd[1]))
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
if (socket->priv->timeout)
|
while (TRUE)
|
||||||
timeout = socket->priv->timeout * 1000;
|
{
|
||||||
else
|
|
||||||
timeout = -1;
|
|
||||||
|
|
||||||
do
|
|
||||||
result = g_poll (poll_fd, num, timeout);
|
result = g_poll (poll_fd, num, timeout);
|
||||||
while (result == -1 && get_socket_errno () == EINTR);
|
if (result != -1 || errno != EINTR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (timeout != -1)
|
||||||
|
{
|
||||||
|
timeout -= (g_get_monotonic_time () - start_time) * 1000;
|
||||||
|
if (timeout < 0)
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (num > 1)
|
if (num > 1)
|
||||||
g_cancellable_release_fd (cancellable);
|
g_cancellable_release_fd (cancellable);
|
||||||
|
@ -145,6 +145,11 @@ gboolean g_socket_condition_wait (GSocket
|
|||||||
GIOCondition condition,
|
GIOCondition condition,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
gboolean g_socket_condition_timed_wait (GSocket *socket,
|
||||||
|
GIOCondition condition,
|
||||||
|
gint64 timeout,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
GSocket * g_socket_accept (GSocket *socket,
|
GSocket * g_socket_accept (GSocket *socket,
|
||||||
GCancellable *cancellable,
|
GCancellable *cancellable,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -583,6 +583,56 @@ test_ipv6_v4mapped (void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
static void
|
||||||
test_sockaddr (void)
|
test_sockaddr (void)
|
||||||
{
|
{
|
||||||
@ -774,10 +824,11 @@ main (int argc,
|
|||||||
g_test_add_func ("/socket/ipv4_async", test_ipv4_async);
|
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_sync", test_ipv6_sync);
|
||||||
g_test_add_func ("/socket/ipv6_async", test_ipv6_async);
|
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)
|
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
|
||||||
g_test_add_func ("/socket/ipv6_v4mapped", test_ipv6_v4mapped);
|
g_test_add_func ("/socket/ipv6_v4mapped", test_ipv6_v4mapped);
|
||||||
#endif
|
#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);
|
g_test_add_func ("/socket/address", test_sockaddr);
|
||||||
#ifdef G_OS_UNIX
|
#ifdef G_OS_UNIX
|
||||||
g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);
|
g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user