[libgda] Allow gda_connection_set_main_context() to work with multiple contexts



commit 54746d5124dc6c460f96eae3268f653b7b4218dc
Author: Vivien Malerba <malerba gnome-db org>
Date:   Wed Apr 2 18:33:08 2014 +0200

    Allow gda_connection_set_main_context() to work with multiple contexts

 libgda-ui/demos/main.c             |    2 +-
 libgda/gda-connection-private.h    |    1 +
 libgda/gda-connection.c            |  181 ++++++++++++++++++++---------------
 libgda/gda-connection.h            |    8 +-
 libgda/gda-server-provider.c       |    6 +-
 libgda/test-cnc-exec.c             |  111 +++++++++++++++++++++-
 libgda/test-cnc-meta.c             |    2 +-
 libgda/test-cnc-open.c             |   71 ++++++++++++++-
 libgda/thread-wrapper/gda-worker.c |   17 ++++
 libgda/thread-wrapper/gda-worker.h |    1 +
 10 files changed, 309 insertions(+), 91 deletions(-)
---
diff --git a/libgda-ui/demos/main.c b/libgda-ui/demos/main.c
index f26973d..98e994e 100644
--- a/libgda-ui/demos/main.c
+++ b/libgda-ui/demos/main.c
@@ -799,7 +799,7 @@ main (int argc, char **argv)
        /* set main context for connection */
        GMainContext *context;
        context = g_main_context_ref_thread_default ();
-       gda_connection_set_main_context (demo_cnc, context);
+       gda_connection_set_main_context (demo_cnc, NULL, context);
        g_main_context_unref (context);
        g_object_set (demo_cnc, "execution-slowdown", 1000000, NULL);
 
diff --git a/libgda/gda-connection-private.h b/libgda/gda-connection-private.h
index ce45267..d62d72b 100644
--- a/libgda/gda-connection-private.h
+++ b/libgda/gda-connection-private.h
@@ -52,6 +52,7 @@ void                             gda_connection_internal_set_provider_data
                                                                                  
GdaServerProviderConnectionData *data,
                                                                                  GDestroyNotify 
destroy_func);
 GdaServerProviderConnectionData *gda_connection_internal_get_provider_data_error (GdaConnection *cnc, GError 
**error);
+void                             _gda_connection_internal_set_worker_thread (GdaConnection *cnc, GThread 
*thread);
 
 /*
  * Connection's events
diff --git a/libgda/gda-connection.c b/libgda/gda-connection.c
index 23bf74f..d36028a 100644
--- a/libgda/gda-connection.c
+++ b/libgda/gda-connection.c
@@ -2,7 +2,7 @@
  * Copyright (C) 2000 - 2001 Reinhard Müller <reinhard src gnome org>
  * Copyright (C) 2000 - 2004 Rodrigo Moya <rodrigo gnome-db org>
  * Copyright (C) 2001 - 2003 Gonzalo Paniagua Javier <gonzalo gnome-db org>
- * Copyright (C) 2001 - 2013 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2001 - 2014 Vivien Malerba <malerba gnome-db org>
  * Copyright (C) 2002 Andrew Hill <andru src gnome org>
  * Copyright (C) 2002 Cleber Rodrigues <cleberrrjr bol com br>
  * Copyright (C) 2002 Zbigniew Chyla <cyba gnome pl>
@@ -74,9 +74,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 
-static GMutex parser_mutex;
+static GMutex global_mutex;
 static GdaSqlParser *internal_parser = NULL;
-static GMainContext *all_context = NULL;
+static GHashTable *all_context_hash = NULL; /* key = a #GThread, value = a #GMainContext (ref held) */
 
 /* number of GdaConnectionEvent kept by each connection. Should be enough to avoid losing any
  * event, considering that the events are reseted after each statement execution */
