[libsoup] Add SoupSession:use-thread-context
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] Add SoupSession:use-thread-context
- Date: Tue, 8 Nov 2011 17:52:08 +0000 (UTC)
commit 05dff333a7f46eb6644d28a4e15398d347b9a523
Author: Dan Winship <danw gnome org>
Date: Mon Oct 3 14:58:06 2011 -0400
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
libsoup/soup-connection.c | 26 ++++++-
libsoup/soup-connection.h | 1 +
libsoup/soup-message-queue.c | 1 +
libsoup/soup-message-queue.h | 1 +
libsoup/soup-session-async.c | 34 ++++++--
libsoup/soup-session.c | 56 ++++++++++++-
libsoup/soup-session.h | 1 +
libsoup/soup-socket.c | 49 ++++++++++-
libsoup/soup-socket.h | 1 +
tests/context-test.c | 180 ++++++++++++++++++++++++++++++++++++------
10 files changed, 308 insertions(+), 42 deletions(-)
---
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index d82832f..3e7f0ee 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 cd663a8..72e6106 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 59c5c5c..d324597 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 43cb0ae..5fb14c4 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 c813931..edb6239 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 7f5ea0e..16b150a 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 349cfdb..dd09599 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 ee83a3f..e1f7434 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 4d1550f..dc6b59c 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"
diff --git a/tests/context-test.c b/tests/context-test.c
index fe9af31..b72d200 100644
--- a/tests/context-test.c
+++ b/tests/context-test.c
@@ -99,34 +99,37 @@ static gpointer test1_thread (gpointer user_data);
static GCond *test1_cond;
static GMutex *test1_mutex;
+static GMainLoop *test1_loop;
static void
-do_test1 (void)
+do_test1 (int n, gboolean use_thread_context)
{
- GMainLoop *loop;
-
- debug_printf (1, "Test 1: blocking the main thread does not block other thread\n");
+ debug_printf (1, "\nTest %d: blocking the main thread does not block other thread\n", n);
+ if (use_thread_context)
+ debug_printf (1, "(Using g_main_context_push_thread_default())\n");
+ else
+ debug_printf (1, "(Using SOUP_SESSION_ASYNC_CONTEXT)\n");
test1_cond = g_cond_new ();
test1_mutex = g_mutex_new ();
- loop = g_main_loop_new (NULL, FALSE);
- g_idle_add (idle_start_test1_thread, loop);
- g_main_loop_run (loop);
- g_main_loop_unref (loop);
+ test1_loop = g_main_loop_new (NULL, FALSE);
+ g_idle_add (idle_start_test1_thread, GINT_TO_POINTER (use_thread_context));
+ g_main_loop_run (test1_loop);
+ g_main_loop_unref (test1_loop);
g_mutex_free (test1_mutex);
g_cond_free (test1_cond);
}
static gboolean
-idle_start_test1_thread (gpointer loop)
+idle_start_test1_thread (gpointer use_thread_context)
{
GTimeVal time;
GThread *thread;
g_mutex_lock (test1_mutex);
- thread = g_thread_create (test1_thread, base_uri, TRUE, NULL);
+ thread = g_thread_create (test1_thread, use_thread_context, TRUE, NULL);
g_get_current_time (&time);
time.tv_sec += 5;
@@ -138,7 +141,7 @@ idle_start_test1_thread (gpointer loop)
}
g_mutex_unlock (test1_mutex);
- g_main_loop_quit (loop);
+ g_main_loop_quit (test1_loop);
return FALSE;
}
@@ -149,7 +152,7 @@ test1_finished (SoupSession *session, SoupMessage *msg, gpointer loop)
}
static gpointer
-test1_thread (gpointer user_data)
+test1_thread (gpointer use_thread_context)
{
SoupSession *session;
GMainContext *async_context;
@@ -162,10 +165,16 @@ test1_thread (gpointer user_data)
g_mutex_unlock (test1_mutex);
async_context = g_main_context_new ();
- session = soup_test_session_new (
- SOUP_TYPE_SESSION_ASYNC,
- SOUP_SESSION_ASYNC_CONTEXT, async_context,
- NULL);
+ if (use_thread_context) {
+ g_main_context_push_thread_default (async_context);
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+ SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+ NULL);
+ } else {
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+ SOUP_SESSION_ASYNC_CONTEXT, async_context,
+ NULL);
+ }
g_main_context_unref (async_context);
uri = g_build_filename (base_uri, "slow", NULL);
@@ -198,6 +207,9 @@ test1_thread (gpointer user_data)
g_free (uri);
g_cond_signal (test1_cond);
+
+ if (use_thread_context)
+ g_main_context_pop_thread_default (async_context);
return NULL;
}
@@ -208,7 +220,7 @@ test1_thread (gpointer user_data)
static gboolean idle_test2_fail (gpointer user_data);
static void
-do_test2 (void)
+do_test2 (int n, gboolean use_thread_context)
{
guint idle;
GMainContext *async_context;
@@ -216,15 +228,25 @@ do_test2 (void)
char *uri;
SoupMessage *msg;
- debug_printf (1, "Test 2: a session with its own context is independent of the main loop.\n");
+ debug_printf (1, "\nTest %d: a session with its own context is independent of the main loop.\n", n);
+ if (use_thread_context)
+ debug_printf (1, "(Using g_main_context_push_thread_default())\n");
+ else
+ debug_printf (1, "(Using SOUP_SESSION_ASYNC_CONTEXT)\n");
idle = g_idle_add_full (G_PRIORITY_HIGH, idle_test2_fail, NULL, NULL);
async_context = g_main_context_new ();
- session = soup_test_session_new (
- SOUP_TYPE_SESSION_ASYNC,
- SOUP_SESSION_ASYNC_CONTEXT, async_context,
- NULL);
+ if (use_thread_context) {
+ g_main_context_push_thread_default (async_context);
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+ SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+ NULL);
+ } else {
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+ SOUP_SESSION_ASYNC_CONTEXT, async_context,
+ NULL);
+ }
g_main_context_unref (async_context);
uri = g_build_filename (base_uri, "slow", NULL);
@@ -243,6 +265,9 @@ do_test2 (void)
g_free (uri);
g_source_remove (idle);
+
+ if (use_thread_context)
+ g_main_context_pop_thread_default (async_context);
}
static gboolean
@@ -253,6 +278,110 @@ idle_test2_fail (gpointer user_data)
return FALSE;
}
+static void
+multi_request_started (SoupSession *session, SoupMessage *msg,
+ SoupSocket *socket, gpointer user_data)
+{
+ g_object_set_data (G_OBJECT (msg), "started", GUINT_TO_POINTER (TRUE));
+}
+
+static void
+msg1_got_headers (SoupMessage *msg, gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+
+ g_main_loop_quit (loop);
+}
+
+static void
+multi_msg_finished (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+
+ g_object_set_data (G_OBJECT (msg), "finished", GUINT_TO_POINTER (TRUE));
+ g_main_loop_quit (loop);
+}
+
+static void
+do_multicontext_test (int n)
+{
+ SoupSession *session;
+ SoupMessage *msg1, *msg2;
+ GMainContext *context1, *context2;
+ GMainLoop *loop1, *loop2;
+
+ debug_printf (1, "\nTest %d: Using multiple async contexts\n", n);
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+ SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
+ NULL);
+ g_signal_connect (session, "request-started",
+ G_CALLBACK (multi_request_started), NULL);
+
+ context1 = g_main_context_new ();
+ loop1 = g_main_loop_new (context1, FALSE);
+ context2 = g_main_context_new ();
+ loop2 = g_main_loop_new (context2, FALSE);
+
+ g_main_context_push_thread_default (context1);
+ msg1 = soup_message_new ("GET", base_uri);
+ g_object_ref (msg1);
+ soup_session_queue_message (session, msg1, multi_msg_finished, loop1);
+ g_signal_connect (msg1, "got-headers",
+ G_CALLBACK (msg1_got_headers), loop1);
+ g_object_set_data (G_OBJECT (msg1), "session", session);
+ g_main_context_pop_thread_default (context1);
+
+ g_main_context_push_thread_default (context2);
+ msg2 = soup_message_new ("GET", base_uri);
+ g_object_ref (msg2);
+ soup_session_queue_message (session, msg2, multi_msg_finished, loop2);
+ g_main_context_pop_thread_default (context2);
+
+ g_main_context_push_thread_default (context1);
+ g_main_loop_run (loop1);
+ g_main_context_pop_thread_default (context1);
+
+ if (!g_object_get_data (G_OBJECT (msg1), "started")) {
+ debug_printf (1, " msg1 not started??\n");
+ errors++;
+ }
+ if (g_object_get_data (G_OBJECT (msg2), "started")) {
+ debug_printf (1, " msg2 started while loop1 was running!\n");
+ errors++;
+ }
+
+ g_main_context_push_thread_default (context2);
+ g_main_loop_run (loop2);
+ g_main_context_pop_thread_default (context2);
+
+ if (g_object_get_data (G_OBJECT (msg1), "finished")) {
+ debug_printf (1, " msg1 finished while loop2 was running!\n");
+ errors++;
+ }
+ if (!g_object_get_data (G_OBJECT (msg2), "finished")) {
+ debug_printf (1, " msg2 not finished??\n");
+ errors++;
+ }
+
+ g_main_context_push_thread_default (context1);
+ g_main_loop_run (loop1);
+ g_main_context_pop_thread_default (context1);
+
+ if (!g_object_get_data (G_OBJECT (msg1), "finished")) {
+ debug_printf (1, " msg1 not finished??\n");
+ errors++;
+ }
+
+ g_main_loop_unref (loop1);
+ g_main_loop_unref (loop2);
+ g_main_context_unref (context1);
+ g_main_context_unref (context2);
+ g_object_unref (msg1);
+ g_object_unref (msg2);
+
+ soup_test_session_abort_unref (session);
+}
int
main (int argc, char **argv)
@@ -266,8 +395,11 @@ main (int argc, char **argv)
base_uri = g_strdup_printf ("http://127.0.0.1:%u/",
soup_server_get_port (server));
- do_test1 ();
- do_test2 ();
+ do_test1 (1, FALSE);
+ do_test1 (2, TRUE);
+ do_test2 (3, FALSE);
+ do_test2 (4, TRUE);
+ do_multicontext_test (5);
g_free (base_uri);
soup_test_server_quit_unref (server);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]