From 18d2918a02028bf649607bb9959b926d10f184f6 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Wed, 4 Nov 2020 15:47:33 -0800 Subject: 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. --- thunk.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/thunk.h b/thunk.h index ef868ab..d2ec683 100644 --- a/thunk.h +++ b/thunk.h @@ -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) \ -- cgit v1.2.1