Product SiteDocumentation Site


tc_waitq_init, tc_waitq_wakeup_all, tc_waitq_wakeup_one, tc_waitq_wait_event, tc_waitq_unregister — libtc wait queue functions


#include <tc/threaded_cr.h>

void tc_waitq_init(struct tc_waitq *wq);

enum tc_rv tc_waitq_wait_event(struct tc_waitq *wq, CONDITION);

void tc_waitq_wakeup_all(struct tc_waitq *wq);

void tc_waitq_wakeup_one(struct tc_waitq *wq);

void tc_waitq_unregister(struct tc_waitq *wq);


tc_waitqs are can be used to wait for an arbitrary condition in one tc_thread.
Before a tc_waitq may be used, it has to be initialized with a call to tc_waitq_init(). It may not be used after a call to its destructor tc_waitq_unregister().
When one tc_thread potentially changes some state, so that a waiting for condition might become true for an other thread it can trigger re-evaluation of the waiting condition in other threads by calls to tc_waitq_wakeup_all() or tc_waitq_wakeup_one(). The former wakes all tc_threads sleeping on that tc_waitq, while the latter wakes only one.
The tc_waitq_wait_event() macro sleeps on an tc_waitq until the CONDITION evaluates to true.

Return value

tc_waitq_wait_event() returns RV_OK if the condition became true and RV_INTR if the call was interrupted by a tc_signal.


The following example outlines a simple memory allocator, that blocks further allocations when it is exhausted.
struct mempool {
	atomic_t available;
	struct tc_waitq wq;

void mempool_init(struct mempool *mp, int size)
	atomic_set(&mp->available, size);

static int _try_alloc(struct mempool *mp, int size)
	if (atomic_sub_return(size, &mp->available) > 0)
		return 1;

	atomic_add_return(size, &mp->available);
	return 0;

void *mempool_alloc(struct mempool *mp, int size)
	void *rv;

	if (tc_waitq_wait_event(&mp->wq, _try_alloc(mp, size) == 1) != RV_OK)
		return NULL;

	rv = malloc(size);
	if (!rv)
		atomic_add_return(size, &mp->available);
	return rv;

void mempool_free(struct mempool *mp, void* mem, int size)
	atomic_add_return(size, &mp->available);


Philipp Reisner