diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2020-11-04 15:47:33 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2020-11-04 15:47:33 -0800 |
commit | 18d2918a02028bf649607bb9959b926d10f184f6 (patch) | |
tree | 1aeea75d16a17ed14649f9f47b18e5605f3b6044 | |
parent | 31dea83f4e5f3e57c3fc05d8ad01a58dc844c2c7 (diff) |
thunk: introduce public variant of THUNK_DEFINE
This is necessarily split in two:
THUNK_DEFINE()
THUNK_DECLARE()
use is identical to the original THUNK_DEFINE (now THUNK_DEFINE_STATIC),
and you supply the same input to both DEFINE and DECLARE.
The THUNK_DECLARE() should go in the public header, which you also
include in the implementing .c file, not just from consumers.
The THUNK_DEFINE() goes in the implementing .c file, same as before.
Use this variant when you wish to instantiate via THUNK() from external
listings, just include the THUNK_DECLARE()-containing .h.
-rw-r--r-- | thunk.h | 50 |
1 files changed, 50 insertions, 0 deletions
@@ -418,6 +418,56 @@ struct thunk_t { \ static int _THUNK_GEN_PROTO(_name, __VA_ARGS__) + +/* this is the public variant which is split across declare & define */ +/* put the declaration in the .h, the define in the .c, be sure to include the + * .h from the implementing .c - not just the consumers. + */ +#define THUNK_DECLARE(_name, ...) \ + int _THUNK_GEN_PROTO(_name, __VA_ARGS__); \ + typedef struct __thunk_environment_##_name { \ + /* struct for encapsulating the calling environment */ \ + thunk_t __thunk; \ + _THUNK_GEN_STRUCT (__VA_ARGS__); \ + } __thunk_environment_##_name; \ + \ + int __thunk_dispatch_##_name(thunk_t *thunk); \ + thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__); + + +#define THUNK_DEFINE(_name, ...) \ + int __thunk_dispatch_##_name(thunk_t *thunk) { \ + /* dispatch thunk from associated environment */ \ + __thunk_environment_##_name *env; \ + int r; \ + \ + /* XXX: the embedded __thunk is always at the start, otherwise \ + * container_of() could be used... */ \ + env = (__thunk_environment_##_name *)thunk; \ + assert(env); \ + \ + r = _THUNK_GEN_DISPATCH(_name, env, __VA_ARGS__); \ + free(env); \ + \ + return r; \ + } \ + \ + thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) { \ + /* allocate and populate environment, return it */ \ + __thunk_environment_##_name *env; \ + \ + env = malloc(sizeof(*env)); \ + assert(env); \ + \ + _THUNK_GEN_INITIALIZE(env, __VA_ARGS__); \ + env->__thunk.dispatch = __thunk_dispatch_##_name; \ + \ + return &env->__thunk; \ + } \ + \ + int _THUNK_GEN_PROTO(_name, __VA_ARGS__) + + /* Call the appropriate instantiate function which returns an embedded thunk_t, * this is how you prepare the thunks established via THUNK_DEFINE(). */ #define _THUNK(_call) \ |