/** * \file coroutine.h * \brief Coroutines in C. * \author Vitaly Kravtsov (in4lio@gmail.com) * \copyright The MIT License * * \defgroup coro Coroutines in C * * Coroutine mechanics, implemented using the C language extensions "Labels as Values", * "Statements and Declarations in Expressions" and "Locally Declared Labels". * Based on Simon Tatham "Coroutines in C". * * \code * CORO_CONTEXT( A ); * CORO_CONTEXT( B ); * * CORO_DEFINE( A ) * { * CORO_BEGIN(); * for ( ; ; ) { * // ... * CORO_YIELD(); * } * CORO_END(); * } * * CORO_DEFINE( B ) * { * CORO_LOCAL int b; * * CORO_BEGIN(); * for ( ; ; ) { * // ... * CORO_WAIT( cond ); * } * CORO_END(); * } * * int main( void ) * { * for ( ; ; ) { * CORO_CALL( A ); * CORO_CALL( B ); * } * return 0; * } * \endcode * * Any local variables which need to be persistent across a coroutine switching * must be declared static (CORO_LOCAL). * * \{ */ #ifndef COROUTINE_H #define COROUTINE_H typedef void * co_t; typedef unsigned int semaphore_t; enum { CO_READY, CO_WAIT, CO_YIELD, CO_END, CO_SKIP, }; /** * \brief Define the coroutine context (a pointer to label). * \param name Coroutine name. */ #define CORO_CONTEXT( name ) \ co_t co_##name #define CORO_CONTEXT_INIT( name ) ({ \ co_##name = NULL; \ }) /** * \brief Declare the local variable that preserves a value across a coroutine switching. */ #define CORO_LOCAL static /** * \brief Define the coroutine. * \param name Coroutine name. */ #define CORO_DEFINE( name ) \ int coro_##name( co_t *co_p ) /** * \brief The coroutine beginning. * \param initial The initial operation, executed whenever enter in the coroutine. */ #define CORO_BEGIN( initial ) ({ \ initial; \ if ( *co_p ) goto **co_p; \ }) /** * \brief The coroutine end. * \param final The final operation, executed whenever exit from the coroutine. * \hideinitializer */ #define CORO_END( final ) ({ \ __label__ L; \ *co_p = &&L; \ L: \ final; \ return CO_END; \ }) /** * \brief Switching to the next coroutine. * \param final Final operation. */ #define CORO_YIELD( final ) ({ \ __label__ L; \ *co_p = &&L; \ final; \ return CO_YIELD; \ L:; \ }) /** * \brief Waiting for the condition is true. * \param cond Condition. * \param ... Final operation. */ #define CORO_WAIT( cond, ... ) ({ \ __label__ L; \ *co_p = &&L; \ L: \ if (!( cond )) { \ __VA_ARGS__; /* final */ \ return CO_WAIT; \ } \ }) /** * \brief Restart the coroutine. * \param final Final operation. */ #define CORO_RESTART( final ) ({ \ *co_p = NULL; \ final; \ return CO_YIELD; \ }) /** * \brief Quit the coroutine. * \param final Final operation. */ #define CORO_QUIT( final ) CORO_END( final ) /** * \brief Call the coroutine. * \param name Coroutine name. */ #define CORO_CALL( name ) \ coro_##name( &co_##name ) /** * \brief Checking the coroutine is not completed. * \param coro Result of the coroutine call. * \return Alive flag. */ #define CORO_ALIVE( coro ) (( coro ) < CO_END ) /** * \brief Start and waiting for the child coroutine is completed. * \param coro Child coroutine. * \param ... Final operation. */ #define CORO_WAIT_CORO( coro, ... ) \ CORO_WAIT( !CORO_ALIVE( coro ), ## __VA_ARGS__ ) /** * \brief Initialize the semaphore. * \param name Semaphore name. * \param val Semaphore capacity. */ #define SEMAPHORE_INIT( name, val ) ({ \ name = val; \ }) /** * \brief Waiting and acquire the semaphore. * \param name Semaphore name. * \param ... Final operation. */ #define SEMAPHORE_ACQUIRE( name, ... ) ({ \ CORO_WAIT(( name > 0 ), ## __VA_ARGS__ ); \ --name; \ }) /** * \brief Release the semaphore. * \param name Semaphore name. */ #define SEMAPHORE_RELEASE( name ) ({ \ ++name; \ }) #endif /* COROUTINE_H */ /** \} */