GdaThreadWrapper

## GdaThreadWrapper GdaThreadWrapper — Execute functions in a sub thread |

## Stability Level

Stable, unless otherwise indicated

## Synopsis

    #include <libgda/thread-wrapper/gda-thread-wrapper.h>

    struct              GdaThreadWrapper;
    GdaThreadWrapper *  gda_thread_wrapper_new              (void);
                        GdaThreadNotification;
    enum                GdaThreadNotificationType;
    GIOChannel *        gda_thread_wrapper_get_io_channel   (GdaThreadWrapper *wrapper);
    void                gda_thread_wrapper_unset_io_channel (GdaThreadWrapper *wrapper);
    gpointer            (*GdaThreadWrapperFunc)             (gpointer arg,
                                                             GError **error);
    guint               gda_thread_wrapper_execute          (GdaThreadWrapper *wrapper,
                                                             GdaThreadWrapperFunc func,
                                                             gpointer arg,
                                                             GDestroyNotify arg_destroy_func,
                                                             GError **error);
    void                (*GdaThreadWrapperVoidFunc)         (gpointer arg,
                                                             GError **error);
    guint               gda_thread_wrapper_execute_void     (GdaThreadWrapper *wrapper,
                                                             GdaThreadWrapperVoidFunc func,
                                                             gpointer arg,
                                                             GDestroyNotify arg_destroy_func,
                                                             GError **error);
    gboolean            gda_thread_wrapper_cancel           (GdaThreadWrapper *wrapper,
                                                             guint id);
    void                gda_thread_wrapper_iterate          (GdaThreadWrapper *wrapper,
                                                             gboolean may_block);
    gpointer            gda_thread_wrapper_fetch_result     (GdaThreadWrapper *wrapper,
                                                             gboolean may_lock,
                                                             guint exp_id,
                                                             GError **error);
    gint                gda_thread_wrapper_get_waiting_size (GdaThreadWrapper *wrapper);
    void                (*GdaThreadWrapperCallback)         (GdaThreadWrapper *wrapper,
                                                             gpointer instance,
                                                             const gchar *signame,
                                                             gint n_param_values,
                                                             const GValue *param_values,
                                                             gpointer gda_reserved,
                                                             gpointer data);
    gulong              gda_thread_wrapper_connect_raw      (GdaThreadWrapper *wrapper,
                                                             gpointer instance,
                                                             const gchar *sig_name,
                                                             gboolean private_thread,
                                                             gboolean private_job,
                                                             GdaThreadWrapperCallback callback,
                                                             gpointer data);
    void                gda_thread_wrapper_disconnect       (GdaThreadWrapper *wrapper,
                                                             gulong id);
    void                gda_thread_wrapper_steal_signal     (GdaThreadWrapper *wrapper,
                                                             gulong id);

## Object Hierarchy

      GObject
       +----GdaThreadWrapper

## Description

The purpose of the GdaThreadWrapper object is to execute functions in an isolated sub thread. As the GdaThreadWrapper is thread safe, one is able to isolate some code's execution is a private worker thread, and make a non thread safe code thread safe.

The downside of this is that the actual execution of the code will be slower as it requires threads to be synchronized.

The GdaThreadWrapper implements its own locking mechanism and can safely be used from multiple threads at once without needing further locking.

Each thread using a GdaThreadWrapper object can use it as if it was the only user: the GdaThreadWrapper will simply dispatch all the execution requests to its private worker thread and report the execution's status only to the thread which made the request.

The user can also specify a callback function to be called when an object exmits a signal while being used by the worker thread, see the `gda_thread_wrapper_connect_raw()` method.

The following diagram illustrates the conceptual working of the GdaThreadWrapper object: here two user threads are represented (assigned a red and green colors), both using a single GdaThreadWrapper, so in this diagram, 3 threads are present. The communication between the threads are handled by some GAsyncQueue objects (in a transparent way for the user, presented here only for illustration purposes). The queue represented in yellow is where jobs are pushed by each user thread (step 1), and popped by the worker thread (step 2). Once the worker thread has finished with a job, it stores the result along with the job and pushes it to the queue dedicated to the user thread (step 3) in this example the red queue (because the job was issued from the thread represented in red). The last step is when the user fetches the result (in its user thread), step 4.

