[libsoup/carlosgc/thread-safe: 18/19] connection: attach the idle timeout source to the session context




commit df4fde3929af4d3bb9ce03c42937eee1649ba6c5
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Thu Apr 21 15:04:47 2022 +0200

    connection: attach the idle timeout source to the session context
    
    The connection thread owner might change, so the context where the idle
    timeout source was attached might be destroyed while the connection is
    still alive. So, better use the session context always, since
    disconnecting at idle state is always safe from the session thread.

 libsoup/soup-connection-manager.c |  1 +
 libsoup/soup-connection.c         | 47 ++++++++++++++++++++++++---------------
 libsoup/soup-session-private.h    |  2 ++
 libsoup/soup-session.c            |  8 +++++++
 4 files changed, 40 insertions(+), 18 deletions(-)
---
diff --git a/libsoup/soup-connection-manager.c b/libsoup/soup-connection-manager.c
index d5966655..a200f221 100644
--- a/libsoup/soup-connection-manager.c
+++ b/libsoup/soup-connection-manager.c
@@ -461,6 +461,7 @@ soup_connection_manager_get_connection_locked (SoupConnectionManager *manager,
         socket_props = soup_session_ensure_socket_props (item->session);
         conn = g_object_new (SOUP_TYPE_CONNECTION,
                              "id", ++manager->last_connection_id,
+                             "context", soup_session_get_context (item->session),
                              "remote-connectable", remote_connectable,
                              "ssl", soup_uri_is_https (host->uri),
                              "socket-properties", socket_props,
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index 64ee4afa..6e77ec72 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -77,13 +77,14 @@ enum {
         PROP_TLS_PROTOCOL_VERSION,
         PROP_TLS_CIPHERSUITE_NAME,
         PROP_FORCE_HTTP_VERSION,
+        PROP_CONTEXT,
 
        LAST_PROPERTY
 };
 
 static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
 
-static void stop_idle_timer (SoupConnectionPrivate *priv);
+static gboolean idle_timeout (gpointer conn);
 
 /* Number of seconds after which we close a connection that hasn't yet
  * been used.
@@ -135,7 +136,11 @@ soup_connection_dispose (GObject *object)
        SoupConnection *conn = SOUP_CONNECTION (object);
        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
 
-       stop_idle_timer (priv);
+        if (priv->idle_timeout_src) {
+                g_source_destroy (priv->idle_timeout_src);
+                g_source_unref (priv->idle_timeout_src);
+                priv->idle_timeout_src = NULL;
+        }
 
        G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
 }
@@ -162,6 +167,13 @@ soup_connection_set_property (GObject *object, guint prop_id,
        case PROP_FORCE_HTTP_VERSION:
                priv->force_http_version = g_value_get_uchar (value);
                break;
+        case PROP_CONTEXT:
+                priv->idle_timeout_src = g_timeout_source_new (0);
+                g_source_set_ready_time (priv->idle_timeout_src, -1);
+                g_source_set_name (priv->idle_timeout_src, "Soup connection idle timeout");
+                g_source_set_callback (priv->idle_timeout_src, idle_timeout, object, NULL);
+                g_source_attach (priv->idle_timeout_src, g_value_get_pointer (value));
+                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -354,6 +366,12 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
                                     0, G_MAXUINT8, G_MAXUINT8,
                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                     G_PARAM_STATIC_STRINGS);
+        properties[PROP_CONTEXT] =
+                g_param_spec_pointer ("context",
+                                      "Context",
+                                      "The session main context",
+                                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+                                      G_PARAM_STATIC_STRINGS);
 
         g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
 }
@@ -373,7 +391,7 @@ static gboolean
 idle_timeout (gpointer conn)
 {
        soup_connection_disconnect (conn);
-       return FALSE;
+       return G_SOURCE_REMOVE;
 }
 
 static void
@@ -381,21 +399,14 @@ start_idle_timer (SoupConnection *conn)
 {
        SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
 
-       if (priv->socket_props->idle_timeout > 0 && !priv->idle_timeout_src) {
-               priv->idle_timeout_src =
-                       soup_add_timeout (g_main_context_get_thread_default (),
-                                         priv->socket_props->idle_timeout * 1000,
-                                         idle_timeout, conn);
-       }
-}
+       if (priv->socket_props->idle_timeout == 0)
+                return;
 
-static void
-stop_idle_timer (SoupConnectionPrivate *priv)
-{
-       if (priv->idle_timeout_src) {
-               g_source_destroy (priv->idle_timeout_src);
-                g_clear_pointer (&priv->idle_timeout_src, g_source_unref);
-       }
+        if (g_source_get_ready_time (priv->idle_timeout_src) >= 0)
+                return;
+
+        g_source_set_ready_time (priv->idle_timeout_src,
+                                 g_get_monotonic_time () + (guint64)priv->socket_props->idle_timeout * 
G_USEC_PER_SEC);
 }
 
 static void
@@ -1168,7 +1179,7 @@ soup_connection_setup_message_io (SoupConnection *conn,
         g_assert (g_atomic_int_get (&priv->state) == SOUP_CONNECTION_IN_USE);
 
         priv->unused_timeout = 0;
-        stop_idle_timer (priv);
+        g_source_set_ready_time (priv->idle_timeout_src, -1);
 
         if (priv->proxy_uri && soup_message_get_method (msg) == SOUP_METHOD_CONNECT)
                 set_proxy_msg (conn, msg);
diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h
index 3ed380d1..77595c81 100644
--- a/libsoup/soup-session-private.h
+++ b/libsoup/soup-session-private.h
@@ -42,6 +42,8 @@ void     soup_session_kick_queue (SoupSession *session);
 
 SoupSocketProperties *soup_session_ensure_socket_props (SoupSession *session);
 
+GMainContext *soup_session_get_context (SoupSession *session);
+
 G_END_DECLS
 
 #endif /* __SOUP_SESSION_PRIVATE_H__ */
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 9d8b15d4..ef03cdab 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -359,6 +359,14 @@ soup_session_finalize (GObject *object)
        G_OBJECT_CLASS (soup_session_parent_class)->finalize (object);
 }
 
+GMainContext *
+soup_session_get_context (SoupSession *session)
+{
+        SoupSessionPrivate *priv = soup_session_get_instance_private (session);
+
+        return priv->context;
+}
+
 SoupSocketProperties *
 soup_session_ensure_socket_props (SoupSession *session)
 {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]