/** * Let sleepers know about the wake-up condition. * * @param hl the list of waiting parties * @param data waking-up data to supply to callback */ static void wq_notify(hash_list_t *hl, void *data) { hash_list_iter_t *iter; size_t i, count; iter = hash_list_iterator(hl); count = hash_list_length(hl); i = 0; while (hash_list_iter_has_next(iter)) { wq_event_t *we = hash_list_iter_next(iter); wq_status_t status; wq_event_check(we); /* * Stop iteration in case callbacks have called wq_sleep() on the * same waiting queue we're iterating on and added items to the list. * This sanity check ensures we're not going to loop forever with a * callback systematically appending something. */ if (i++ >= count) { /* Something is odd, let them know about the calling stack */ s_critical("stopping after processing %zu item%s (list now has %u)", count, plural(count), hash_list_length(hl)); } status = (*we->cb)(we->arg, data); switch (status) { case WQ_SLEEP: continue; /* Still sleeping, leave in the list */ case WQ_EXCLUSIVE: case WQ_REMOVE: goto remove; } s_error("invalid status %d returned by %s()", status, stacktrace_function_name(we->cb)); remove: hash_list_iter_remove(iter); wq_event_free(we); /* * The callback may decide that we shouldn't continue notifying * other sleepers (because it knows it grabbed a resource that others * will need for instance). This is used as an early termination * of the loop. */ if (WQ_EXCLUSIVE == status) break; } hash_list_iter_release(&iter); }
/** * Checks whether there is a successor in the iterator's direction. */ bool hash_list_iter_has_more(const hash_list_iter_t *iter) { hash_list_iter_check(iter); g_assert(iter->dir != HASH_LIST_ITER_UNDEFINED); switch (iter->dir) { case HASH_LIST_ITER_FORWARDS: return hash_list_iter_has_next(iter); case HASH_LIST_ITER_BACKWARDS: return hash_list_iter_has_previous(iter); case HASH_LIST_ITER_UNDEFINED: break; } g_assert_not_reached(); return FALSE; }