Whilst asynchronous IO (non-blocking descriptors with select/poll/epoll/kqueue etc) is not the most documented thing on the web, there are a handful of good examples.
<
You need to have a main loop that provides async_schedule(), async_foreach(), async_tick() etc. These functions in turn place entries into a global list of methods that will run upon next call to async_tick(). Then you can write code that is much more tidy and does not include any switch statements.
You can just write:
async_schedule(callback, arg, timeout);
Or:
async_wait(condition, callback, arg, timeout);
Then your condition can even be set in another thread (provided that you take care of thread safety when accessing that variable).
I have implemented an async framework in C for my embedded project because I wanted to have non-preemptive multitasking and async is perfect for doing many tasks by doing a little bit of work during every iteration of the main loop.
The code is here: https://github.com/mkschreder/fortmax-blocks/blob/master/common/kernel/async.c