If, when the worker thread is busy with a job, a signal is emitted, and if the user has set up a signal handler using `gda_thread_wrapper_connect_raw()`, then a "job as signal" is created by the worker thread and pushed to the user thread as illustrated at the bottom of the diagram.

It's the user's responsability to regularly check if a submitted job has completed (using `gda_thread_wrapper_fetch_result()`) or if a signal has been emitted by an object while in the worker thread and needs to be handled by the GdaThreadWrapper to call the associated callback (using `gda_thread_wrapper_iterate()` or automatically done when calling `gda_thread_wrapper_fetch_result()`).

However, when a main loop is available, the GdaThreadWrapper can emit notifications through a GIOChannel which can be intregated in the main loop. The GIOChannel can be created using `gda_thread_wrapper_get_io_channel()`.

The purpose of the GdaThreadWrapper object is to execute functions in an isolated sub thread. As the GdaThreadWrapper is thread safe, one is able to isolate some code's execution is a private worker thread, and make a non thread safe code thread safe.

The downside of this is that the actual execution of the code will be slower as it requires threads to be synchronized.

The GdaThreadWrapper implements its own locking mechanism and can safely be used from multiple threads at once without needing further locking.

Each thread using a GdaThreadWrapper object can use it as if it was the only user: the GdaThreadWrapper will simply dispatch all the execution requests to its private worker thread and report the execution's status only to the thread which made the request.

The user can also specify a callback function to be called when an object exmits a signal while being used by the worker thread, see the `gda_thread_wrapper_connect_raw()` method.

The following diagram illustrates the conceptual working of the GdaThreadWrapper object: here two user threads are represented (assigned a red and green colors), both using a single GdaThreadWrapper, so in this diagram, 3 threads are present. The communication between the threads are handled by some GAsyncQueue objects (in a transparent way for the user, presented here only for illustration purposes). The queue represented in yellow is where jobs are pushed by each user thread (step 1), and popped by the worker thread (step 2). Once the user thread has finished with a job, it stores the result along with the job and pushes it to the queue dedicated to the user thread (step 3) in this example the red queue (because the job was issued from the thread represented in red). The last step is when the user fetches the result (in its user thread), step 4.

If, when the worker thread is busy with a job, a signal is emitted, and if the user has set up a signal handler using `gda_thread_wrapper_connect_raw()`, then a "job as signal" is created by the worker thread and pushed to the user thread as illustrated at the bottom of the diagram.

## Details

### struct GdaThreadWrapper

    struct GdaThreadWrapper;

### gda_thread_wrapper_new ()

    GdaThreadWrapper *  gda_thread_wrapper_new              (void);

Creates a new GdaThreadWrapper object

Returns : | a new GdaThreadWrapper object, or `NULL` if threads are not supported/enabled

Since 4.2

### GdaThreadNotification

    typedef struct {
    	GdaThreadNotificationType type;
    	guint                     job_id;
    } GdaThreadNotification;

A notification to be read through the GIOChannel which is returned by `gda_thread_wrapper_get_io_channel()`, for example:

    gboolean
    wrapper_ioc_cb (GIOChannel *source, GIOCondition condition, gpointer data)
    {
        GIOStatus status;
        gsize nread;
        GdaThreadNotification notif;
        if (condition & G_IO_IN) {
       status = g_io_channel_read_chars (source, (gchar*) &notif, sizeof (notif), &nread, NULL);
            if ((status != G_IO_STATUS_NORMAL) || (nread != sizeof (notif)))
                goto onerror;
       switch (notif.type) {
       case GDA_THREAD_NOTIFICATION_JOB:
                check_for_wrapper_result (bcnc);
                break;
            case GDA_THREAD_NOTIFICATION_SIGNAL:
                gda_thread_wrapper_iterate (bcnc->priv->wrapper, FALSE);
                break;
            default:
                goto onerror;
                break;
       }
      }
      if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
                goto onerror;
      return TRUE; // keep callback

    onerror:
      g_io_channel_shutdown (bcnc->priv->ioc, FALSE, NULL);
      return FALSE; // removed callback
    }

    {
    [...]
        GIOChannel *ioc;
        ioc = gda_thread_wrapper_get_io_channel (wrapper);
        if (!ioc)
            [handle error]
        else {
            guint watch_id;
            watch_id = g_io_add_watch (ioc, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                                       (GIOFunc) wrapper_ioc_cb, NULL);
        }
    }

