/** * 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_clear: * @hook_list: a #GHookList * * Removes all the #GHook elements from a #GHookList. */ void g_hook_list_clear (GHookList *hook_list) { g_return_if_fail (hook_list != NULL); if (hook_list->is_setup) { GHook *hook; hook_list->is_setup = FALSE; hook = hook_list->hooks; if (!hook) { /* destroy hook_list->hook_memchunk */ } else do { GHook *tmp; g_hook_ref (hook_list, hook); g_hook_destroy_link (hook_list, hook); tmp = hook->next; g_hook_unref (hook_list, hook); hook = tmp; } while (hook); } }
void g_hook_list_clear (GHookList *hook_list) { g_return_if_fail (hook_list != NULL); if (hook_list->is_setup) { GHook *hook; hook_list->is_setup = FALSE; hook = hook_list->hooks; if (!hook) { g_mem_chunk_destroy (hook_list->hook_memchunk); hook_list->hook_memchunk = NULL; } else do { GHook *tmp; g_hook_ref (hook_list, hook); g_hook_destroy_link (hook_list, hook); tmp = hook->next; g_hook_unref (hook_list, hook); hook = tmp; } while (hook); if (hook_list->hook_memchunk) g_warning (G_STRLOC ": failed to clear hooklist, unconsolidated references on hooks left"); } }
/** * g_hook_insert_sorted: * @hook_list: a #GHookList * @hook: the #GHook to insert * @func: the comparison function used to sort the #GHook elements * * Inserts a #GHook into a #GHookList, sorted by the given function. */ void g_hook_insert_sorted (GHookList *hook_list, GHook *hook, GHookCompareFunc func) { GHook *sibling; 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 (hook->func != NULL); g_return_if_fail (func != NULL); /* first non-destroyed hook */ sibling = hook_list->hooks; while (sibling && !sibling->hook_id) sibling = sibling->next; while (sibling) { GHook *tmp; g_hook_ref (hook_list, sibling); if (func (hook, sibling) <= 0 && sibling->hook_id) { g_hook_unref (hook_list, sibling); break; } /* next non-destroyed hook */ tmp = sibling->next; while (tmp && !tmp->hook_id) tmp = tmp->next; g_hook_unref (hook_list, sibling); sibling = tmp; } g_hook_insert_before (hook_list, sibling, hook); }
/** * g_hook_find: * @hook_list: a #GHookList * @need_valids: %TRUE if #GHook elements which have been destroyed * should be skipped * @func: the function to call for each #GHook, which should return * %TRUE when the #GHook has been found * @data: the data to pass to @func * * Finds a #GHook in a #GHookList using the given function to * test for a match. * * Returns: the found #GHook or %NULL if no matching #GHook is found */ GHook* g_hook_find (GHookList *hook_list, gboolean need_valids, GHookFindFunc func, gpointer data) { GHook *hook; g_return_val_if_fail (hook_list != NULL, NULL); g_return_val_if_fail (func != NULL, NULL); hook = hook_list->hooks; while (hook) { GHook *tmp; /* test only non-destroyed hooks */ if (!hook->hook_id) { hook = hook->next; continue; } g_hook_ref (hook_list, hook); if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook))) { g_hook_unref (hook_list, hook); return hook; } tmp = hook->next; g_hook_unref (hook_list, hook); hook = tmp; } return NULL; }
/** * 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; }