static void g_tls_interaction_init (GTlsInteraction *interaction) { interaction->priv = G_TYPE_INSTANCE_GET_PRIVATE (interaction, G_TYPE_TLS_INTERACTION, GTlsInteractionPrivate); interaction->priv->context = g_main_context_ref_thread_default (); }
/** * g_io_scheduler_push_job: * @job_func: a #GIOSchedulerJobFunc. * @user_data: data to pass to @job_func * @notify: (allow-none): a #GDestroyNotify for @user_data, or %NULL * @io_priority: the <link linkend="io-priority">I/O priority</link> * of the request. * @cancellable: optional #GCancellable object, %NULL to ignore. * * Schedules the I/O job to run in another thread. * * @notify will be called on @user_data after @job_func has returned, * regardless whether the job was cancelled or has run to completion. * * If @cancellable is not %NULL, it can be used to cancel the I/O job * by calling g_cancellable_cancel() or by calling * g_io_scheduler_cancel_all_jobs(). * * Deprecated: use #GThreadPool or g_task_run_in_thread() **/ void g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, gpointer user_data, GDestroyNotify notify, gint io_priority, GCancellable *cancellable) { GIOSchedulerJob *job; GTask *task; g_return_if_fail (job_func != NULL); job = g_slice_new0 (GIOSchedulerJob); job->job_func = job_func; job->data = user_data; job->destroy_notify = notify; if (cancellable) job->cancellable = g_object_ref (cancellable); job->context = g_main_context_ref_thread_default (); G_LOCK (active_jobs); active_jobs = g_list_prepend (active_jobs, job); job->active_link = active_jobs; G_UNLOCK (active_jobs); task = g_task_new (NULL, cancellable, NULL, NULL); g_task_set_task_data (task, job, (GDestroyNotify)g_io_job_free); g_task_set_priority (task, io_priority); g_task_run_in_thread (task, io_job_thread); g_object_unref (task); }
/** * gda_worker_submit_job: (skip) * @worker: a #GdaWorker object * @callback_context: (allow-none): a #GMainContext, or %NULL (ignored if no setting has been defined with gda_worker_set_callback()) * @func: the function to call from the worker thread * @data: (allow-none): the data to pass to @func, or %NULL * @data_destroy_func: (allow-none): a function to destroy @data, or %NULL * @result_destroy_func: (allow-none): a function to destroy the result, if any, of the execution of @func, or %NULL * @error: (allow-none): a place to store errors, or %NULL. * * Request that the worker thread call @func with the @data argument. * * Notes: * <itemizedlist> * <listitem><para>if @data_destroy_func is not %NULL, then it will be called to destroy @data when the job is removed, * which can occur within the context of the worker thread, or within the context of any thread using @worker.</para></listitem> * <listitem><para>if @result_destroy_func is not %NULL, then it will be called to destroy the result produced by @func. * Similarly to @data_destroy_func, if it is not %NULL (and if there is a non %NULL result), then that function can be * called in the context of any thread.</para></listitem> * <listitem><para>the error here can only report failures while executing gda_worker_submit_job(), not any error which may occur * while executing @func from the worker thread.</para></listitem> * <listitem><para>when this function returns, the job may already have been completed, so you should not assume that the job * is in any specific state.</para></listitem> * <listitem><para>passing %NULL for @callback_context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem> * </itemizedlist> * * Returns: a job ID, or %0 if an error occurred * * Since: 6.0 */ guint gda_worker_submit_job (GdaWorker *worker, GMainContext *callback_context, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, GDestroyNotify result_destroy_func, GError **error) { g_return_val_if_fail (worker, 0); g_return_val_if_fail (func, 0); if (!worker->callbacks_hash) { g_warning ("GdaWorker has been destroyed\n"); return 0; } DeclaredCallback *dc; guint jid; GMainContext *co; gboolean unref_co = FALSE; co = callback_context; if (!co) { co = g_main_context_ref_thread_default (); unref_co = TRUE; } g_rec_mutex_lock (& worker->rmutex); dc = g_hash_table_lookup (worker->callbacks_hash, co); jid = _gda_worker_submit_job_with_its (worker, dc ? dc->its : NULL, func, data, data_destroy_func, result_destroy_func, error); g_rec_mutex_unlock (& worker->rmutex); if (unref_co) g_main_context_unref (co); return jid; }
GumScriptTask * gum_script_task_new (GumScriptTaskFunc func, gpointer source_object, GCancellable * cancellable, GAsyncReadyCallback callback, gpointer callback_data) { GumScriptTask * task; GumScriptTaskPrivate * priv; task = g_object_new (GUM_TYPE_SCRIPT_TASK, NULL); priv = task->priv; priv->func = func; priv->source_object = (source_object != NULL) ? g_object_ref (source_object) : NULL; priv->cancellable = (cancellable != NULL) ? g_object_ref (cancellable) : NULL; priv->callback = callback; priv->callback_data = callback_data; priv->context = g_main_context_ref_thread_default (); return task; }
static void gst_gl_window_default_run (GstGLWindow * window) { GstGLWindowPrivate *priv = window->priv; if (g_main_context_get_thread_default ()) { if (priv->main_context) g_main_context_unref (priv->main_context); if (priv->loop) g_main_loop_unref (priv->loop); priv->main_context = g_main_context_ref_thread_default (); priv->loop = NULL; priv->alive = TRUE; } else { g_main_context_push_thread_default (priv->main_context); } g_main_loop_run (priv->loop); if (!priv->loop) { priv->alive = FALSE; g_main_context_unref (priv->main_context); priv->main_context = NULL; } else { g_main_context_pop_thread_default (priv->main_context); } }
static void cockpit_web_server_init (CockpitWebServer *server) { server->requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, cockpit_request_free, NULL); server->main_context = g_main_context_ref_thread_default (); server->ssl_exception_prefix = g_string_new (""); }
static void cockpit_stream_init (CockpitStream *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, COCKPIT_TYPE_STREAM, CockpitStreamPrivate); self->priv->in_buffer = g_byte_array_new (); self->priv->out_queue = g_queue_new (); self->priv->context = g_main_context_ref_thread_default (); }
static void do_call (Client *client, CallType call_type) { GMainContext *current_context; /* only schedule in idle if we're not in the right thread */ current_context = g_main_context_ref_thread_default (); if (current_context != client->main_context) schedule_call_in_idle (client, call_type); else actually_do_call (client, client->connection, client->name_owner, call_type); g_main_context_unref (current_context); }
static void cockpit_pipe_init (CockpitPipe *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, COCKPIT_TYPE_PIPE, CockpitPipePrivate); self->priv->in_buffer = g_byte_array_new (); self->priv->in_fd = -1; self->priv->out_queue = g_queue_new (); self->priv->out_fd = -1; self->priv->err_fd = -1; self->priv->status = -1; self->priv->context = g_main_context_ref_thread_default (); }
static gboolean gst_gl_window_default_open (GstGLWindow * window, GError ** error) { GstGLWindowPrivate *priv = window->priv; if (g_main_context_get_thread_default ()) { if (priv->main_context) g_main_context_unref (priv->main_context); if (priv->loop) g_main_loop_unref (priv->loop); priv->main_context = g_main_context_ref_thread_default (); priv->loop = NULL; priv->alive = TRUE; } else { g_main_context_push_thread_default (priv->main_context); } return TRUE; }
/** * g_bus_watch_name: * @bus_type: The type of bus to watch a name on. * @name: The name (well-known or unique) to watch. * @flags: Flags from the #GBusNameWatcherFlags enumeration. * @name_appeared_handler: (nullable): Handler to invoke when @name is known to exist or %NULL. * @name_vanished_handler: (nullable): Handler to invoke when @name is known to not exist or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: (nullable): Function for freeing @user_data or %NULL. * * Starts watching @name on the bus specified by @bus_type and calls * @name_appeared_handler and @name_vanished_handler when the name is * known to have a owner respectively known to lose its * owner. Callbacks will be invoked in the * [thread-default main context][g-main-context-push-thread-default] * of the thread you are calling this function from. * * You are guaranteed that one of the handlers will be invoked after * calling this function. When you are done watching the name, just * call g_bus_unwatch_name() with the watcher id this function * returns. * * If the name vanishes or appears (for example the application owning * the name could restart), the handlers are also invoked. If the * #GDBusConnection that is used for watching the name disconnects, then * @name_vanished_handler is invoked since it is no longer * possible to access the name. * * Another guarantee is that invocations of @name_appeared_handler * and @name_vanished_handler are guaranteed to alternate; that * is, if @name_appeared_handler is invoked then you are * guaranteed that the next time one of the handlers is invoked, it * will be @name_vanished_handler. The reverse is also true. * * This behavior makes it very simple to write applications that want * to take action when a certain [name exists][gdbus-watching-names]. * Basically, the application should create object proxies in * @name_appeared_handler and destroy them again (if any) in * @name_vanished_handler. * * Returns: An identifier (never 0) that an be used with * g_bus_unwatch_name() to stop watching the name. * * Since: 2.26 */ guint g_bus_watch_name (GBusType bus_type, const gchar *name, GBusNameWatcherFlags flags, GBusNameAppearedCallback name_appeared_handler, GBusNameVanishedCallback name_vanished_handler, gpointer user_data, GDestroyNotify user_data_free_func) { Client *client; g_return_val_if_fail (g_dbus_is_name (name), 0); G_LOCK (lock); client = g_new0 (Client, 1); client->ref_count = 1; client->id = g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */ client->name = g_strdup (name); client->flags = flags; client->name_appeared_handler = name_appeared_handler; client->name_vanished_handler = name_vanished_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) { map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal); } g_hash_table_insert (map_id_to_client, GUINT_TO_POINTER (client->id), client); g_bus_get (bus_type, NULL, connection_get_cb, client_ref (client)); G_UNLOCK (lock); return client->id; }
/** * g_bus_watch_name_on_connection: * @connection: A #GDBusConnection. * @name: The name (well-known or unique) to watch. * @flags: Flags from the #GBusNameWatcherFlags enumeration. * @name_appeared_handler: (allow-none): Handler to invoke when @name is known to exist or %NULL. * @name_vanished_handler: (allow-none): Handler to invoke when @name is known to not exist or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: (allow-none): Function for freeing @user_data or %NULL. * * Like g_bus_watch_name() but takes a #GDBusConnection instead of a * #GBusType. * * Returns: An identifier (never 0) that an be used with * g_bus_unwatch_name() to stop watching the name. * * Since: 2.26 */ guint g_bus_watch_name_on_connection (GDBusConnection *connection, const gchar *name, GBusNameWatcherFlags flags, GBusNameAppearedCallback name_appeared_handler, GBusNameVanishedCallback name_vanished_handler, gpointer user_data, GDestroyNotify user_data_free_func) { Client *client; g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0); g_return_val_if_fail (g_dbus_is_name (name), 0); G_LOCK (lock); client = g_new0 (Client, 1); client->ref_count = 1; client->id = next_global_id++; /* TODO: uh oh, handle overflow */ client->name = g_strdup (name); client->flags = flags; client->name_appeared_handler = name_appeared_handler; client->name_vanished_handler = name_vanished_handler; client->user_data = user_data; client->user_data_free_func = user_data_free_func; client->main_context = g_main_context_ref_thread_default (); if (map_id_to_client == NULL) map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_insert (map_id_to_client, GUINT_TO_POINTER (client->id), client); client->connection = g_object_ref (connection); G_UNLOCK (lock); has_connection (client); return client->id; }
static void dasom_server_init (DasomServer *server) { g_debug (G_STRLOC ": %s", G_STRFUNC); GSettings *settings = g_settings_new ("org.freedesktop.Dasom"); gchar **hotkeys = g_settings_get_strv (settings, "hotkeys"); server->hotkeys = dasom_key_newv ((const gchar **) hotkeys); g_object_unref (settings); g_strfreev (hotkeys); server->candidate = dasom_candidate_new (); server->module_manager = dasom_module_manager_get_default (); server->instances = dasom_server_create_module_instances (server); server->main_context = g_main_context_ref_thread_default (); server->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_object_unref); server->agents_list = NULL; }
/** Set up the main context the session will be executing in. * * Must be called just before the session starts, by the thread which * will execute the session main loop. Once acquired, the main context * pointer is immutable for the duration of the session run. */ static int set_main_context(struct sr_session *session) { GMainContext *main_context; g_mutex_lock(&session->main_mutex); /* May happen if sr_session_start() is called a second time * while the session is still running. */ if (session->main_context) { sr_err("Main context already set."); g_mutex_unlock(&session->main_mutex); return SR_ERR; } main_context = g_main_context_ref_thread_default(); /* * Try to use an existing main context if possible, but only if we * can make it owned by the current thread. Otherwise, create our * own main context so that event source callbacks can execute in * the session thread. */ if (g_main_context_acquire(main_context)) { g_main_context_release(main_context); sr_dbg("Using thread-default main context."); } else { g_main_context_unref(main_context); sr_dbg("Creating our own main context."); main_context = g_main_context_new(); } session->main_context = main_context; g_mutex_unlock(&session->main_mutex); return SR_OK; }
gboolean ostree_repo_pull (OstreeRepo *self, const char *remote_name, char **refs_to_fetch, OstreeRepoPullFlags flags, OstreeAsyncProgress *progress, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GHashTableIter hash_iter; gpointer key, value; gboolean tls_permissive = FALSE; OstreeFetcherConfigFlags fetcher_flags = 0; gs_free char *remote_key = NULL; gs_free char *path = NULL; gs_free char *baseurl = NULL; gs_free char *summary_data = NULL; gs_unref_hashtable GHashTable *requested_refs_to_fetch = NULL; gs_unref_hashtable GHashTable *updated_refs = NULL; gs_unref_hashtable GHashTable *commits_to_fetch = NULL; gs_free char *remote_mode_str = NULL; GSource *queue_src = NULL; OtPullData pull_data_real = { 0, }; OtPullData *pull_data = &pull_data_real; SoupURI *summary_uri = NULL; GKeyFile *config = NULL; GKeyFile *remote_config = NULL; char **configured_branches = NULL; guint64 bytes_transferred; guint64 start_time; guint64 end_time; pull_data->async_error = error; pull_data->main_context = g_main_context_ref_thread_default (); pull_data->loop = g_main_loop_new (pull_data->main_context, FALSE); pull_data->flags = flags; pull_data->repo = self; pull_data->progress = progress; pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, (GDestroyNotify)g_variant_unref, NULL); pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); pull_data->requested_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); start_time = g_get_monotonic_time (); pull_data->remote_name = g_strdup (remote_name); config = ostree_repo_get_config (self); remote_key = g_strdup_printf ("remote \"%s\"", pull_data->remote_name); if (!repo_get_string_key_inherit (self, remote_key, "url", &baseurl, error)) goto out; pull_data->base_uri = soup_uri_new (baseurl); #ifdef HAVE_GPGME if (!ot_keyfile_get_boolean_with_default (config, remote_key, "gpg-verify", TRUE, &pull_data->gpg_verify, error)) goto out; #else pull_data->gpg_verify = FALSE; #endif if (!ot_keyfile_get_boolean_with_default (config, remote_key, "tls-permissive", FALSE, &tls_permissive, error)) goto out; if (tls_permissive) fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE; pull_data->fetcher = ostree_fetcher_new (pull_data->repo->tmp_dir, fetcher_flags); if (!pull_data->base_uri) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to parse url '%s'", baseurl); goto out; } if (!load_remote_repo_config (pull_data, &remote_config, cancellable, error)) goto out; if (!ot_keyfile_get_value_with_default (remote_config, "core", "mode", "bare", &remote_mode_str, error)) goto out; if (!ostree_repo_mode_from_string (remote_mode_str, &pull_data->remote_mode, error)) goto out; if (pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE_Z2) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Can't pull from archives with mode \"%s\"", remote_mode_str); goto out; } requested_refs_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); updated_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); commits_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (refs_to_fetch != NULL) { char **strviter; for (strviter = refs_to_fetch; *strviter; strviter++) { const char *branch = *strviter; char *contents; if (ostree_validate_checksum_string (branch, NULL)) { char *key = g_strdup (branch); g_hash_table_insert (commits_to_fetch, key, key); } else { if (!fetch_ref_contents (pull_data, branch, &contents, cancellable, error)) goto out; /* Transfer ownership of contents */ g_hash_table_insert (requested_refs_to_fetch, g_strdup (branch), contents); } } } else { GError *temp_error = NULL; gboolean fetch_all_refs; configured_branches = g_key_file_get_string_list (config, remote_key, "branches", NULL, &temp_error); if (configured_branches == NULL && temp_error != NULL) { if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) { g_clear_error (&temp_error); fetch_all_refs = TRUE; } else { g_propagate_error (error, temp_error); goto out; } } else fetch_all_refs = FALSE; if (fetch_all_refs) { summary_uri = soup_uri_copy (pull_data->base_uri); path = g_build_filename (soup_uri_get_path (summary_uri), "refs", "summary", NULL); soup_uri_set_path (summary_uri, path); if (!fetch_uri_contents_utf8_sync (pull_data, summary_uri, &summary_data, cancellable, error)) goto out; if (!parse_ref_summary (summary_data, &requested_refs_to_fetch, error)) goto out; } else { char **branches_iter = configured_branches; if (!(branches_iter && *branches_iter)) g_print ("No configured branches for remote %s\n", pull_data->remote_name); for (;branches_iter && *branches_iter; branches_iter++) { const char *branch = *branches_iter; char *contents; if (!fetch_ref_contents (pull_data, branch, &contents, cancellable, error)) goto out; /* Transfer ownership of contents */ g_hash_table_insert (requested_refs_to_fetch, g_strdup (branch), contents); } } } if (!ostree_repo_prepare_transaction (pull_data->repo, &pull_data->transaction_resuming, cancellable, error)) goto out; pull_data->metadata_objects_to_fetch = ot_waitable_queue_new (); pull_data->metadata_objects_to_scan = ot_waitable_queue_new (); pull_data->metadata_thread = g_thread_new ("metadatascan", metadata_thread_main, pull_data); g_hash_table_iter_init (&hash_iter, commits_to_fetch); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const char *commit = value; ot_waitable_queue_push (pull_data->metadata_objects_to_scan, pull_worker_message_new (PULL_MSG_SCAN, ostree_object_name_serialize (commit, OSTREE_OBJECT_TYPE_COMMIT))); } g_hash_table_iter_init (&hash_iter, requested_refs_to_fetch); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const char *ref = key; const char *sha256 = value; ot_waitable_queue_push (pull_data->metadata_objects_to_scan, pull_worker_message_new (PULL_MSG_SCAN, ostree_object_name_serialize (sha256, OSTREE_OBJECT_TYPE_COMMIT))); g_hash_table_insert (updated_refs, g_strdup (ref), g_strdup (sha256)); } { queue_src = ot_waitable_queue_create_source (pull_data->metadata_objects_to_fetch); g_source_set_callback (queue_src, (GSourceFunc)on_metadata_objects_to_fetch_ready, pull_data, NULL); g_source_attach (queue_src, pull_data->main_context); g_source_unref (queue_src); } /* Prime the message queue */ pull_data->idle_serial++; ot_waitable_queue_push (pull_data->metadata_objects_to_scan, pull_worker_message_new (PULL_MSG_MAIN_IDLE, GUINT_TO_POINTER (pull_data->idle_serial))); /* Now await work completion */ if (!run_mainloop_monitor_fetcher (pull_data)) goto out; g_hash_table_iter_init (&hash_iter, updated_refs); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const char *ref = key; const char *checksum = value; gs_free char *remote_ref = NULL; gs_free char *original_rev = NULL; remote_ref = g_strdup_printf ("%s/%s", pull_data->remote_name, ref); if (!ostree_repo_resolve_rev (pull_data->repo, remote_ref, TRUE, &original_rev, error)) goto out; if (original_rev && strcmp (checksum, original_rev) == 0) { g_print ("remote %s is unchanged from %s\n", remote_ref, original_rev); } else { ostree_repo_transaction_set_ref (pull_data->repo, pull_data->remote_name, ref, checksum); g_print ("remote %s is now %s\n", remote_ref, checksum); } } if (!ostree_repo_commit_transaction (pull_data->repo, NULL, cancellable, error)) goto out; end_time = g_get_monotonic_time (); bytes_transferred = ostree_fetcher_bytes_transferred (pull_data->fetcher); if (bytes_transferred > 0) { guint shift; if (bytes_transferred < 1024) shift = 1; else shift = 1024; g_print ("%u metadata, %u content objects fetched; %" G_GUINT64_FORMAT " %s transferred in %u seconds\n", pull_data->n_fetched_metadata, pull_data->n_fetched_content, (guint64)(bytes_transferred / shift), shift == 1 ? "B" : "KiB", (guint) ((end_time - start_time) / G_USEC_PER_SEC)); } ret = TRUE; out: if (pull_data->main_context) g_main_context_unref (pull_data->main_context); if (pull_data->loop) g_main_loop_unref (pull_data->loop); g_strfreev (configured_branches); g_clear_object (&pull_data->fetcher); g_free (pull_data->remote_name); if (pull_data->base_uri) soup_uri_free (pull_data->base_uri); if (queue_src) g_source_destroy (queue_src); if (pull_data->metadata_thread) { ot_waitable_queue_push (pull_data->metadata_objects_to_scan, pull_worker_message_new (PULL_MSG_QUIT, NULL)); g_thread_join (pull_data->metadata_thread); } g_clear_pointer (&pull_data->metadata_objects_to_scan, (GDestroyNotify) ot_waitable_queue_unref); g_clear_pointer (&pull_data->metadata_objects_to_fetch, (GDestroyNotify) ot_waitable_queue_unref); g_clear_pointer (&pull_data->scanned_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&remote_config, (GDestroyNotify) g_key_file_unref); if (summary_uri) soup_uri_free (summary_uri); return ret; }
/** * gda_worker_do_job: (skip) * @worker: a #GdaWorker object * @context: (allow-none): a #GMainContext to execute a main loop in (while waiting), or %NULL * @timeout_ms: the maximum number of milisecons to wait before returning, or %0 for unlimited wait * @out_result: (allow-none): a place to store the result, if any, of @func's execution, or %NULL * @out_job_id: (allow-none): a place to store the ID of the job having been submitted, or %NULL * @func: the function to call from the worker thread * @data: (allow-none): the data to pass to @func, or %NULL * @data_destroy_func: (allow-none): a function to destroy @data, or %NULL * @result_destroy_func: (allow-none): a function to destroy the result, if any, of @func's execution, or %NULL * @error: (allow-none): a place to store errors, or %NULL. * * Request that the worker thread call @func with the @data argument, much like gda_worker_submit_job(), * but waits (starting a #GMainLoop) for a maximum of @timeout_ms miliseconds for @func to be executed. * * If this function is called from within @worker's worker thread, then this function simply calls @func with @data and does not * use @context. * * The following cases are possible if this function is not called from within @worker's worker thread: * <itemizedlist> * <listitem><para>the call to @func took less than @timeout_ms miliseconds: the return value is %TRUE and * @out_result contains the result of the @func's execution, and @out_job_id contains %NULL. Note in this * case that @error may still contain an error code if @func's execution produced an error. Also note that in this case * any setting defined by gda_worker_set_callback() is not applied (as the result is immediately returned)</para></listitem> * <listitem><para>The call to @func takes more then @timeout_ms miliseconds: the return value is %TRUE and * @out_result is %NULL and @out_job_id contains the ID of the job as if it had been submitted using gda_worker_submit_job(). * If @out_job_id is %NULL, and if no setting has been defined using gda_worker_set_callback(), then the job will be discarded * (as if gda_worker_forget_job() had been called). * </para></listitem> * <listitem><para>The call to @func could not be done (some kind of plumbing error for instance): the returned value is %FALSE * and @out_result and @out_job_id are set to %NULL (if they are not %NULL)</para></listitem> * </itemizedlist> * * Notes: * <itemizedlist> * <listitem><para>@result_destroy_func is needed in case @out_result is %NULL (to avoid memory leaks)</para></listitem> * <listitem><para>passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem> * </itemizedlist> * * Returns: %TRUE if no error occurred * * Since: 6.0 */ gboolean gda_worker_do_job (GdaWorker *worker, GMainContext *context, gint timeout_ms, gpointer *out_result, guint *out_job_id, GdaWorkerFunc func, gpointer data, GDestroyNotify data_destroy_func, GDestroyNotify result_destroy_func, GError **error) { if (out_result) *out_result = NULL; if (out_job_id) *out_job_id = 0; g_return_val_if_fail (worker, FALSE); g_return_val_if_fail (func, FALSE); if (!worker->callbacks_hash || !worker->jobs_hash) { g_warning ("GdaWorker has been destroyed\n"); return FALSE; } if (gda_worker_thread_is_worker (worker)) { /* we are called from within the worker thread => call the function directly */ gpointer result; result = func (data, error); if (data_destroy_func) data_destroy_func (data); if (out_result) *out_result = result; else if (result && result_destroy_func) result_destroy_func (result); return TRUE; } guint jid, itsid, timer = 0; /* determine which GMainContext to use */ GMainContext *co; gboolean unref_co = FALSE; co = context; if (!co) { co = g_main_context_ref_thread_default (); unref_co = TRUE; } /* prepare main loop */ GMainLoop *loop; loop = g_main_loop_new (co, FALSE); /* prepare ITSignaler to be notified */ ITSignaler *its; its = itsignaler_new (); itsid = itsignaler_add (its, co, (ITSignalerFunc) do_itsignaler_cb, g_main_loop_ref (loop), (GDestroyNotify) g_main_loop_unref); /* push job */ g_rec_mutex_lock (& worker->rmutex); /* required to call _gda_worker_submit_job_with_its() */ jid = _gda_worker_submit_job_with_its (worker, its, func, data, data_destroy_func, result_destroy_func, error); g_rec_mutex_unlock (& worker->rmutex); if (jid == 0) { /* an error occurred */ g_assert (itsignaler_remove (its, co, itsid)); itsignaler_unref (its); g_main_loop_unref (loop); if (unref_co) g_main_context_unref (co); return FALSE; } /* check if result is already here */ WorkerJob *job; job = itsignaler_pop_notification (its, 0); if (!job) { if (timeout_ms > 0) { /* start timer to limit waiting time */ GSource *timer_src; timer_src = g_timeout_source_new (timeout_ms); g_source_set_callback (timer_src, (GSourceFunc) do_timer_cb, loop, NULL); timer = g_source_attach (timer_src, co); g_source_unref (timer_src); } g_main_loop_run (loop); /* either timer has arrived or job has been done */ job = itsignaler_pop_notification (its, 0); } g_main_loop_unref (loop); g_assert (itsignaler_remove (its, co, itsid)); itsignaler_unref (its); if (job) { /* job done before the timer, if any, elapsed */ if (timer > 0) g_assert (g_source_remove (timer)); g_assert (gda_worker_fetch_job_result (worker, jid, out_result, error)); } else { /* timer came first, job is not yet finished */ /* apply settings from gda_worker_set_callback(), if any */ g_rec_mutex_lock (&worker->rmutex); DeclaredCallback *dc; dc = g_hash_table_lookup (worker->callbacks_hash, co); if (dc) { job = g_hash_table_lookup (worker->jobs_hash, &jid); g_assert (job); g_assert (!job->reply_its); job->reply_its = itsignaler_ref (dc->its); } g_rec_mutex_unlock (& worker->rmutex); /* cleanups */ if (out_job_id) *out_job_id = jid; else if (!dc) /* forget all about the job */ gda_worker_forget_job (worker, jid); } if (unref_co) g_main_context_unref (co); return TRUE; }
static void g_dbus_server_init (GDBusServer *server) { server->main_context_at_construction = g_main_context_ref_thread_default (); }
/** * gda_worker_set_callback: (skip) * @worker: a #GdaWorker object * @context: (allow-none): a #GMainContext, or %NULL * @callback: (allow-none): the function to call when a job submitted from within the calling thread using gda_worker_submit_job() has finished being processed. * @user_data: argument passed to @callback * @error: (allow-none): a place to store errors, or %NULL * * Declare a callback function to be called when a job has been processed. If @callback is %NULL, then any previously * effect of this function is removed. If the same function is called with a different @callback value, then the previous one * is simply replaced. * * Since this function adds a new source of events to the specified #GMainContext (or the default one if @context is %NULL), * * Notes: * <itemizedlist> * <listitem><para>before calling this function, @worker internally gets rid of the job, so the @jib_id passed * to @callback does not actually designate a known job ID, and so calling gda_worker_fetch_job_result() for that * job ID will fail</para></listitem> * <listitem><para>the job's result, if any, has to be freed by @callback (@worker does not do it)</para></listitem> * <listitem><para>any call to this function will only be honored for the jobs submitted _after_ calling it, the ones * submitted before are not affected</para></listitem> * <listitem><para>passing %NULL for @context is similar to passing the result of g_main_context_ref_thread_default()</para></listitem> * </itemizedlist> * * Returns: %TRUE if no error occurred. * * Since: 6.0 */ gboolean gda_worker_set_callback (GdaWorker *worker, GMainContext *context, GdaWorkerCallback callback, gpointer user_data, GError **error) { g_return_val_if_fail (worker, FALSE); g_return_val_if_fail (callback, FALSE); if (!worker->callbacks_hash) { g_warning ("GdaWorker has been destroyed\n"); return FALSE; } GMainContext *co; gboolean unref_co = FALSE; co = context; if (!co) { co = g_main_context_ref_thread_default (); unref_co = TRUE; } #ifdef DEBUG_NOTIFICATION g_print ("[W] %s() GMainContext=%p, thread=%p\n", __FUNCTION__, co, g_thread_self()); #endif g_rec_mutex_lock (& worker->rmutex); gboolean retval = TRUE; DeclaredCallback *dc = NULL; dc = g_hash_table_lookup (worker->callbacks_hash, co); if (dc) { if (callback) { /* change callback's attributes */ dc->callback = callback; dc->user_data = user_data; } else { /* remove callback */ g_hash_table_remove (worker->callbacks_hash, co); } } if (!dc) { if (callback) { /* add callback */ dc = declared_callback_new (worker, co, callback, user_data); if (!dc) { g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_INTER_THREAD_ERROR, _("Cannot build inter thread communication device")); g_rec_mutex_unlock (& worker->rmutex); return FALSE; } g_hash_table_insert (worker->callbacks_hash, co, dc); dc->source_sig_id = itsignaler_add (dc->its, co, (ITSignalerFunc) dc_callback, dc, NULL); if (dc->source_sig_id == 0) { g_hash_table_remove (worker->callbacks_hash, co); g_set_error (error, GDA_WORKER_ERROR, GDA_WORKER_INTER_THREAD_ERROR, _("GdaWorker internal error")); retval = FALSE; } } else { /* nothing to do */ } } g_rec_mutex_unlock (& worker->rmutex); if (unref_co) g_main_context_unref (co); return retval; }