Esempio n. 1
0
/**
 * 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);
}
Esempio n. 2
0
/**
 * 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;
}