/** * g_hook_list_invoke_check: * @hook_list: a #GHookList * @may_recurse: %TRUE if functions which are already running * (e.g. in another thread) can be called. If set to %FALSE, * these are skipped * * Calls all of the #GHook functions in a #GHookList. * Any function which returns %FALSE is removed from the #GHookList. */ void g_hook_list_invoke_check (GHookList *hook_list, gboolean may_recurse) { GHook *hook; g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->is_setup); hook = g_hook_first_valid (hook_list, may_recurse); while (hook) { GHookCheckFunc func; gboolean was_in_call; gboolean need_destroy; func = (GHookCheckFunc) hook->func; was_in_call = G_HOOK_IN_CALL (hook); hook->flags |= G_HOOK_FLAG_IN_CALL; need_destroy = !func (hook->data); if (!was_in_call) hook->flags &= ~G_HOOK_FLAG_IN_CALL; if (need_destroy) g_hook_destroy_link (hook_list, hook); hook = g_hook_next_valid (hook_list, hook, may_recurse); } }
/** * g_hook_next_valid: * @hook_list: a #GHookList * @hook: the current #GHook * @may_be_in_call: %TRUE if hooks which are currently running * (e.g. in another thread) are considered valid. If set to %FALSE, * these are skipped * * Returns the next #GHook in a #GHookList which has not been destroyed. * The reference count for the #GHook is incremented, so you must call * g_hook_unref() to restore it when no longer needed. (Or continue to call * g_hook_next_valid() until %NULL is returned.) * * Returns: the next valid #GHook, or %NULL if none are valid */ GHook* g_hook_next_valid (GHookList *hook_list, GHook *hook, gboolean may_be_in_call) { GHook *ohook = hook; g_return_val_if_fail (hook_list != NULL, NULL); if (!hook) return NULL; hook = hook->next; while (hook) { if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) { g_hook_ref (hook_list, hook); g_hook_unref (hook_list, ohook); return hook; } hook = hook->next; } g_hook_unref (hook_list, ohook); return NULL; }
/** * g_hook_list_marshal: * @hook_list: a #GHookList * @may_recurse: %TRUE if hooks which are currently running * (e.g. in another thread) are considered valid. If set to %FALSE, * these are skipped * @marshaller: the function to call for each #GHook * @marshal_data: data to pass to @marshaller * * Calls a function on each valid #GHook. */ void g_hook_list_marshal (GHookList *hook_list, gboolean may_recurse, GHookMarshaller marshaller, gpointer data) { GHook *hook; g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->is_setup); g_return_if_fail (marshaller != NULL); hook = g_hook_first_valid (hook_list, may_recurse); while (hook) { gboolean was_in_call; was_in_call = G_HOOK_IN_CALL (hook); hook->flags |= G_HOOK_FLAG_IN_CALL; marshaller (hook, data); if (!was_in_call) hook->flags &= ~G_HOOK_FLAG_IN_CALL; hook = g_hook_next_valid (hook_list, hook, may_recurse); } }
EXPORT_C void g_hook_list_marshal_check (GHookList *hook_list, gboolean may_recurse, GHookCheckMarshaller marshaller, gpointer data) { GHook *hook; g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->is_setup); g_return_if_fail (marshaller != NULL); hook = g_hook_first_valid (hook_list, may_recurse); while (hook) { gboolean was_in_call; gboolean need_destroy; was_in_call = G_HOOK_IN_CALL (hook); hook->flags |= G_HOOK_FLAG_IN_CALL; need_destroy = !marshaller (hook, data); if (!was_in_call) hook->flags &= ~G_HOOK_FLAG_IN_CALL; if (need_destroy) g_hook_destroy_link (hook_list, hook); hook = g_hook_next_valid (hook_list, hook, may_recurse); } }
EXPORT_C void g_hook_list_invoke (GHookList *hook_list, gboolean may_recurse) { GHook *hook; g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->is_setup); hook = g_hook_first_valid (hook_list, may_recurse); while (hook) { GHookFunc func; gboolean was_in_call; func = (GHookFunc) hook->func; was_in_call = G_HOOK_IN_CALL (hook); hook->flags |= G_HOOK_FLAG_IN_CALL; func (hook->data); if (!was_in_call) hook->flags &= ~G_HOOK_FLAG_IN_CALL; hook = g_hook_next_valid (hook_list, hook, may_recurse); } }
void g_hook_free (GHookList *hook_list, GHook *hook) { g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->is_setup); g_return_if_fail (hook != NULL); g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); g_return_if_fail (!G_HOOK_IN_CALL (hook)); hook_list->finalize_hook (hook_list, hook); g_chunk_free (hook, hook_list->hook_memchunk); }
/** * g_hook_free: * @hook_list: a #GHookList * @hook: the #GHook to free * * Calls the #GHookList @finalize_hook function if it exists, * and frees the memory allocated for the #GHook. */ void g_hook_free (GHookList *hook_list, GHook *hook) { g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->is_setup); g_return_if_fail (hook != NULL); g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); g_return_if_fail (!G_HOOK_IN_CALL (hook)); if(hook_list->finalize_hook != NULL) hook_list->finalize_hook (hook_list, hook); g_slice_free1 (hook_list->hook_size, hook); }
/* HOLDS: main_loop_lock */ static void g_main_dispatch (GTimeVal *dispatch_time) { while (pending_dispatches != NULL) { gboolean need_destroy; GSource *source = pending_dispatches->data; GSList *tmp_list; tmp_list = pending_dispatches; pending_dispatches = g_slist_remove_link (pending_dispatches, pending_dispatches); g_slist_free_1 (tmp_list); if (G_HOOK_IS_VALID (source)) { gboolean was_in_call; gpointer hook_data = source->hook.data; gpointer source_data = source->source_data; gboolean (*dispatch) (gpointer, GTimeVal *, gpointer); dispatch = ((GSourceFuncs *) source->hook.func)->dispatch; was_in_call = G_HOOK_IN_CALL (source); source->hook.flags |= G_HOOK_FLAG_IN_CALL; G_UNLOCK (main_loop); need_destroy = ! dispatch (source_data, dispatch_time, hook_data); G_LOCK (main_loop); if (!was_in_call) source->hook.flags &= ~G_HOOK_FLAG_IN_CALL; if (need_destroy && G_HOOK_IS_VALID (source)) g_hook_destroy_link (&source_list, (GHook *) source); } g_hook_unref (&source_list, (GHook*) source); } }
void g_hook_unref (GHookList *hook_list, GHook *hook) { g_return_if_fail (hook_list != NULL); g_return_if_fail (hook_list->hook_memchunk != NULL); g_return_if_fail (hook != NULL); g_return_if_fail (hook->ref_count > 0); hook->ref_count--; if (!hook->ref_count) { g_return_if_fail (hook->hook_id == 0); g_return_if_fail (!G_HOOK_IN_CALL (hook)); if (hook->prev) hook->prev->next = hook->next; else hook_list->hooks = hook->next; if (hook->next) { hook->next->prev = hook->prev; hook->next = NULL; } hook->prev = NULL; if (!hook_list->is_setup) { hook_list->is_setup = TRUE; g_hook_free (hook_list, hook); hook_list->is_setup = FALSE; if (!hook_list->hooks) { g_mem_chunk_destroy (hook_list->hook_memchunk); hook_list->hook_memchunk = NULL; } } else g_hook_free (hook_list, hook); } }
/** * g_hook_first_valid: * @hook_list: a #GHookList * @may_be_in_call: %TRUE if hooks which are currently running * (e.g. in another thread) are considered valid. If set to %FALSE, * these are skipped * * Returns the first #GHook in a #GHookList which has not been destroyed. * The reference count for the #GHook is incremented, so you must call * g_hook_unref() to restore it when no longer needed. (Or call * g_hook_next_valid() if you are stepping through the #GHookList.) * * Returns: the first valid #GHook, or %NULL if none are valid */ GHook* g_hook_first_valid (GHookList *hook_list, gboolean may_be_in_call) { g_return_val_if_fail (hook_list != NULL, NULL); if (hook_list->is_setup) { GHook *hook; hook = hook_list->hooks; if (hook) { g_hook_ref (hook_list, hook); if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) return hook; else return g_hook_next_valid (hook_list, hook, may_be_in_call); } } return NULL; }
/* g_main_iterate () runs a single iteration of the mainloop, or, * if !dispatch checks to see if any sources need dispatching. * basic algorithm for dispatch=TRUE: * * 1) while the list of currently pending sources is non-empty, * we call (*dispatch) on those that are !IN_CALL or can_recurse, * removing sources from the list after each returns. * the return value of (*dispatch) determines whether the source * itself is kept alive. * * 2) call (*prepare) for sources that are not yet SOURCE_READY and * are !IN_CALL or can_recurse. a return value of TRUE determines * that the source would like to be dispatched immediatedly, it * is then flagged as SOURCE_READY. * * 3) poll with the pollfds from all sources at the priority of the * first source flagged as SOURCE_READY. if there are any sources * flagged as SOURCE_READY, we use a timeout of 0 or the minimum * of all timouts otherwise. * * 4) for each source !IN_CALL or can_recurse, if SOURCE_READY or * (*check) returns true, add the source to the pending list. * once one source returns true, stop after checking all sources * at that priority. * * 5) while the list of currently pending sources is non-empty, * call (*dispatch) on each source, removing the source * after the call. * */ static gboolean g_main_iterate (gboolean block, gboolean dispatch) { GHook *hook; GTimeVal current_time = { 0, 0 }; gint n_ready = 0; gint current_priority = 0; gint timeout; gboolean retval = FALSE; g_return_val_if_fail (!block || dispatch, FALSE); g_get_current_time (¤t_time); G_LOCK (main_loop); #ifdef G_THREADS_ENABLED if (poll_waiting) { g_warning("g_main_iterate(): main loop already active in another thread"); G_UNLOCK (main_loop); return FALSE; } #endif /* If recursing, finish up current dispatch, before starting over */ if (pending_dispatches) { if (dispatch) g_main_dispatch (¤t_time); G_UNLOCK (main_loop); return TRUE; } /* Prepare all sources */ timeout = block ? -1 : 0; hook = g_hook_first_valid (&source_list, TRUE); while (hook) { GSource *source = (GSource*) hook; gint source_timeout = -1; if ((n_ready > 0) && (source->priority > current_priority)) { g_hook_unref (&source_list, hook); break; } if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE)) { hook = g_hook_next_valid (&source_list, hook, TRUE); continue; } if (!(hook->flags & G_SOURCE_READY)) { gboolean (*prepare) (gpointer source_data, GTimeVal *current_time, gint *timeout, gpointer user_data); prepare = ((GSourceFuncs *) hook->func)->prepare; in_check_or_prepare++; G_UNLOCK (main_loop); if ((*prepare) (source->source_data, ¤t_time, &source_timeout, source->hook.data)) hook->flags |= G_SOURCE_READY; G_LOCK (main_loop); in_check_or_prepare--; } if (hook->flags & G_SOURCE_READY) { if (!dispatch) { g_hook_unref (&source_list, hook); G_UNLOCK (main_loop); return TRUE; } else { n_ready++; current_priority = source->priority; timeout = 0; } } if (source_timeout >= 0) { if (timeout < 0) timeout = source_timeout; else timeout = MIN (timeout, source_timeout); } hook = g_hook_next_valid (&source_list, hook, TRUE); } /* poll(), if necessary */ g_main_poll (timeout, n_ready > 0, current_priority); if (timeout != 0) g_get_current_time (¤t_time); /* Check to see what sources need to be dispatched */ n_ready = 0; hook = g_hook_first_valid (&source_list, TRUE); while (hook) { GSource *source = (GSource *)hook; if ((n_ready > 0) && (source->priority > current_priority)) { g_hook_unref (&source_list, hook); break; } if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE)) { hook = g_hook_next_valid (&source_list, hook, TRUE); continue; } if (!(hook->flags & G_SOURCE_READY)) { gboolean (*check) (gpointer source_data, GTimeVal *current_time, gpointer user_data); check = ((GSourceFuncs *) hook->func)->check; in_check_or_prepare++; G_UNLOCK (main_loop); if ((*check) (source->source_data, ¤t_time, source->hook.data)) hook->flags |= G_SOURCE_READY; G_LOCK (main_loop); in_check_or_prepare--; } if (hook->flags & G_SOURCE_READY) { if (dispatch) { hook->flags &= ~G_SOURCE_READY; g_hook_ref (&source_list, hook); pending_dispatches = g_slist_prepend (pending_dispatches, source); current_priority = source->priority; n_ready++; } else { g_hook_unref (&source_list, hook); G_UNLOCK (main_loop); return TRUE; } } hook = g_hook_next_valid (&source_list, hook, TRUE); } /* Now invoke the callbacks */ if (pending_dispatches) { pending_dispatches = g_slist_reverse (pending_dispatches); g_main_dispatch (¤t_time); retval = TRUE; } G_UNLOCK (main_loop); return retval; }