/* coroutine.h - Simple coroutine and request/response implementation * * Copyright (C) 2024 Luke T. Shumaker * SPDX-Licence-Identifier: AGPL-3.0-or-later */ #ifndef _COROUTINE_H_ #define _COROUTINE_H_ #include /* for size_t */ #include /* for bool */ /* typedefs *******************************************************************/ typedef size_t cid_t; /* 0=none; otherwise 1-indexed */ #define COROUTINE __attribute__ ((noreturn, no_split_stack)) void typedef void (*cr_fn_t)(void *args); /* managing coroutines ********************************************************/ void coroutine_init(void); cid_t coroutine_add(cr_fn_t fn, void *args); void coroutine_main(void); /* inside of coroutines *******************************************************/ __attribute__ ((no_split_stack)) bool cr_begin( void); __attribute__ ((no_split_stack, noreturn)) void cr_exit(void); __attribute__ ((no_split_stack)) void cr_yield(void); __attribute__ ((no_split_stack)) void cr_pause_and_yield(void); __attribute__ ((no_split_stack)) void cr_unpause(cid_t); #define cr_end cr_exit cid_t cr_getcid(void); /* request/response channels **************************************************/ #define cr_chan_t(req_t, resp_t) struct { \ cid_t requester; \ cid_t responder; \ req_t req; \ resp_t resp; \ } #define cr_chan_req(ch, _resp_p, _req) do { \ (ch)->requester = cr_getcid(); \ (ch)->req = (_req); \ if ((ch)->responder != 0) \ cr_unpause((ch)->responder); \ cr_pause_and_yield(); \ if ((typeof(&(ch)->resp))(_resp_p)) \ *((typeof(&(ch)->resp))(_resp_p)) = (ch)->resp; \ } while (0) #define cr_chan_have_req(ch) ((ch)->requester != 0) #define cr_chan_recv_req(ch, _req_p) do { \ (ch)->responder = cr_getcid(); \ if ((ch)->requester == 0) \ cr_pause_and_yield(); \ *(_req_p) = (ch)->req; \ } while (0) #define cr_chan_send_resp(ch, _resp) do { \ cr_unpause((ch)->requester); \ (ch)->responder = 0; \ (ch)->requester = 0; \ (ch)->resp = (_resp); \ } while (0) #endif /* _COROUTINE_H_ */