void svc_accessor::stop() { // stop main loop if (main_loop_) { GMainLoop* loop = main_loop_.get(); if (loop && g_main_loop_is_running(loop)) { g_main_loop_quit(loop); loop_thread_->join(); // wait for exit thread loop_thread_.reset(); } // wait for clear context GMainContext* main_context = g_main_loop_get_context(loop); while(!g_main_context_acquire(main_context)) sched_yield(); g_main_context_release(main_context_.get()); main_context_.reset(); main_loop_.reset(); // unregister service if (svc_) svc_.reset(); } }
void ags_gui_task_thread_run(AgsThread *thread) { AgsGuiThread *gui_thread; GMainContext *main_context; gui_thread = AGS_AUDIO_LOOP(AGS_MAIN(AGS_DEVOUT(thread->devout)->ags_main)->main_loop)->gui_thread; main_context = g_main_context_default(); if(!g_main_context_acquire(main_context)){ gboolean got_ownership = FALSE; while(!got_ownership){ got_ownership = g_main_context_wait(main_context, &(gui_thread->cond), &(gui_thread->mutex)); } } gdk_threads_enter(); gdk_threads_leave(); g_main_context_iteration(main_context, FALSE); AGS_THREAD_CLASS(ags_gui_task_thread_parent_class)->run(thread); g_main_context_release(main_context); }
static int glib_acquire(glib_glue_t *glue) { if (g_main_context_acquire(glue->mc)) return TRUE; while (!g_main_context_wait(glue->mc, &glue->gcnd, &glue->gmtx)) ; return TRUE; }
static void main_loop_dispatch (void) { GMainContext *context = g_main_loop_get_context (loop); if (!g_main_context_acquire (context)) abort (); g_main_context_dispatch (context); g_main_context_release (context); }
CAMLprim value lwt_glib_iter(value may_block) { GMainContext *gc; gint max_priority, timeout; GPollFD *pollfds = NULL; gint pollfds_size = 0; gint nfds; gint i; /* Get the main context. */ gc = g_main_context_default(); /* Try to acquire it. */ if (!g_main_context_acquire(gc)) caml_failwith("Lwt_glib.iter"); /* Dispatch pending events. */ g_main_context_dispatch(gc); /* Prepare the context for polling. */ g_main_context_prepare(gc, &max_priority); /* Get all file descriptors to poll. */ while (pollfds_size < (nfds = g_main_context_query(gc, max_priority, &timeout, pollfds, pollfds_size))) { free(pollfds); pollfds_size = nfds; pollfds = lwt_unix_malloc(pollfds_size * sizeof (GPollFD)); } /* Clear all revents fields. */ for (i = 0; i < nfds; i++) pollfds[i].revents = 0; /* Set the timeout to 0 if we do not want to block. */ if (!Bool_val(may_block)) timeout = 0; /* Do the blocking call. */ caml_enter_blocking_section(); g_main_context_get_poll_func(gc)(pollfds, nfds, timeout); caml_leave_blocking_section(); /* Let glib parse the result. */ g_main_context_check(gc, max_priority, pollfds, nfds); /* Release the context. */ g_main_context_release(gc); free(pollfds); return Val_unit; }
static void soup_proxy_resolver_gnome_init (SoupProxyResolverGNOME *resolver_gnome) { GMainContext *default_context; G_LOCK (resolver_gnome); if (!gconf_client) { /* GConf is not thread-safe, and we might be running * in some random thread right now while other * GConf-related activity is going on in the main * thread. To prevent badness, we try to claim the * default GMainContext; if we succeed, then either * we're in the thread of the default GMainContext, or * else there isn't currently any thread running the * default GMainContext (meaning either the main loop * hasn't been started yet, or else there is no main * loop). Either way, it's safe to use GConf. * * If we can't manage to acquire the default * GMainContext, then that means another thread * already has it, so we use g_idle_add() to ask that * thread to do the GConf initialization, and wait * for that thread to finish. */ default_context = g_main_context_default (); if (g_main_context_acquire (default_context)) { init_gconf (NULL); g_main_context_release (default_context); } else { SoupProxyResolverGNOMEInitData id; id.lock = g_mutex_new (); id.cond = g_cond_new (); g_mutex_lock (id.lock); g_idle_add (init_gconf, &id); g_cond_wait (id.cond, id.lock); g_mutex_unlock (id.lock); g_cond_free (id.cond); g_mutex_free (id.lock); } } G_UNLOCK(resolver_gnome); }
/** @internal Run the main loop. * * The main loop runs until su_source_break() is called from a callback. * * @param self pointer to port object * */ static void su_source_run(su_port_t *self) { GMainContext *gmc; GMainLoop *gml; enter; gmc = g_source_get_context(self->sup_source); if (gmc && g_main_context_acquire(gmc)) { gml = g_main_loop_new(gmc, TRUE); self->sup_main_loop = gml; g_main_loop_run(gml); g_main_loop_unref(gml); self->sup_main_loop = NULL; g_main_context_release(gmc); } }
void grustna_main_loop_run_thread_local (GMainLoop *loop) { GMainContext *context; gboolean context_acquired; context = g_main_loop_get_context (loop); context_acquired = g_main_context_acquire (context); while (!context_acquired) context_acquired = g_main_context_wait (context, &rust_context_released_cond, &rust_context_mutex); g_main_context_push_thread_default (context); g_main_loop_run (loop); g_main_context_pop_thread_default (context); g_main_context_release (context); }
/** 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 *def_context; /* May happen if sr_session_start() is called again after * sr_session_run(), but the session hasn't been stopped yet. */ if (session->main_loop) { sr_err("Cannot set main context; main loop already created."); return SR_ERR; } g_mutex_lock(&session->main_mutex); def_context = g_main_context_get_thread_default(); if (!def_context) def_context = g_main_context_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(def_context)) { g_main_context_release(def_context); sr_dbg("Using thread-default main context."); session->main_context = def_context; session->main_context_is_default = TRUE; } else { sr_dbg("Creating our own main context."); session->main_context = g_main_context_new(); session->main_context_is_default = FALSE; } g_mutex_unlock(&session->main_mutex); return SR_OK; }
/** 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; }
/** @internal Block until wait object is signaled or timeout. * * This function waits for wait objects and the timers associated with * the root object. When any wait object is signaled or timer is * expired, it invokes the callbacks. * * This function returns when a callback has been invoked or @c tout * milliseconds is elapsed. * * @param self pointer to port * @param tout timeout in milliseconds * * @Return * Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if * there are no active timers. */ su_duration_t su_source_step(su_port_t *self, su_duration_t tout) { GMainContext *gmc; enter; gmc = g_source_get_context(self->sup_source); if (gmc && g_main_context_acquire(gmc)) { GPollFD *fds = NULL; gint fds_size = 0; gint fds_wait; gint priority = G_MAXINT; gint src_tout = -1; g_main_context_prepare(gmc, &priority); fds_wait = g_main_context_query(gmc, priority, &src_tout, NULL, 0); while (fds_wait > fds_size) { fds = g_alloca(fds_wait * sizeof(fds[0])); fds_size = fds_wait; fds_wait = g_main_context_query(gmc, priority, &src_tout, fds, fds_size); } if (src_tout >= 0 && tout > (su_duration_t)src_tout) tout = src_tout; su_wait((su_wait_t *)fds, fds_wait, tout); g_main_context_check(gmc, priority, fds, fds_wait); g_main_context_dispatch(gmc); g_main_context_release(gmc); } return 0; }
static int os_host_main_loop_wait(int64_t timeout) { GMainContext *context = g_main_context_default(); int ret; g_main_context_acquire(context); glib_pollfds_fill(&timeout); qemu_mutex_unlock_iothread(); replay_mutex_unlock(); ret = qemu_poll_ns((GPollFD *)gpollfds->data, gpollfds->len, timeout); replay_mutex_lock(); qemu_mutex_lock_iothread(); glib_pollfds_poll(); g_main_context_release(context); return ret; }
static mst_Boolean main_loop_poll (int ms) { GMainContext *context; int timeout; if (!loop || !g_main_loop_is_running (loop)) return FALSE; if (!fds) { fds = g_new (GPollFD, 20); allocated_nfds = 20; } context = g_main_loop_get_context (loop); if (!g_main_context_acquire (context)) abort (); timeout = -1; g_main_context_prepare (context, &maxprio); while ((nfds = g_main_context_query (context, maxprio, &timeout, fds, allocated_nfds)) > allocated_nfds) { g_free (fds); fds = g_new (GPollFD, nfds); allocated_nfds = nfds; } if (ms != -1 && (timeout == -1 || timeout > ms)) timeout = ms; g_main_context_release (context); g_poll (fds, nfds, timeout); return g_main_context_check (context, maxprio, fds, nfds); }
static gpointer loop_thread_init (gpointer data) { KmsLoop *self = KMS_LOOP (data); GMainLoop *loop; GMainContext *context; KMS_LOOP_LOCK (self); self->priv->context = g_main_context_new (); context = g_main_context_ref (self->priv->context); self->priv->loop = g_main_loop_new (context, FALSE); loop = g_main_loop_ref (self->priv->loop); KMS_LOOP_UNLOCK (self); /* unlock main process because context is already initialized */ g_mutex_lock (&self->priv->mutex); self->priv->initialized = TRUE; g_cond_signal (&self->priv->cond); g_mutex_unlock (&self->priv->mutex); if (!g_main_context_acquire (context)) { GST_ERROR ("Can not acquire context"); goto end; } GST_DEBUG ("Running main loop"); g_main_loop_run (loop); g_main_context_release (context); end: GST_DEBUG ("Thread finished"); g_main_loop_unref (loop); g_main_context_unref (context); return NULL; }
gboolean grustna_call (RustFunc func, gpointer data, GMainContext *context) { gboolean thread_default_context = FALSE; g_return_val_if_fail (func != NULL, FALSE); if (context == NULL) { context = g_main_context_get_thread_default (); if (context == NULL) context = get_rust_thread_context (); else thread_default_context = TRUE; } /* This code is based on g_main_context_invoke_full() */ if (g_main_context_is_owner (context)) { /* Fastest path: the caller is in the same thread where some code * is supposedly driving the loop context affine to this call. */ func (data, context); return TRUE; } if (g_main_context_acquire (context)) { /* Here, we get to exclusively use the desired loop context * that is not (yet) driven by an event loop. * This is perfectly OK for non-async functions on objects affine * to this context, and matches the behavior of GIO-style async calls * that rely on the thread-default context to be eventually driven * in order to complete. */ if (!thread_default_context) g_main_context_push_thread_default (context); func (data, context); if (!thread_default_context) g_main_context_pop_thread_default (context); g_main_context_release (context); /* Unblock a potentially waiting * grustna_main_loop_run_thread_local() */ g_cond_broadcast (&rust_context_released_cond); return TRUE; } else { /* Shunt the call to the loop thread * and wait for it to complete. */ RustCallData *call_data; RustCallStatus status; GSource *idle; call_data = g_slice_new0 (RustCallData); call_data->func = func; call_data->param = data; call_data->context = g_main_context_ref (context); call_data->ref_count = 3; call_data->minder_backoff = 1 * G_TIME_SPAN_MILLISECOND; call_data->status = RUST_CALL_PENDING; idle = g_idle_source_new (); g_source_set_priority (idle, G_PRIORITY_DEFAULT); g_source_set_callback (idle, loop_callback, call_data, NULL); g_source_attach (idle, context); call_data->source = idle; g_cond_init (&call_data->return_cond); add_call_minder (call_data); g_mutex_lock (&call_mutex); while ((status = call_data->status) == RUST_CALL_PENDING) g_cond_wait (&call_data->return_cond, &call_mutex); g_mutex_unlock (&call_mutex); call_data_unref (call_data); return status == RUST_CALL_RETURNED; } }
static int os_host_main_loop_wait(int64_t timeout) { GMainContext *context = g_main_context_default(); GPollFD poll_fds[1024 * 2]; /* this is probably overkill */ int select_ret = 0; int g_poll_ret, ret, i, n_poll_fds; PollingEntry *pe; WaitObjects *w = &wait_objects; gint poll_timeout; int64_t poll_timeout_ns; static struct timeval tv0; fd_set rfds, wfds, xfds; int nfds; g_main_context_acquire(context); /* XXX: need to suppress polling by better using win32 events */ ret = 0; for (pe = first_polling_entry; pe != NULL; pe = pe->next) { ret |= pe->func(pe->opaque); } if (ret != 0) { g_main_context_release(context); return ret; } FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); nfds = pollfds_fill(gpollfds, &rfds, &wfds, &xfds); if (nfds >= 0) { select_ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv0); if (select_ret != 0) { timeout = 0; } if (select_ret > 0) { pollfds_poll(gpollfds, nfds, &rfds, &wfds, &xfds); } } g_main_context_prepare(context, &max_priority); n_poll_fds = g_main_context_query(context, max_priority, &poll_timeout, poll_fds, ARRAY_SIZE(poll_fds)); g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds)); for (i = 0; i < w->num; i++) { poll_fds[n_poll_fds + i].fd = (DWORD_PTR)w->events[i]; poll_fds[n_poll_fds + i].events = G_IO_IN; } if (poll_timeout < 0) { poll_timeout_ns = -1; } else { poll_timeout_ns = (int64_t)poll_timeout * (int64_t)SCALE_MS; } poll_timeout_ns = qemu_soonest_timeout(poll_timeout_ns, timeout); qemu_mutex_unlock_iothread(); replay_mutex_unlock(); g_poll_ret = qemu_poll_ns(poll_fds, n_poll_fds + w->num, poll_timeout_ns); replay_mutex_lock(); qemu_mutex_lock_iothread(); if (g_poll_ret > 0) { for (i = 0; i < w->num; i++) { w->revents[i] = poll_fds[n_poll_fds + i].revents; } for (i = 0; i < w->num; i++) { if (w->revents[i] && w->func[i]) { w->func[i](w->opaque[i]); } } } if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) { g_main_context_dispatch(context); } g_main_context_release(context); return select_ret || g_poll_ret; }
MOSHEXPORT void mglib_loop_acquire(void){ g_main_context_acquire(g_main_context_default()); }
int xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timespec *timeout, sigset_t *sigmask) { fd_set all_rfds, all_wfds; struct timespec tmo; struct timespec *tmop = timeout; GMainContext *context; bool have_wfds = wfds != NULL; GPollFD gfds_buf[128]; GPollFD *gfds = gfds_buf; int gfds_size = ARRAYELTS (gfds_buf); int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1; bool context_acquired = false; int i, nfds, tmo_in_millisec, must_free = 0; bool need_to_dispatch; context = g_main_context_default (); context_acquired = g_main_context_acquire (context); /* FIXME: If we couldn't acquire the context, we just silently proceed because this function handles more than just glib file descriptors. Note that, as implemented, this failure is completely silent: there is no feedback to the caller. */ if (rfds) all_rfds = *rfds; else FD_ZERO (&all_rfds); if (wfds) all_wfds = *wfds; else FD_ZERO (&all_wfds); n_gfds = (context_acquired ? g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec, gfds, gfds_size) : -1); if (gfds_size < n_gfds) { /* Avoid using SAFE_NALLOCA, as that implicitly refers to the current thread. Using xnmalloc avoids thread-switching problems here. */ gfds = xnmalloc (n_gfds, sizeof *gfds); must_free = 1; gfds_size = n_gfds; n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec, gfds, gfds_size); } for (i = 0; i < n_gfds; ++i) { if (gfds[i].events & G_IO_IN) { FD_SET (gfds[i].fd, &all_rfds); if (gfds[i].fd > max_fds) max_fds = gfds[i].fd; } if (gfds[i].events & G_IO_OUT) { FD_SET (gfds[i].fd, &all_wfds); if (gfds[i].fd > max_fds) max_fds = gfds[i].fd; have_wfds = true; } } if (must_free) xfree (gfds); if (n_gfds >= 0 && tmo_in_millisec >= 0) { tmo = make_timespec (tmo_in_millisec / 1000, 1000 * 1000 * (tmo_in_millisec % 1000)); if (!timeout || timespec_cmp (tmo, *timeout) < 0) tmop = &tmo; } fds_lim = max_fds + 1; nfds = thread_select (pselect, fds_lim, &all_rfds, have_wfds ? &all_wfds : NULL, efds, tmop, sigmask); if (nfds < 0) retval = nfds; else if (nfds > 0) { for (i = 0; i < fds_lim; ++i) { if (FD_ISSET (i, &all_rfds)) { if (rfds && FD_ISSET (i, rfds)) ++retval; else ++our_fds; } else if (rfds) FD_CLR (i, rfds); if (have_wfds && FD_ISSET (i, &all_wfds)) { if (wfds && FD_ISSET (i, wfds)) ++retval; else ++our_fds; } else if (wfds) FD_CLR (i, wfds); if (efds && FD_ISSET (i, efds)) ++retval; } } /* If Gtk+ is in use eventually gtk_main_iteration will be called, unless retval is zero. */ #ifdef USE_GTK need_to_dispatch = retval == 0; #else need_to_dispatch = true; #endif if (need_to_dispatch && context_acquired) { int pselect_errno = errno; /* Prevent g_main_dispatch recursion, that would occur without block_input wrapper, because event handlers call unblock_input. Event loop recursion was causing Bug#15801. */ block_input (); while (g_main_context_pending (context)) g_main_context_dispatch (context); unblock_input (); errno = pselect_errno; } if (context_acquired) g_main_context_release (context); /* To not have to recalculate timeout, return like this. */ if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0)) { retval = -1; errno = EINTR; } return retval; }
/** * g_tls_interaction_invoke_ask_password: * @interaction: a #GTlsInteraction object * @password: a #GTlsPassword object * @cancellable: an optional #GCancellable cancellation object * @error: an optional location to place an error on failure * * Invoke the interaction to ask the user for a password. It invokes this * interaction in the main loop, specifically the #GMainContext returned by * g_main_context_get_thread_default() when the interaction is created. This * is called by called by #GTlsConnection or #GTlsDatabase to ask the user * for a password. * * Derived subclasses usually implement a password prompt, although they may * also choose to provide a password from elsewhere. The @password value will * be filled in and then @callback will be called. Alternatively the user may * abort this password request, which will usually abort the TLS connection. * * The implementation can either be a synchronous (eg: modal dialog) or an * asynchronous one (eg: modeless dialog). This function will take care of * calling which ever one correctly. * * If the interaction is cancelled by the cancellation object, or by the * user then %G_TLS_INTERACTION_FAILED will be returned with an error that * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may * not support immediate cancellation. * * Returns: The status of the ask password interaction. * * Since: 2.30 */ GTlsInteractionResult g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction, GTlsPassword *password, GCancellable *cancellable, GError **error) { GTlsInteractionResult result; InvokeClosure *closure; GTlsInteractionClass *klass; g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED); closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable); klass = G_TLS_INTERACTION_GET_CLASS (interaction); if (klass->ask_password) { g_main_context_invoke (interaction->priv->context, on_invoke_ask_password_sync, closure); result = invoke_closure_wait_and_free (closure, error); } else if (klass->ask_password_async) { g_return_val_if_fail (klass->ask_password_finish, G_TLS_INTERACTION_UNHANDLED); g_main_context_invoke (interaction->priv->context, on_invoke_ask_password_async_as_sync, closure); /* * Handle the case where we've been called from within the main context * or in the case where the main context is not running. This approximates * the behavior of a modal dialog. */ if (g_main_context_acquire (interaction->priv->context)) { while (!closure->complete) { g_mutex_unlock (closure->mutex); g_main_context_iteration (interaction->priv->context, TRUE); g_mutex_lock (closure->mutex); } g_main_context_release (interaction->priv->context); if (closure->error) { g_propagate_error (error, closure->error); closure->error = NULL; } result = closure->result; invoke_closure_free (closure); } /* * Handle the case where we're in a different thread than the main * context and a main loop is running. */ else { result = invoke_closure_wait_and_free (closure, error); } } else { result = G_TLS_INTERACTION_UNHANDLED; invoke_closure_free (closure); } return result; }
/** * gcr_importer_import: * @importer: the importer * @cancellable: a #GCancellable, or %NULL * @error: the location to place an error on failure, or %NULL * * Import the queued items in the importer. This call will block * until the operation completes. * * Returns: whether the items were imported successfully or not */ gboolean gcr_importer_import (GcrImporter *importer, GCancellable *cancellable, GError **error) { gboolean result; ImportClosure *closure; GcrImporterIface *iface; g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); iface = GCR_IMPORTER_GET_INTERFACE (importer); if (iface->import_sync) return (iface->import_sync) (importer, cancellable, error); g_return_val_if_fail (iface->import_async != NULL, FALSE); g_return_val_if_fail (iface->import_finish != NULL, FALSE); closure = g_new0 (ImportClosure, 1); closure->cond = g_new (GCond, 1); g_cond_init (closure->cond); closure->mutex = g_new (GMutex, 1); g_mutex_init (closure->mutex); closure->context = g_main_context_get_thread_default (); g_mutex_lock (closure->mutex); (iface->import_async) (importer, cancellable, on_import_async_complete, closure); /* * Handle the case where we've been called from within the main context * or in the case where the main context is not running. This approximates * the behavior of a modal dialog. */ if (g_main_context_acquire (closure->context)) { while (!closure->complete) { g_mutex_unlock (closure->mutex); g_main_context_iteration (closure->context, TRUE); g_mutex_lock (closure->mutex); } g_main_context_release (closure->context); /* * Handle the case where we're in a different thread than the main * context and a main loop is running. */ } else { while (!closure->complete) g_cond_wait (closure->cond, closure->mutex); } g_mutex_unlock (closure->mutex); result = (closure->error == NULL); if (closure->error) g_propagate_error (error, closure->error); g_cond_clear (closure->cond); g_free (closure->cond); g_mutex_clear (closure->mutex); g_free (closure->mutex); g_free (closure); return result; }
static void call_minder (gpointer data, G_GNUC_UNUSED gpointer pool_data) { RustCallData *call_data = data; GMainContext *context = call_data->context; RustCallStatus status = RUST_CALL_PENDING; gint64 end_time; end_time = g_get_monotonic_time() + CALL_MINDER_TIMEOUT; do { if (g_main_context_acquire (context)) { status = call_data->status; /* No locking needed */ if (status == RUST_CALL_PENDING) { /* Nothing has been there to drive our call, let's do it now */ g_source_destroy (call_data->source); g_main_context_push_thread_default (context); call_data->func (call_data->param, context); g_main_context_pop_thread_default (context); g_mutex_lock (&call_mutex); status = RUST_CALL_RETURNED; call_data->status = status; g_cond_signal (&call_data->return_cond); g_mutex_unlock (&call_mutex); } g_main_context_release (context); /* Unblock a potentially waiting * grustna_main_loop_run_thread_local() */ g_cond_broadcast (&rust_context_released_cond); } else { gint64 wakeup_time; g_mutex_lock (&call_mutex); wakeup_time = g_get_monotonic_time () + call_data->minder_backoff; if (wakeup_time > end_time) { g_critical ("call timed out waiting on context %p", call_data->context); status = RUST_CALL_TIMED_OUT; call_data->status = status; g_cond_signal (&call_data->return_cond); } else { if (!g_cond_wait_until (&call_data->return_cond, &call_mutex, wakeup_time)) call_data->minder_backoff *= 2; status = call_data->status; } g_mutex_unlock (&call_mutex); } } while (status == RUST_CALL_PENDING); call_data_unref (call_data); }