summaryrefslogtreecommitdiff
path: root/libsoup
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2011-10-03 14:58:06 -0400
committerDan Winship <danw@gnome.org>2011-11-08 12:49:32 -0500
commit05dff333a7f46eb6644d28a4e15398d347b9a523 (patch)
treea1970e2694bae81bbcdd3d8b94e9ff1b78334f84 /libsoup
parent43043425599e98cae85877aa53baf0115e342f5c (diff)
downloadlibsoup-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.c26
-rw-r--r--libsoup/soup-connection.h1
-rw-r--r--libsoup/soup-message-queue.c1
-rw-r--r--libsoup/soup-message-queue.h1
-rw-r--r--libsoup/soup-session-async.c34
-rw-r--r--libsoup/soup-session.c56
-rw-r--r--libsoup/soup-session.h1
-rw-r--r--libsoup/soup-socket.c49
-rw-r--r--libsoup/soup-socket.h1
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"