diff options
author | Dan Winship <danw@gnome.org> | 2011-10-03 14:58:06 -0400 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2011-11-08 12:49:32 -0500 |
commit | 05dff333a7f46eb6644d28a4e15398d347b9a523 (patch) | |
tree | a1970e2694bae81bbcdd3d8b94e9ff1b78334f84 /libsoup | |
parent | 43043425599e98cae85877aa53baf0115e342f5c (diff) | |
download | libsoup-05dff333a7f46eb6644d28a4e15398d347b9a523.tar.gz |
Add SoupSession:use-thread-context
Add a SoupSession flag telling it to use
g_main_context_get_thread_default() on a per-message basis, rather
than using a single GMainContext for everything. In the simple case,
this is just more glib-like API. In the more complicated case, it
allows synchronously sending one or more messages on a
SoupSessionAsync without running the main GMainLoop.
https://bugs.webkit.org/show_bug.cgi?id=68238
Diffstat (limited to 'libsoup')
-rw-r--r-- | libsoup/soup-connection.c | 26 | ||||
-rw-r--r-- | libsoup/soup-connection.h | 1 | ||||
-rw-r--r-- | libsoup/soup-message-queue.c | 1 | ||||
-rw-r--r-- | libsoup/soup-message-queue.h | 1 | ||||
-rw-r--r-- | libsoup/soup-session-async.c | 34 | ||||
-rw-r--r-- | libsoup/soup-session.c | 56 | ||||
-rw-r--r-- | libsoup/soup-session.h | 1 | ||||
-rw-r--r-- | libsoup/soup-socket.c | 49 | ||||
-rw-r--r-- | libsoup/soup-socket.h | 1 |
9 files changed, 152 insertions, 18 deletions
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c index d82832f3..3e7f0eed 100644 --- a/libsoup/soup-connection.c +++ b/libsoup/soup-connection.c @@ -37,7 +37,8 @@ typedef struct { GTlsDatabase *tlsdb; gboolean ssl, ssl_strict, ssl_fallback; - GMainContext *async_context; + GMainContext *async_context; + gboolean use_thread_context; SoupMessageQueueItem *cur_item; SoupConnectionState state; @@ -67,6 +68,7 @@ enum { PROP_SSL_STRICT, PROP_SSL_FALLBACK, PROP_ASYNC_CONTEXT, + PROP_USE_THREAD_CONTEXT, PROP_TIMEOUT, PROP_IDLE_TIMEOUT, PROP_STATE, @@ -214,6 +216,13 @@ soup_connection_class_init (SoupConnectionClass *connection_class) "GMainContext to dispatch this connection's async I/O in", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property ( + object_class, PROP_USE_THREAD_CONTEXT, + g_param_spec_boolean (SOUP_CONNECTION_USE_THREAD_CONTEXT, + "Use thread context", + "Use g_main_context_get_thread_default", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property ( object_class, PROP_TIMEOUT, g_param_spec_uint (SOUP_CONNECTION_TIMEOUT, "Timeout value", @@ -295,6 +304,9 @@ set_property (GObject *object, guint prop_id, if (priv->async_context) g_main_context_ref (priv->async_context); break; + case PROP_USE_THREAD_CONTEXT: + priv->use_thread_context = g_value_get_boolean (value); + break; case PROP_TIMEOUT: priv->io_timeout = g_value_get_uint (value); break; @@ -341,6 +353,9 @@ get_property (GObject *object, guint prop_id, case PROP_ASYNC_CONTEXT: g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL); break; + case PROP_USE_THREAD_CONTEXT: + g_value_set_boolean (value, priv->use_thread_context); + break; case PROP_TIMEOUT: g_value_set_uint (value, priv->io_timeout); break; @@ -533,6 +548,7 @@ soup_connection_connect_async (SoupConnection *conn, SOUP_SOCKET_SSL_STRICT, priv->ssl_strict, SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback, SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context, + SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context, SOUP_SOCKET_TIMEOUT, priv->io_timeout, "clean-dispose", TRUE, NULL); @@ -672,6 +688,7 @@ soup_connection_start_ssl_async (SoupConnection *conn, SoupConnectionPrivate *priv; const char *server_name; SoupConnectionAsyncConnectData *data; + GMainContext *async_context; g_return_if_fail (SOUP_IS_CONNECTION (conn)); priv = SOUP_CONNECTION_GET_PRIVATE (conn); @@ -681,12 +698,17 @@ soup_connection_start_ssl_async (SoupConnection *conn, data->callback = callback; data->callback_data = user_data; + if (priv->use_thread_context) + async_context = g_main_context_get_thread_default (); + else + async_context = priv->async_context; + server_name = soup_address_get_name (priv->tunnel_addr ? priv->tunnel_addr : priv->remote_addr); if (!soup_socket_start_proxy_ssl (priv->socket, server_name, cancellable)) { - soup_add_completion (priv->async_context, + soup_add_completion (async_context, idle_start_ssl_completed, data); return; } diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h index cd663a84..72e61062 100644 --- a/libsoup/soup-connection.h +++ b/libsoup/soup-connection.h @@ -47,6 +47,7 @@ typedef void (*SoupConnectionCallback) (SoupConnection *conn, #define SOUP_CONNECTION_SSL_STRICT "ssl-strict" #define SOUP_CONNECTION_SSL_FALLBACK "ssl-fallback" #define SOUP_CONNECTION_ASYNC_CONTEXT "async-context" +#define SOUP_CONNECTION_USE_THREAD_CONTEXT "use-thread-context" #define SOUP_CONNECTION_TIMEOUT "timeout" #define SOUP_CONNECTION_IDLE_TIMEOUT "idle-timeout" #define SOUP_CONNECTION_STATE "state" diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c index 59c5c5c4..d3245978 100644 --- a/libsoup/soup-message-queue.c +++ b/libsoup/soup-message-queue.c @@ -103,6 +103,7 @@ soup_message_queue_append (SoupMessageQueue *queue, SoupMessage *msg, item = g_slice_new0 (SoupMessageQueueItem); item->session = queue->session; + item->async_context = soup_session_get_async_context (item->session); item->queue = queue; item->msg = g_object_ref (msg); item->callback = callback; diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h index 43cb0aec..5fb14c4d 100644 --- a/libsoup/soup-message-queue.h +++ b/libsoup/soup-message-queue.h @@ -39,6 +39,7 @@ struct _SoupMessageQueueItem { SoupMessage *msg; SoupSessionCallback callback; gpointer callback_data; + GMainContext *async_context; GCancellable *cancellable; SoupAddress *proxy_addr; diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c index c813931f..edb62392 100644 --- a/libsoup/soup-session-async.c +++ b/libsoup/soup-session-async.c @@ -47,13 +47,25 @@ static void auth_required (SoupSession *session, SoupMessage *msg, G_DEFINE_TYPE (SoupSessionAsync, soup_session_async, SOUP_TYPE_SESSION) typedef struct { - GSource *idle_run_queue_source; + GHashTable *idle_run_queue_sources; + } SoupSessionAsyncPrivate; #define SOUP_SESSION_ASYNC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION_ASYNC, SoupSessionAsyncPrivate)) static void +destroy_unref_source (gpointer source) +{ + g_source_destroy (source); + g_source_unref (source); +} + +static void soup_session_async_init (SoupSessionAsync *sa) { + SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (sa); + + priv->idle_run_queue_sources = + g_hash_table_new_full (NULL, NULL, NULL, destroy_unref_source); } static void @@ -61,8 +73,7 @@ finalize (GObject *object) { SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (object); - if (priv->idle_run_queue_source) - g_source_destroy (priv->idle_run_queue_source); + g_hash_table_destroy (priv->idle_run_queue_sources); G_OBJECT_CLASS (soup_session_async_parent_class)->finalize (object); } @@ -364,6 +375,9 @@ process_queue_item (SoupMessageQueueItem *item, SoupSession *session = item->session; SoupProxyURIResolver *proxy_resolver; + if (item->async_context != soup_session_get_async_context (session)) + return; + do { if (item->paused) return; @@ -470,7 +484,8 @@ idle_run_queue (gpointer sa) { SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (sa); - priv->idle_run_queue_source = NULL; + g_hash_table_remove (priv->idle_run_queue_sources, + soup_session_get_async_context (sa)); run_queue (sa); return FALSE; } @@ -480,10 +495,13 @@ do_idle_run_queue (SoupSession *session) { SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (session); - if (!priv->idle_run_queue_source) { - priv->idle_run_queue_source = soup_add_completion ( - soup_session_get_async_context (session), - idle_run_queue, session); + if (!g_hash_table_lookup (priv->idle_run_queue_sources, + soup_session_get_async_context (session))) { + GMainContext *async_context = soup_session_get_async_context (session); + GSource *source = soup_add_completion (async_context, idle_run_queue, session); + + g_hash_table_insert (priv->idle_run_queue_sources, + async_context, g_source_ref (source)); } } diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c index 7f5ea0e3..16b150a0 100644 --- a/libsoup/soup-session.c +++ b/libsoup/soup-session.c @@ -101,6 +101,7 @@ typedef struct { GMutex *host_lock; GMainContext *async_context; + gboolean use_thread_context; GResolver *resolver; @@ -156,6 +157,7 @@ enum { PROP_TLS_DATABASE, PROP_SSL_STRICT, PROP_ASYNC_CONTEXT, + PROP_USE_THREAD_CONTEXT, PROP_TIMEOUT, PROP_USER_AGENT, PROP_ACCEPT_LANGUAGE, @@ -653,7 +655,7 @@ soup_session_class_init (SoupSessionClass *session_class) * * Alias for the #SoupSession:async-context property. (The * session's #GMainContext.) - **/ + */ g_object_class_install_property ( object_class, PROP_ASYNC_CONTEXT, g_param_spec_pointer (SOUP_SESSION_ASYNC_CONTEXT, @@ -661,6 +663,33 @@ soup_session_class_init (SoupSessionClass *session_class) "The GMainContext to dispatch async I/O in", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); /** + * SOUP_SESSION_USE_THREAD_CONTEXT: + * + * Alias for the #SoupSession:use-thread-context property, qv. + * + * Since: 2.38 + */ + /** + * SoupSession:use-thread-context: + * + * If set, asynchronous operations in this session will run in + * whatever the thread-default #GMainContext is at the time + * they are started, rather than always occurring in a context + * fixed at the session's construction time. "Bookkeeping" + * tasks (like expiring idle connections) will happen in the + * context that was thread-default at the time the session was + * created. + * + * Since: 2.38 + */ + g_object_class_install_property ( + object_class, PROP_USE_THREAD_CONTEXT, + g_param_spec_boolean (SOUP_SESSION_USE_THREAD_CONTEXT, + "Use thread-default GMainContext", + "Whether to use thread-default main contexts", + FALSE, + G_PARAM_READWRITE)); + /** * SOUP_SESSION_TIMEOUT: * * Alias for the #SoupSession:timeout property. (The timeout @@ -1109,6 +1138,16 @@ set_property (GObject *object, guint prop_id, if (priv->async_context) g_main_context_ref (priv->async_context); break; + case PROP_USE_THREAD_CONTEXT: + priv->use_thread_context = g_value_get_boolean (value); + if (priv->use_thread_context) { + if (priv->async_context) + g_main_context_unref (priv->async_context); + priv->async_context = g_main_context_get_thread_default (); + if (priv->async_context) + g_main_context_ref (priv->async_context); + } + break; case PROP_TIMEOUT: priv->io_timeout = g_value_get_uint (value); break; @@ -1216,6 +1255,9 @@ get_property (GObject *object, guint prop_id, case PROP_ASYNC_CONTEXT: g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL); break; + case PROP_USE_THREAD_CONTEXT: + g_value_set_boolean (value, priv->use_thread_context); + break; case PROP_TIMEOUT: g_value_set_uint (value, priv->io_timeout); break; @@ -1294,6 +1336,9 @@ uri_is_https (SoupSessionPrivate *priv, SoupURI *uri) * context, so you will need to ref it yourself if you want it to * outlive its session. * + * If #SoupSession:use-thread-context is true, this will return the + * current thread-default main context. + * * Return value: (transfer none): @session's #GMainContext, which may * be %NULL **/ @@ -1305,7 +1350,10 @@ soup_session_get_async_context (SoupSession *session) g_return_val_if_fail (SOUP_IS_SESSION (session), NULL); priv = SOUP_SESSION_GET_PRIVATE (session); - return priv->async_context; + if (priv->use_thread_context) + return g_main_context_get_thread_default (); + else + return priv->async_context; } /* Hosts */ @@ -1784,6 +1832,7 @@ soup_session_get_connection (SoupSession *session, SOUP_CONNECTION_SSL_CREDENTIALS, priv->tlsdb, SOUP_CONNECTION_SSL_STRICT, (priv->tlsdb != NULL) && priv->ssl_strict, SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context, + SOUP_CONNECTION_USE_THREAD_CONTEXT, priv->use_thread_context, SOUP_CONNECTION_TIMEOUT, priv->io_timeout, SOUP_CONNECTION_IDLE_TIMEOUT, priv->idle_timeout, SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback, @@ -2234,7 +2283,8 @@ soup_session_prepare_for_uri (SoupSession *session, SoupURI *uri) addr = g_object_ref (host->addr); g_mutex_unlock (priv->host_lock); - soup_address_resolve_async (addr, priv->async_context, + soup_address_resolve_async (addr, + soup_session_get_async_context (session), NULL, NULL, NULL); g_object_unref (addr); } diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h index 349cfdb1..dd09599b 100644 --- a/libsoup/soup-session.h +++ b/libsoup/soup-session.h @@ -68,6 +68,7 @@ GType soup_session_get_type (void); #define SOUP_SESSION_TLS_DATABASE "tls-database" #define SOUP_SESSION_SSL_STRICT "ssl-strict" #define SOUP_SESSION_ASYNC_CONTEXT "async-context" +#define SOUP_SESSION_USE_THREAD_CONTEXT "use-thread-context" #define SOUP_SESSION_TIMEOUT "timeout" #define SOUP_SESSION_USER_AGENT "user-agent" #define SOUP_SESSION_ACCEPT_LANGUAGE "accept-language" diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index ee83a3f1..e1f7434c 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -55,6 +55,7 @@ enum { PROP_SSL_STRICT, PROP_SSL_FALLBACK, PROP_ASYNC_CONTEXT, + PROP_USE_THREAD_CONTEXT, PROP_TIMEOUT, PROP_TRUSTED_CERTIFICATE, PROP_CLEAN_DISPOSE, @@ -78,6 +79,7 @@ typedef struct { guint ssl_strict:1; guint ssl_fallback:1; guint clean_dispose:1; + guint use_thread_context:1; gpointer ssl_creds; GMainContext *async_context; @@ -406,6 +408,29 @@ soup_socket_class_init (SoupSocketClass *socket_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); /** + * SOUP_SOCKET_USE_THREAD_CONTEXT: + * + * Alias for the #SoupSocket:use-thread-context property. (Use + * g_main_context_get_thread_default()) + * + * Since: 2.36.1 + */ + /** + * SoupSocket:use-thread-context: + * + * Use g_main_context_get_thread_default(). + * + * Since: 2.36.1 + */ + g_object_class_install_property ( + object_class, PROP_USE_THREAD_CONTEXT, + g_param_spec_boolean (SOUP_SOCKET_USE_THREAD_CONTEXT, + "Use thread context", + "Use g_main_context_get_thread_default", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /** * SOUP_SOCKET_TIMEOUT: * * Alias for the #SoupSocket:timeout property. (The timeout @@ -509,6 +534,9 @@ set_property (GObject *object, guint prop_id, if (priv->async_context) g_main_context_ref (priv->async_context); break; + case PROP_USE_THREAD_CONTEXT: + priv->use_thread_context = g_value_get_boolean (value); + break; case PROP_TIMEOUT: priv->timeout = g_value_get_uint (value); if (priv->conn) @@ -557,6 +585,9 @@ get_property (GObject *object, guint prop_id, case PROP_ASYNC_CONTEXT: g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL); break; + case PROP_USE_THREAD_CONTEXT: + g_value_set_boolean (value, priv->use_thread_context); + break; case PROP_TIMEOUT: g_value_set_uint (value, priv->timeout); break; @@ -648,7 +679,7 @@ async_connected (GObject *client, GAsyncResult *result, gpointer data) GSocketConnection *conn; guint status; - if (priv->async_context) + if (priv->async_context && !priv->use_thread_context) g_main_context_pop_thread_default (priv->async_context); conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), @@ -694,7 +725,7 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable, priv->connect_cancel = cancellable ? g_object_ref (cancellable) : g_cancellable_new (); - if (priv->async_context) + if (priv->async_context && !priv->use_thread_context) g_main_context_push_thread_default (priv->async_context); client = g_socket_client_new (); @@ -765,13 +796,20 @@ soup_socket_create_watch (SoupSocketPrivate *priv, GIOCondition cond, GCancellable *cancellable) { GSource *watch; + GMainContext *async_context; if (cond == G_IO_IN) watch = g_pollable_input_stream_create_source (priv->istream, cancellable); else watch = g_pollable_output_stream_create_source (priv->ostream, cancellable); g_source_set_callback (watch, (GSourceFunc)callback, user_data, NULL); - g_source_attach (watch, priv->async_context); + + if (priv->use_thread_context) + async_context = g_main_context_get_thread_default (); + else + async_context = priv->async_context; + + g_source_attach (watch, async_context); g_source_unref (watch); return watch; @@ -793,6 +831,7 @@ listen_watch (GObject *pollable, gpointer data) new_priv->gsock = new_gsock; if (priv->async_context) new_priv->async_context = g_main_context_ref (priv->async_context); + new_priv->use_thread_context = priv->use_thread_context; new_priv->non_blocking = priv->non_blocking; new_priv->is_server = TRUE; new_priv->ssl = priv->ssl; @@ -1018,7 +1057,7 @@ handshake_async_ready (GObject *source, GAsyncResult *result, gpointer user_data GError *error = NULL; guint status; - if (priv->async_context) + if (priv->async_context && !priv->use_thread_context) g_main_context_pop_thread_default (priv->async_context); if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (priv->conn), @@ -1052,7 +1091,7 @@ soup_socket_handshake_async (SoupSocket *sock, data->callback = callback; data->user_data = user_data; - if (priv->async_context) + if (priv->async_context && !priv->use_thread_context) g_main_context_push_thread_default (priv->async_context); g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->conn), G_PRIORITY_DEFAULT, diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h index 4d1550f0..dc6b59c4 100644 --- a/libsoup/soup-socket.h +++ b/libsoup/soup-socket.h @@ -48,6 +48,7 @@ typedef struct { #define SOUP_SOCKET_SSL_FALLBACK "ssl-fallback" #define SOUP_SOCKET_TRUSTED_CERTIFICATE "trusted-certificate" #define SOUP_SOCKET_ASYNC_CONTEXT "async-context" +#define SOUP_SOCKET_USE_THREAD_CONTEXT "use-thread-context" #define SOUP_SOCKET_TIMEOUT "timeout" #define SOUP_SOCKET_TLS_CERTIFICATE "tls-certificate" #define SOUP_SOCKET_TLS_ERRORS "tls-errors" |