GdaThreadNotificationType `type`; | the notification type
guint `job_id`; | the job ID, if `type` is a GDA_THREAD_NOTIFICATION_JOB

### enum GdaThreadNotificationType

    typedef enum {
    	GDA_THREAD_NOTIFICATION_JOB    = 0x01,
    	GDA_THREAD_NOTIFICATION_SIGNAL = 0x02
    } GdaThreadNotificationType;

Defines the kind of notification which can be obtained when reading from te GIOChannel returned by `gda_thread_wrapper_get_io_channel()`.

`GDA_THREAD_NOTIFICATION_JOB` | the notification regards a job finished
`GDA_THREAD_NOTIFICATION_SIGNAL` | the notification regards a signal

### gda_thread_wrapper_get_io_channel ()

    GIOChannel *        gda_thread_wrapper_get_io_channel   (GdaThreadWrapper *wrapper);

Allow `wrapper` to notify when an execution job is finished, by making its exec ID readable through a new GIOChannel. This function is useful when the notification needs to be included into a main loop. This also notifies that signals (emitted by objects in `wrapper`'s internal thread) are available.

The returned GIOChannel will have something to read everytime an execution job is finished for an execution job submitted from the calling thread. The user whould read GdaThreadNotification structures from the channel and analyse its contents to call `gda_thread_wrapper_iterate()` or `gda_thread_wrapper_fetch_result()`.

Note1: the new communication channel will only be operational for jobs submitted after this function returns, and for signals which have been connected after this function returns. A safe practice is to call this function before the `wrapper` object has been used.

Note2: this function will return the same GIOChannel everytime it's called from the same thread.

Note3: if the usage of the returned GIOChannel reveals an error, then `g_io_channel_shutdown()` and `g_io_channel_unref()` should be called on the GIOChannel to let `wrapper` know it should not use that object anymore.

`wrapper` : | a GdaThreadWrapper object
Returns : | a new GIOChannel, or `NULL` if it could not be created. [transfer none]

Since 4.2.9

### gda_thread_wrapper_unset_io_channel ()

    void                gda_thread_wrapper_unset_io_channel (GdaThreadWrapper *wrapper);

Does the opposite of `gda_thread_wrapper_get_io_channel()`

`wrapper` : | a GdaThreadWrapper

Since 4.2.9

### GdaThreadWrapperFunc ()

    gpointer            (*GdaThreadWrapperFunc)             (gpointer arg,
                                                             GError **error);

Specifies the type of function to be passed to `gda_thread_wrapper_execute()`.

Specifies the type of function to be passed to `gda_thread_wrapper_execute()`.

`arg` : | pointer to the data (which is the `arg` argument passed to `gda_thread_wrapper_execute_void()`)
`error` : | a place to store errors
Returns : | a pointer to some data which will be returned by `gda_thread_wrapper_fetch_result()`

### gda_thread_wrapper_execute ()

    guint               gda_thread_wrapper_execute          (GdaThreadWrapper *wrapper,
                                                             GdaThreadWrapperFunc func,
                                                             gpointer arg,
                                                             GDestroyNotify arg_destroy_func,
                                                             GError **error);

Make `wrapper` execute the `func` function with the `arg` argument (along with a GError which is not `error`) in the sub thread managed by `wrapper`. To execute a function which does not return anything, use `gda_thread_wrapper_execute_void()`.

This method returns immediately, and the caller then needs to use `gda_thread_wrapper_fetch_result()` to check if the execution has finished and get the result.

Once `func`'s execution is finished, if `arg` is not `NULL`, the `arg_destroy_func` destruction function is called on `arg`. This call occurs in the thread calling `gda_thread_wrapper_fetch_result()`.

`wrapper` : | a GdaThreadWrapper object
`func` : | the function to execute, not `NULL`
`arg` : | argument to pass to `func`, or `NULL`. [allow-none]
`arg_destroy_func` : | function to be called when the execution has finished, to destroy `arg`, or `NULL`. [allow-none]
`error` : | a place to store errors, for errors occurring in this method, not errors occurring while `func` is executed, or `NULL`
Returns : | the job ID, or 0 if an error occurred

Since 4.2

### GdaThreadWrapperVoidFunc ()

    void                (*GdaThreadWrapperVoidFunc)         (gpointer arg,
                                                             GError **error);

Specifies the type of function to be passed to `gda_thread_wrapper_execute_void()`.

`arg` : | a pointer to the data (which is the `arg` argument passed to `gda_thread_wrapper_execute_void()`)
`error` : | a place to store errors

### gda_thread_wrapper_execute_void ()

    guint               gda_thread_wrapper_execute_void     (GdaThreadWrapper *wrapper,
                                                             GdaThreadWrapperVoidFunc func,
                                                             gpointer arg,
                                                             GDestroyNotify arg_destroy_func,
                                                             GError **error);

Make `wrapper` execute the `func` function with the `arg` argument (along with a GError which is not `error`) in the sub thread managed by `wrapper`. To execute a function which returns some pointer, use `gda_thread_wrapper_execute()`.

This method returns immediately. Calling `gda_thread_wrapper_fetch_result()` is not necessary as `func` does not return any result. However, it may be necessary to call `gda_thread_wrapper_iterate()` to give `wrapper` a chance to execute the `arg_destroy_func` function if not `NULL` (note that `gda_thread_wrapper_iterate()` is called by `gda_thread_wrapper_fetch_result()` itself).

Once `func`'s execution is finished, if `arg` is not `NULL`, the `arg_destroy_func` destruction function is called on `arg`. This call occurs in the thread calling `gda_thread_wrapper_fetch_result()`.

`wrapper` : | a GdaThreadWrapper object
`func` : | the function to execute, not `NULL`
`arg` : | argument to pass to `func`. [allow-none]
`arg_destroy_func` : | function to be called when the execution has finished, to destroy `arg`, or `NULL`. [allow-none]
`error` : | a place to store errors, for errors occurring in this method, not errors occurring while `func` is executed, or `NULL`
Returns : | the job ID, or 0 if an error occurred

Since 4.2

### gda_thread_wrapper_cancel ()

    gboolean            gda_thread_wrapper_cancel           (GdaThreadWrapper *wrapper,
                                                             guint id);

Cancels a job not yet executed. This may fail for the following reasons:

- the job `id` could not be found, either because it has already been treated or because it does not exist or because it was created in another thread

- the job `id` is currently being treated by the worker thread

`wrapper` : | a GdaThreadWrapper object
`id` : | the ID of a job as returned by `gda_thread_wrapper_execute()` or `gda_thread_wrapper_execute_void()`
Returns : | `TRUE` if the job has been cancelled, or `FALSE` in any other case.

Since 4.2

### gda_thread_wrapper_iterate ()

    void                gda_thread_wrapper_iterate          (GdaThreadWrapper *wrapper,
                                                             gboolean may_block);

This method gives `wrapper` a chance to check if some functions to be executed have finished for the calling thread. In this case it handles the execution result and makes it ready to be processed using `gda_thread_wrapper_fetch_result()`.

This method also allows `wrapper` to handle signals which may have been emitted by objects while in the worker thread, and call the callback function specified when `gda_thread_wrapper_connect_raw()` was used.

If `may_block` is `TRUE`, then it will block untill there is one finished execution (functions returning void and signals are ignored regarding this argument).

`wrapper` : | a GdaThreadWrapper object
`may_block` : | whether the call may block

Since 4.2

### gda_thread_wrapper_fetch_result ()

    gpointer            gda_thread_wrapper_fetch_result     (GdaThreadWrapper *wrapper,
                                                             gboolean may_lock,
                                                             guint exp_id,
                                                             GError **error);

Use this method to check if the execution of a function is finished. The function's execution must have been requested using `gda_thread_wrapper_execute()`.

`wrapper` : | a GdaThreadWrapper object
`may_lock` : | TRUE if this funct must lock the caller untill a result is available
`exp_id` : | ID of the job for which a result is expected
`error` : | a place to store errors, for errors which may have occurred during the execution, or `NULL`
Returns : | the pointer returned by the execution, or `NULL` if no result is available. [transfer none][allow-none]

Since 4.2

### gda_thread_wrapper_get_waiting_size ()

    gint                gda_thread_wrapper_get_waiting_size (GdaThreadWrapper *wrapper);

Use this method to query the number of functions which have been queued to be executed but which have not yet been executed.

`wrapper` : | a GdaThreadWrapper object
Returns : | the number of jobs not yet executed

Since 4.2

### GdaThreadWrapperCallback ()

    void                (*GdaThreadWrapperCallback)         (GdaThreadWrapper *wrapper,
                                                             gpointer instance,
                                                             const gchar *signame,
                                                             gint n_param_values,
                                                             const GValue *param_values,
                                                             gpointer gda_reserved,
                                                             gpointer data);

Specifies the type of function to be passed to `gda_thread_wrapper_connect_raw()`.

`wrapper` : | the GdaThreadWrapper
`instance` : | a pointer to the instance which emitted the signal
`signame` : | the name of the signal being emitted
`n_param_values` : | number of GValue in `param_values`
`param_values` : | array of `n_param_values` GValue
`gda_reserved` : | reserved
`data` : | a pointer to the data (which is the `data` argument passed to `gda_thread_wrapper_connect_raw()`)

### gda_thread_wrapper_connect_raw ()

    gulong              gda_thread_wrapper_connect_raw      (GdaThreadWrapper *wrapper,
                                                             gpointer instance,
                                                             const gchar *sig_name,
                                                             gboolean private_thread,
                                                             gboolean private_job,
                                                             GdaThreadWrapperCallback callback,
                                                             gpointer data);

Connects a callback function to a signal for a particular object. The difference with `g_signal_connect()` and similar functions are:

- the `callback` argument is not a GCallback function, so the callback signature is not dependent on the signal itself

- the signal handler must not have to return any value

- the `callback` function will be called asynchronously, the caller may need to use `gda_thread_wrapper_iterate()` to get the notification

- if `private_job` and `private_thread` control in which case the signal is propagated.

Also note that signal handling is done asynchronously: when emitted in the worker thread, it will be "queued" to be processed in the user thread when it has the chance (when `gda_thread_wrapper_iterate()` is called directly or indirectly). The side effect is that the callback function is usually called long after the object emitting the signal has finished emitting it.

To disconnect a signal handler, don't use any of the g_signal_handler_*() functions but the `gda_thread_wrapper_disconnect()` method.

`wrapper` : | a GdaThreadWrapper object
`instance` : | the instance to connect to
`sig_name` : | a string of the form "signal-name::detail"
`private_thread` : | set to `TRUE` if `callback` is to be invoked only if the signal has been emitted while in `wrapper`'s private sub thread (ie. used when `wrapper` is executing some functions specified by `gda_thread_wrapper_execute()` or `gda_thread_wrapper_execute_void()`), and to `FALSE` if the callback is to be invoked whenever the signal is emitted, independently of the thread in which the signal is emitted.
`private_job` : | set to `TRUE` if `callback` is to be invoked only if the signal has been emitted when a job created for the calling thread is being executed, and to `FALSE` if `callback` has to be called whenever the `sig_name` signal is emitted by `instance`. Note that this argument is not taken into account if `private_thread` is set to `FALSE`.
`callback` : | a GdaThreadWrapperCallback function. [scope call]
`data` : | data to pass to `callback`'s calls. [closure]
Returns : | the handler ID

Since 4.2

### gda_thread_wrapper_disconnect ()

    void                gda_thread_wrapper_disconnect       (GdaThreadWrapper *wrapper,
                                                             gulong id);

Disconnects the emission of a signal, does the opposite of `gda_thread_wrapper_connect_raw()`.

As soon as this method returns, the callback function set when `gda_thread_wrapper_connect_raw()` was called will not be called anymore (even if the object has emitted the signal in the worker thread and this signal has not been handled in the user thread).

`wrapper` : | a GdaThreadWrapper object
`id` : | a handler ID, as returned by `gda_thread_wrapper_connect_raw()`

Since 4.2

### gda_thread_wrapper_steal_signal ()

    void                gda_thread_wrapper_steal_signal     (GdaThreadWrapper *wrapper,
                                                             gulong id);

Requests that the signal which ID is `id` (which has been obtained using `gda_thread_wrapper_connect_raw()`) be treated by the calling thread instead of by the thread in which `gda_thread_wrapper_connect_raw()` was called.

`wrapper` : | a GdaThreadWrapper object
`id` : | a signal ID

Since 4.2