@@ -89,7 +89,7 @@ struct _GdaConnectionPrivate {
        gchar                *cnc_string;
        gchar                *auth_string;
 
-       GMainContext         *context;
+       GHashTable           *context_hash; /* key = a #GThread, value = a #GMainContext (ref held) */
 
        GdaMetaStore         *meta_store;
 
@@ -104,6 +104,7 @@ struct _GdaConnectionPrivate {
        GHashTable           *prepared_stmts;
 
        GdaServerProviderConnectionData *provider_data;
+       GThread              *worker_thread; /* no ref held, used only for comparisons */
 
        /* multi threading locking */
        GMutex                object_mutex;
@@ -404,6 +405,12 @@ gda_connection_lockable_init (GdaLockableIface *iface)
 }
 
 static void
+all_context_hash_func (GThread *key, GMainContext *context, GHashTable *copyto)
+{
+       g_hash_table_insert (copyto, key, g_main_context_ref (context));
+}
+
+static void
 gda_connection_init (GdaConnection *cnc, G_GNUC_UNUSED GdaConnectionClass *klass)
 {
        g_return_if_fail (GDA_IS_CONNECTION (cnc));
@@ -415,10 +422,14 @@ gda_connection_init (GdaConnection *cnc, G_GNUC_UNUSED GdaConnectionClass *klass
        cnc->priv->dsn = NULL;
        cnc->priv->cnc_string = NULL;
        cnc->priv->auth_string = NULL;
-       if (all_context)
-               cnc->priv->context = g_main_context_ref (all_context);
+       if (all_context_hash) {
+               g_mutex_lock (&global_mutex);
+               cnc->priv->context_hash = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) 
g_main_context_unref);
+               g_hash_table_foreach (all_context_hash, (GHFunc) all_context_hash_func, 
cnc->priv->context_hash);
+               g_mutex_unlock (&global_mutex);
+       }
        else
-               cnc->priv->context = NULL;
+               cnc->priv->context_hash = NULL;
        cnc->priv->auto_clear_events = TRUE;
        cnc->priv->events_array_size = EVENTS_ARRAY_SIZE;
        cnc->priv->events_array = g_new0 (GdaConnectionEvent*, EVENTS_ARRAY_SIZE);
@@ -429,6 +440,7 @@ gda_connection_init (GdaConnection *cnc, G_GNUC_UNUSED GdaConnectionClass *klass
 
        cnc->priv->trans_meta_context = NULL;
        cnc->priv->provider_data = NULL;
+       cnc->priv->worker_thread = NULL;
 
        cnc->priv->exec_times = FALSE;
        cnc->priv->exec_slowdown = 0;
@@ -446,9 +458,9 @@ gda_connection_dispose (GObject *object)
        /* free memory */
        _gda_connection_close_no_warning (cnc, NULL);
 
-       if (cnc->priv->context) {
-               g_main_context_unref (cnc->priv->context);
-               cnc->priv->context = NULL;
+       if (cnc->priv->context_hash) {
+               g_hash_table_destroy (cnc->priv->context_hash);
+               cnc->priv->context_hash = NULL;
        }
 
        /* get rid of prepared statements to avoid problems */
@@ -760,6 +772,7 @@ gda_connection_get_property (GObject *object,
 /**
  * gda_connection_set_main_context:
  * @cnc: (allow-none): a #GdaConnection, or %NULL
+ * @thread: (allow-none): the #GThread in which @context will be used, or %NULL (for the current thread)
  * @context: (allow-none): a #GMainContext, or %NULL
  *
  * Defines the #GMainContext which will still process events while a potentially blocking operation is 
performed.
@@ -768,7 +781,7 @@ gda_connection_get_property (GObject *object,
  * <programlisting><![CDATA[GMainContext *context;
  * cnc = gda_connection_new_...;
  * context = g_main_context_ref_thread_default ();
- * gda_connection_set_main_context (cnc, context);
+ * gda_connection_set_main_context (cnc, NULL, context);
  * g_main_context_unref (context);
  * GError *error = NULL;
  * if (! gda_connection_open (cnc, &error))
@@ -780,38 +793,46 @@ gda_connection_get_property (GObject *object,
  * Since: 6.0
  */
 void
-gda_connection_set_main_context (GdaConnection *cnc, GMainContext *context)
+gda_connection_set_main_context (GdaConnection *cnc, GThread *thread, GMainContext *context)
 {
+       if (!thread)
+               thread = g_thread_self ();
+
+       g_mutex_lock (&global_mutex);
+
        if (cnc) {
                g_return_if_fail (GDA_IS_CONNECTION (cnc));
-               if (cnc->priv->context == context)
-                       return;
-
-               gda_connection_lock ((GdaLockable*) cnc);
-               if (cnc->priv->context) {
-                       g_main_context_unref (cnc->priv->context);
-                       cnc->priv->context = NULL;
+               if (context) {
+                       if (! cnc->priv->context_hash)
+                               cnc->priv->context_hash = g_hash_table_new_full (NULL, NULL, NULL,
+                                                                                (GDestroyNotify) 
g_main_context_unref);
+                       g_main_context_ref (context);
+                       g_hash_table_insert (cnc->priv->context_hash, thread, g_main_context_ref (context));
+                       g_main_context_unref (context);
                }
-               if (context)
-                       cnc->priv->context = g_main_context_ref (context);
-               gda_connection_unlock ((GdaLockable*) cnc);
+               else if (cnc->priv->context_hash)
+                       g_hash_table_remove (cnc->priv->context_hash, thread);
        }
        else {
-               if (all_context == context)
-                       return;
-
-               if (all_context) {
-                       g_main_context_unref (all_context);
-                       all_context = NULL;
+               if (context) {
+                       if (! all_context_hash)
+                               all_context_hash = g_hash_table_new_full (NULL, NULL, NULL,
+                                                                         (GDestroyNotify) 
g_main_context_unref);
+                       g_main_context_ref (context);
+                       g_hash_table_insert (all_context_hash, thread, g_main_context_ref (context));
+                       g_main_context_unref (context);
                }
-               if (context)
-                       all_context = g_main_context_ref (context);
+               else if (all_context_hash)
+                       g_hash_table_remove (all_context_hash, thread);
        }
+
+       g_mutex_unlock (&global_mutex);
 }
 
 /**
  * gda_connection_get_main_context:
  * @cnc: (allow-none): a #GdaConnection, or %NULL
+ * @thread: (allow-none): the #GThread in which @context will be used, or %NULL (for the current thread)
  *
  * Get the #GMainContext used while a potentially blocking operation is performed, see 
gda_connection_set_main_context().
  * If no main context has been defined, then some function calls (for example connection opening) may block 
until the
@@ -822,14 +843,28 @@ gda_connection_set_main_context (GdaConnection *cnc, GMainContext *context)
  * Since: 6.0
  */
 GMainContext *
-gda_connection_get_main_context (GdaConnection *cnc)
+gda_connection_get_main_context (GdaConnection *cnc, GThread *thread)
 {
+       if (!thread)
+               thread = g_thread_self ();
+
+       GMainContext *context = NULL;
+
        if (cnc) {
                g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-               return cnc->priv->context;
+               g_mutex_lock (&global_mutex);
+               if (cnc->priv->context_hash)
+                       context = g_hash_table_lookup (cnc->priv->context_hash, thread);
+               g_mutex_unlock (&global_mutex);
        }
-       else
-               return all_context;
+       else {
+               g_mutex_lock (&global_mutex);
+               if (all_context_hash)
+                       context = g_hash_table_lookup (cnc->priv->context_hash, thread);
+               g_mutex_unlock (&global_mutex);
+       }
+
+       return context;
 }
 
 /*
@@ -2893,10 +2928,10 @@ gda_connection_execute_select_command (GdaConnection *cnc, const gchar *sql, GEr
                              || g_str_has_prefix (sql, "SELECT"),
                              NULL);
 
-       g_mutex_lock (&parser_mutex);
+       g_mutex_lock (&global_mutex);
        if (!internal_parser)
                internal_parser = gda_sql_parser_new ();
-       g_mutex_unlock (&parser_mutex);
+       g_mutex_unlock (&global_mutex);
 
        stmt = gda_sql_parser_parse_string (internal_parser, sql, NULL, error);
        if (!stmt)
@@ -2930,10 +2965,10 @@ gda_connection_execute_non_select_command (GdaConnection *cnc, const gchar *sql,
                              || GDA_IS_CONNECTION (cnc)
                              || !gda_connection_is_opened (cnc), -1);
 
-       g_mutex_lock (&parser_mutex);
+       g_mutex_lock (&global_mutex);
        if (!internal_parser)
                internal_parser = gda_sql_parser_new ();
-       g_mutex_unlock (&parser_mutex);
+       g_mutex_unlock (&global_mutex);
 
        stmt = gda_sql_parser_parse_string (internal_parser, sql, NULL, error);
        if (!stmt)
@@ -5636,6 +5671,17 @@ gda_connection_internal_set_provider_data (GdaConnection *cnc, GdaServerProvider
                gda_connection_unlock ((GdaLockable*) cnc);
 }
 
+void
+_gda_connection_internal_set_worker_thread (GdaConnection *cnc, GThread *thread)
+{
+       g_mutex_lock (&global_mutex);
+       if (cnc->priv->worker_thread && thread)
+               g_warning ("Trying to overwriting connection's associated internal thread");
+       else
+               cnc->priv->worker_thread = thread;
+       g_mutex_unlock (&global_mutex);
+}
+
 /**
  * gda_connection_internal_get_provider_data_error: (skip)
  * @cnc: a #GdaConnection object
@@ -5679,9 +5725,9 @@ gda_connection_get_meta_store (GdaConnection *cnc)
                GdaConnection *scnc;
                scnc = gda_meta_store_get_internal_connection (cnc->priv->meta_store);
                if ((scnc != cnc) &&
-                   gda_connection_get_main_context (cnc) &&
-                   ! gda_connection_get_main_context (scnc))
-                       gda_connection_set_main_context (scnc, gda_connection_get_main_context (cnc));
+                   gda_connection_get_main_context (cnc, NULL) &&
+                   ! gda_connection_get_main_context (scnc, NULL))
+                       gda_connection_set_main_context (scnc, NULL, gda_connection_get_main_context (cnc, 
NULL));
        }
        g_mutex_unlock (& cnc->priv->object_mutex);
 
@@ -5705,18 +5751,6 @@ idle_trylock (TryLockData *data)
 }
 
 /*
- * This method is useful only in a multi threading environment (it has no effect in a
- * single thread program).
- * Locks @cnc for the current thread. If the lock can't be obtained, then the current thread
- * will be blocked until it can acquire @cnc's lock. 
- *
- * The cases when the connection can't be locked are:
- * <itemizedlist>
- *   <listitem><para>another thread is already using the connection</para></listitem>
- *   <listitem><para>the connection can only be used by a single thread (see the 
- *     <link linkend="GdaConnection--thread-owner">thread-owner</link> property)</para></listitem>
- * </itemizedlist>
- *
  * To avoid the thread being blocked (possibly forever if the single thread which can use the
  * connection is not the current thead), then it is possible to use gda_connection_trylock() instead.
  */
@@ -5725,21 +5759,18 @@ gda_connection_lock (GdaLockable *lockable)
 {
        GdaConnection *cnc = (GdaConnection *) lockable;
 
-       if (cnc->priv->provider_data) {
-               /* connection is opened */
-               g_assert (cnc->priv->provider_data->worker);
-               if (gda_worker_thread_is_worker (cnc->priv->provider_data->worker))
-                       /* the sitation here is that the connection _has been_ locked by the
-                        * calling thread of the GdaWorker, and as we are in the worker thread
-                        * of the GdaWorker, we don't need to lock it again: it would be useless because
-                        * by desing the connection object may be modified but only by the provider code, 
which
-                        * is Ok, and because it would require a very complex mechanism to "transfer the lock"
-                        * from one thread to the other */
-                       return;
+       if (cnc->priv->worker_thread == g_thread_self ()) {
+               /* the sitation here is that the connection _has been_ locked by the
+                * calling thread of the GdaWorker, and as we are in the worker thread
+                * of the GdaWorker, we don't need to lock it again: it would be useless because
+                * by desing the connection object may be modified but only by the provider code, which
+                * is Ok, and because it would require a very complex mechanism to "transfer the lock"
+                * from one thread to the other */
+               return;
        }
 
        GMainContext *context;
-       context = gda_connection_get_main_context (cnc);
+       context = gda_connection_get_main_context (cnc, NULL);
        if (context) {
                if (gda_connection_trylock (lockable))
                        return;
@@ -5754,7 +5785,7 @@ gda_connection_lock (GdaLockable *lockable)
 
                GSource *idle;
                idle = g_idle_source_new ();
-               g_source_set_priority (idle, G_PRIORITY_HIGH);
+               g_source_set_priority (idle, G_PRIORITY_DEFAULT);
                g_source_attach (idle, context);
                g_source_set_callback (idle, (GSourceFunc) idle_trylock, &lockdata, NULL);
                g_source_unref (idle);
@@ -5777,12 +5808,9 @@ gda_connection_trylock (GdaLockable *lockable)
 {
        GdaConnection *cnc = (GdaConnection *) lockable;
 
-       if (cnc->priv->provider_data) {
-               /* connection is opened */
-               g_assert (cnc->priv->provider_data->worker);
-               if (gda_worker_thread_is_worker (cnc->priv->provider_data->worker))
-                       /* See gda_connection_lock() for explanations */
-                       return TRUE;
+       if (cnc->priv->worker_thread == g_thread_self ()) {
+               /* See gda_connection_lock() for explanations */
+               return TRUE;
        }
 
        return g_rec_mutex_trylock (& cnc->priv->rmutex);
@@ -5797,12 +5825,9 @@ gda_connection_unlock  (GdaLockable *lockable)
 {
        GdaConnection *cnc = (GdaConnection *) lockable;
 
-       if (cnc->priv->provider_data) {
-               /* connection is opened */
-               if (cnc->priv->provider_data->worker &&
-                   gda_worker_thread_is_worker (cnc->priv->provider_data->worker))
-                       /* See gda_connection_lock() for explanations */
-                       return;
+       if (cnc->priv->worker_thread == g_thread_self ()) {
+               /* See gda_connection_lock() for explanations */
+               return;
        }
 
        g_rec_mutex_unlock (& cnc->priv->rmutex);
diff --git a/libgda/gda-connection.h b/libgda/gda-connection.h
index dead156..149faee 100644
--- a/libgda/gda-connection.h
+++ b/libgda/gda-connection.h
@@ -268,8 +268,8 @@ gboolean             gda_connection_is_opened            (GdaConnection *cnc);
 
 GdaConnectionOptions gda_connection_get_options          (GdaConnection *cnc);
 
-void                 gda_connection_set_main_context     (GdaConnection *cnc, GMainContext *context);
-GMainContext        *gda_connection_get_main_context     (GdaConnection *cnc);
+void                 gda_connection_set_main_context     (GdaConnection *cnc, GThread *thread, GMainContext 
*context);
+GMainContext        *gda_connection_get_main_context     (GdaConnection *cnc, GThread *thread);
 
 GdaServerProvider   *gda_connection_get_provider         (GdaConnection *cnc);
 const gchar         *gda_connection_get_provider_name    (GdaConnection *cnc);
@@ -369,6 +369,10 @@ GdaDataModel        *gda_connection_get_meta_store_data  (GdaConnection *cnc, Gd
                                                          GError **error, gint nb_filters, ...);
 GdaDataModel        *gda_connection_get_meta_store_data_v(GdaConnection *cnc, GdaConnectionMetaType 
meta_type,
                                                          GList* filters, GError **error);
+
+//void                 gda_connection_lock_with_context (GdaConnection *cnc, GMainContext *context);
+//void                 gda_connection_unlock (GdaConnection *cnc);
+
 G_END_DECLS
 
 #endif
diff --git a/libgda/gda-server-provider.c b/libgda/gda-server-provider.c
index 2b9b9c3..c03f76b 100644
--- a/libgda/gda-server-provider.c
+++ b/libgda/gda-server-provider.c
@@ -514,7 +514,7 @@ GMainContext *
 _gda_server_provider_get_real_main_context (GdaConnection *cnc)
 {
        GMainContext *context;
-       context = gda_connection_get_main_context (cnc);
+       context = gda_connection_get_main_context (cnc, NULL);
        if (context)
                g_main_context_ref (context);
        else
@@ -2132,7 +2132,7 @@ _gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection
        g_return_val_if_fail ((cb_func && out_job_id) || (!cb_func && !out_job_id), FALSE);
 
        GMainContext *context;
-       context = gda_connection_get_main_context (cnc);
+       context = gda_connection_get_main_context (cnc, NULL);
        if (cb_func && !context) {
                g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_NO_MAIN_CONTEXT_ERROR,
                             "%s", _("You need to define a GMainContext using 
gda_connection_set_main_context()"));
@@ -2143,6 +2143,7 @@ _gda_server_provider_open_connection (GdaServerProvider *provider, GdaConnection
 
        GdaWorker *worker;
        worker = _gda_server_provider_create_worker (provider, TRUE);
+       _gda_connection_internal_set_worker_thread (cnc, gda_worker_get_worker_thread (worker));
 
        /* define callback if not yet done */
        if (cb_func) {
@@ -2225,6 +2226,7 @@ static void
 WorkerCloseConnectionData_free (WorkerCloseConnectionData *data)
 {
        //g_print ("%s() th %p %s\n", __FUNCTION__, g_thread_self(), gda_worker_thread_is_worker 
(data->worker) ? "Thread Worker" : "NOT thread worker");
+       _gda_connection_internal_set_worker_thread (data->cnc, NULL);
        gda_worker_unref (data->worker);
        g_object_unref (data->cnc);
        g_slice_free (WorkerCloseConnectionData, data);
diff --git a/libgda/test-cnc-exec.c b/libgda/test-cnc-exec.c
index c7b75ea..795e3e9 100644
--- a/libgda/test-cnc-exec.c
+++ b/libgda/test-cnc-exec.c
@@ -20,6 +20,7 @@
 #include <glib/gstdio.h>
 
 static guint test1 (void);
+static guint test2 (void);
 
 
 int main(int argc, const char *argv[])
@@ -28,6 +29,7 @@ int main(int argc, const char *argv[])
        guint nfailed = 0;
 
        nfailed += test1 ();
+       nfailed += test2 ();
 
        if (nfailed > 0)
                g_print ("Test failed %u times\n", nfailed);
@@ -43,19 +45,25 @@ idle_incr (guint *ptr)
        return TRUE;
 }
 
+/*
+ * Pass %0 as interval to use an idle function
+ */
 static void
-setup_main_context (GdaConnection *cnc, guint *ptr_to_incr)
+setup_main_context (GdaConnection *cnc, guint interval, guint *ptr_to_incr)
 {
        GMainContext *context;
        GSource *idle;
 
        context = g_main_context_new ();
-       idle = g_idle_source_new ();
+       if (interval == 0)
+               idle = g_idle_source_new ();
+       else
+               idle = g_timeout_source_new (interval);
        g_source_set_priority (idle, G_PRIORITY_DEFAULT);
        g_source_attach (idle, context);
        g_source_set_callback (idle, (GSourceFunc) idle_incr, ptr_to_incr, NULL);
        g_source_unref (idle);
-       gda_connection_set_main_context (cnc, context);
+       gda_connection_set_main_context (cnc, NULL, context);
        g_main_context_unref (context); 
 }
 
@@ -84,7 +92,7 @@ test1 (void)
        }
 
        guint counter = 0;
-       setup_main_context (cnc, &counter);
+       setup_main_context (cnc, 0, &counter);
 
        /* connection open */
        if (! gda_connection_open (cnc, &error)) {
@@ -140,3 +148,98 @@ test1 (void)
 
        return 0;
 }
+
+/*
+ * Test 2:
+ */
+static gpointer
+test2_th (GdaConnection *cnc)
+{
+       /* setup main context */
+       guint counter = 0;
+       setup_main_context (cnc, 100, &counter);
+
+       gda_lockable_lock (GDA_LOCKABLE (cnc));
+       g_usleep (200000);
+       gda_lockable_unlock (GDA_LOCKABLE (cnc));
+       g_thread_yield ();
+
+       gda_lockable_lock (GDA_LOCKABLE (cnc));
+       g_usleep (200000);
+       gda_lockable_unlock (GDA_LOCKABLE (cnc));
+       g_thread_yield ();
+
+       gda_lockable_lock (GDA_LOCKABLE (cnc));
+       g_usleep (200000);
+       gda_lockable_unlock (GDA_LOCKABLE (cnc));
+       g_thread_yield ();
+
+       gda_lockable_lock (GDA_LOCKABLE (cnc));
+       g_usleep (200000);
+       gda_lockable_unlock (GDA_LOCKABLE (cnc));
+
+       guint *ret;
+       ret = g_new (guint, 1);
+       *ret = counter;
+       return ret;
+}
+
+static guint
+test2 (void)
+{
+       g_print ("============= %s started =============\n", __FUNCTION__);
+       GdaConnection *cnc;
+       GError *error = NULL;
+
+       gchar *cnc_string, *fname;
+        fname = g_build_filename (ROOT_DIR, "data", NULL);
+        cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=sales_test", fname);
+        g_free (fname);
+        cnc = gda_connection_new_from_string ("SQLite", cnc_string, NULL,
+                                             GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+       if (!cnc) {
+               g_print ("gda_connection_new_from_string([%s]) failed: %s\n", cnc_string,
+                        error && error->message ? error->message : "No detail");
+               g_free (cnc_string);
+               return 1;
+       }
+
+       /* connection open */
+       if (! gda_connection_open (cnc, &error)) {
+               g_print ("gda_connection_open([%s]) failed: %s\n", cnc_string,
+                        error && error->message ? error->message : "No detail");
+               g_free (cnc_string);
+               return 1;
+       }
+       g_free (cnc_string);
+
+       GThread *tha, *thb;
+
+       tha = g_thread_new ("thA", (GThreadFunc) test2_th, cnc);
+       thb = g_thread_new ("thB", (GThreadFunc) test2_th, cnc);
+       g_print ("Thread A is %p\n", tha);
+       g_print ("Thread B is %p\n", thb);
+
+       guint *counter;
+       counter = g_thread_join (tha);
+       if (*counter == 0) {
+               g_print ("Thread A: gda_connection_lock() failed: did not make GMainContext 'run'\n");
+               return 1;
+       }
+       else
+               g_print ("Thread A: Counter incremented to %u\n", *counter);
+       g_free (counter);
+
+       counter = g_thread_join (thb);
+       if (*counter == 0) {
+               g_print ("Thread B: gda_connection_lock() failed: did not make GMainContext 'run'\n");
+               return 1;
+       }
+       else
+               g_print ("Thread B: Counter incremented to %u\n", *counter);
+       g_free (counter);
+
+       g_object_unref (cnc);
+
+       return 0;
+}
diff --git a/libgda/test-cnc-meta.c b/libgda/test-cnc-meta.c
index 885ad8a..7f59930 100644
--- a/libgda/test-cnc-meta.c
+++ b/libgda/test-cnc-meta.c
@@ -55,7 +55,7 @@ setup_main_context (GdaConnection *cnc, guint *ptr_to_incr)
        g_source_attach (idle, context);
        g_source_set_callback (idle, (GSourceFunc) idle_incr, ptr_to_incr, NULL);
        g_source_unref (idle);
-       gda_connection_set_main_context (cnc, context);
+       gda_connection_set_main_context (cnc, NULL, context);
        g_main_context_unref (context); 
 }
 
diff --git a/libgda/test-cnc-open.c b/libgda/test-cnc-open.c
index 1b0f66c..c3b083a 100644
--- a/libgda/test-cnc-open.c
+++ b/libgda/test-cnc-open.c
@@ -23,6 +23,7 @@ static guint test1 (void);
 static guint test2 (void);
 static guint test3 (void);
 static guint test4 (void);
+static guint test5 (void);
 
 
 int main(int argc, const char *argv[])
@@ -34,6 +35,7 @@ int main(int argc, const char *argv[])
        nfailed += test2 ();
        nfailed += test3 ();
        nfailed += test4 ();
+       nfailed += test5 ();
 
        g_unlink ("test-cnc-opendb.db");
 
@@ -63,7 +65,7 @@ setup_main_context (GdaConnection *cnc, guint *ptr_to_incr)
        g_source_attach (idle, context);
        g_source_set_callback (idle, (GSourceFunc) idle_incr, ptr_to_incr, NULL);
        g_source_unref (idle);
-       gda_connection_set_main_context (cnc, context);
+       gda_connection_set_main_context (cnc, NULL, context);
        g_main_context_unref (context); 
 }
 
@@ -136,7 +138,7 @@ test2 (void)
        setup_main_context (cnc, &counter);
 
        GMainLoop *loop;
-       loop = g_main_loop_new (gda_connection_get_main_context (cnc), FALSE);
+       loop = g_main_loop_new (gda_connection_get_main_context (cnc, NULL), FALSE);
 
        guint job_id;
        job_id = gda_connection_open_async (cnc, (GdaConnectionOpenFunc) test2_open_func, loop, &error);
@@ -236,7 +238,7 @@ test4 (void)
        setup_main_context (cnc, &counter);
 
        GMainLoop *loop;
-       loop = g_main_loop_new (gda_connection_get_main_context (cnc), FALSE);
+       loop = g_main_loop_new (gda_connection_get_main_context (cnc, NULL), FALSE);
 
        guint job_id;
        job_id = gda_connection_open_async (cnc, (GdaConnectionOpenFunc) test4_open_func, loop, &error);
@@ -264,3 +266,66 @@ test4 (void)
 
        return opened ? 1 : 0;
 }
+
+/*
+ * Test 5: open, close and open again
+ */
+static guint
+test5 (void)
+{
+       g_print ("============= %s started =============\n", __FUNCTION__);
+       GdaConnection *cnc;
+       GError *error = NULL;
+       cnc = gda_connection_new_from_string ("SQLite", "DB_NAME=test-cnc-opendb", NULL,
+                                             GDA_CONNECTION_OPTIONS_AUTO_META_DATA, &error);
+
+       if (!cnc) {
+               g_print ("gda_connection_new_from_string() failed: %s\n", error && error->message ? 
error->message : "No detail");
+               return 1;
+       }
+
+       guint counter = 0;
+       setup_main_context (cnc, &counter);
+
+       /* open */
+       if (! gda_connection_open (cnc, &error)) {
+               g_print ("gda_connection_open() 1 failed: %s\n", error && error->message ? error->message : 
"No detail");
+               return 1;
+       }
+       if (counter == 0) {
+               g_print ("gda_connection_open() 1 failed: did not make GMainContext 'run'\n");
+               return 1;
+       }
+       else
+               g_print ("Counter incremented to %u\n", counter);
+
+       /* open */
+       counter = 0;
+       if (! gda_connection_close (cnc, &error)) {
+               g_print ("gda_connection_close() failed: %s\n", error && error->message ? error->message : 
"No detail");
+               return 1;
+       }
+       if (counter == 0) {
+               g_print ("gda_connection_close() failed: did not make GMainContext 'run'\n");
+               return 1;
+       }
+       else
+               g_print ("Counter incremented to %u\n", counter);
+
+       /* open */
+       counter = 0;
+       if (! gda_connection_open (cnc, &error)) {
+               g_print ("gda_connection_open() 2 failed: %s\n", error && error->message ? error->message : 
"No detail");
+               return 1;
+       }
+       if (counter == 0) {
+               g_print ("gda_connection_open() 2 failed: did not make GMainContext 'run'\n");
+               return 1;
+       }
+       else
+               g_print ("Counter incremented to %u\n", counter);
+
+       g_object_unref (cnc);
+
+       return 0;
+}
diff --git a/libgda/thread-wrapper/gda-worker.c b/libgda/thread-wrapper/gda-worker.c
index a6af91d..85c3ec7 100644
--- a/libgda/thread-wrapper/gda-worker.c
+++ b/libgda/thread-wrapper/gda-worker.c
@@ -1014,3 +1014,20 @@ gda_worker_thread_is_worker (GdaWorker *worker)
        g_return_val_if_fail (worker, NULL);
        return worker->worker_thread == g_thread_self () ? TRUE : FALSE;
 }
+
+/**
+ * gda_worker_get_worker_thread:
+ * @worker: a #GdaWorker
+ *
+ * Get a pointer to @worker's inner worker thread
+ *
+ * Returns: (transfer none): the #GThread
+ *
+ * Since: 6.0
+ */
+GThread *
+gda_worker_get_worker_thread (GdaWorker *worker)
+{
+       g_return_val_if_fail (worker, NULL);
+       return worker->worker_thread;
+}
diff --git a/libgda/thread-wrapper/gda-worker.h b/libgda/thread-wrapper/gda-worker.h
index a34b44c..f1451cb 100644
--- a/libgda/thread-wrapper/gda-worker.h
+++ b/libgda/thread-wrapper/gda-worker.h
@@ -106,6 +106,7 @@ gboolean   gda_worker_set_callback (GdaWorker *worker, GMainContext *context, Gd
                                    gpointer user_data, GError **error);
 
 gboolean   gda_worker_thread_is_worker (GdaWorker *worker);
+GThread   *gda_worker_get_worker_thread (GdaWorker *worker);
 
 G_END_DECLS
 


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