summaryrefslogtreecommitdiff
path: root/thunk.h
diff options
context:
space:
mode:
Diffstat (limited to 'thunk.h')
-rw-r--r--thunk.h67
1 files changed, 53 insertions, 14 deletions
diff --git a/thunk.h b/thunk.h
index 2cd607f..f02aff8 100644
--- a/thunk.h
+++ b/thunk.h
@@ -27,6 +27,7 @@ typedef struct thunk_t thunk_t;
struct thunk_t {
int (*dispatch)(thunk_t *);
+ void (*free)(thunk_t *);
};
/* Clever macro args counting from https://gcc.gnu.org/ml/gcc/2000-09/msg00604.html */
@@ -446,12 +447,14 @@ struct thunk_t {
static thunk_t * __thunk_alloc_##_name(void **payload_ptr, size_t payload_size) __attribute__ ((unused));\
static thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) __attribute__ ((unused));\
static thunk_t * _THUNK_GEN_INIT_PROTO(__thunk_init_##_name, thunk_t *_thunk, __VA_ARGS__) __attribute__ ((unused));\
+ static struct __thunk_environment_##_name *__thunk_environment_cache_##_name;\
\
typedef struct __thunk_environment_##_name { \
/* struct for encapsulating the calling environment */ \
- thunk_t __thunk; \
- _THUNK_GEN_STRUCT (__VA_ARGS__); \
- char __payload[]; \
+ thunk_t __thunk; \
+ struct __thunk_environment_##_name *next_free; \
+ _THUNK_GEN_STRUCT (__VA_ARGS__); \
+ char __payload[]; \
} __thunk_environment_##_name; \
\
static int __thunk_dispatch_##_name(thunk_t *thunk) { \
@@ -469,15 +472,28 @@ struct thunk_t {
return r; \
} \
\
+ static void __thunk_free_##_name(thunk_t *thunk) { \
+ __thunk_environment_##_name *env = (__thunk_environment_##_name *)thunk;\
+ \
+ env->next_free = __thunk_environment_cache_##_name; \
+ __thunk_environment_cache_##_name = env; \
+ } \
+ \
static thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) {\
/* allocate and initialize environment, return it */ \
__thunk_environment_##_name *env; \
\
- env = malloc(sizeof(*env)); \
+ if (__thunk_environment_cache_##_name) { \
+ env = __thunk_environment_cache_##_name; \
+ __thunk_environment_cache_##_name = env->next_free; \
+ } else { \
+ env = malloc(sizeof(*env)); \
+ } \
assert(env); \
\
_THUNK_GEN_INITIALIZE(env, __VA_ARGS__); \
env->__thunk.dispatch = __thunk_dispatch_##_name; \
+ env->__thunk.free = __thunk_free_##_name; \
\
return &env->__thunk; \
} \
@@ -495,6 +511,7 @@ struct thunk_t {
} \
\
env->__thunk.dispatch = __thunk_dispatch_##_name; \
+ env->__thunk.free = (void (*)(thunk_t *))free; \
\
return &env->__thunk; \
} \
@@ -522,18 +539,23 @@ struct thunk_t {
int _THUNK_GEN_PROTO(_name, __VA_ARGS__) __attribute__ ((unused)); \
typedef struct __thunk_environment_##_name { \
/* struct for encapsulating the calling environment */ \
- thunk_t __thunk; \
- _THUNK_GEN_STRUCT (__VA_ARGS__); \
- char __payload[]; \
+ thunk_t __thunk; \
+ struct __thunk_environment_##_name *next_free; \
+ _THUNK_GEN_STRUCT (__VA_ARGS__); \
+ char __payload[]; \
} __thunk_environment_##_name; \
\
int __thunk_dispatch_##_name(thunk_t *thunk) __attribute__ ((unused)); \
thunk_t * _THUNK_GEN_INIT_PROTO(__thunk_init_##_name, thunk_t *_thunk, __VA_ARGS__) __attribute__ ((unused));\
thunk_t * __thunk_alloc_##_name(void **payload_ptr, size_t payload_size) __attribute__ ((unused));\
- thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) __attribute__ ((unused));
+ thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) __attribute__ ((unused));\
+ \
+ extern struct __thunk_environment_##_name *__thunk_environment_cache_##_name;
#define THUNK_DEFINE(_name, ...) \
+ struct __thunk_environment_##_name *__thunk_environment_cache_##_name = NULL;\
+ \
int __thunk_dispatch_##_name(thunk_t *thunk) { \
/* dispatch thunk from associated environment */ \
__thunk_environment_##_name *env; \
@@ -549,15 +571,28 @@ struct thunk_t {
return r; \
} \
\
+ void __thunk_free_##_name(thunk_t *thunk) { \
+ __thunk_environment_##_name *env = (__thunk_environment_##_name *)thunk;\
+ \
+ env->next_free = __thunk_environment_cache_##_name; \
+ __thunk_environment_cache_##_name = env; \
+ } \
+ \
thunk_t * _THUNK_GEN_PROTO(__thunk_instantiate_##_name, __VA_ARGS__) { \
/* allocate and populate environment, return it */ \
__thunk_environment_##_name *env; \
\
- env = malloc(sizeof(*env)); \
+ if (__thunk_environment_cache_##_name) { \
+ env = __thunk_environment_cache_##_name; \
+ __thunk_environment_cache_##_name = env->next_free; \
+ } else { \
+ env = malloc(sizeof(*env)); \
+ } \
assert(env); \
\
_THUNK_GEN_INITIALIZE(env, __VA_ARGS__); \
env->__thunk.dispatch = __thunk_dispatch_##_name; \
+ env->__thunk.free = __thunk_free_##_name; \
\
return &env->__thunk; \
} \
@@ -575,6 +610,7 @@ struct thunk_t {
} \
\
env->__thunk.dispatch = __thunk_dispatch_##_name; \
+ env->__thunk.free = (void (*)(thunk_t *))free; \
\
return &env->__thunk; \
} \
@@ -675,19 +711,22 @@ static inline int thunk_dispatch(thunk_t *thunk) {
int r;
r = thunk->dispatch(thunk);
- free(thunk);
+ thunk->free(thunk);
return r;
}
/* Same as thunk_dispatch() but without the free.
- * Callers can trivially free thunk instances w/free(), there's
- * no fancy destructor stuff or anything. So when a thunk needs
- * to be used repeatedly in a loop for instance, use this, then
- * just free the thunk yourself.
+ * Callers can trivially free thunk instances w/thunk_free().
+ * So when a thunk needs to be used repeatedly in a loop for instance, use
+ * this, then just free the thunk yourself.
*/
static inline int thunk_dispatch_keep(thunk_t *thunk) {
return thunk->dispatch(thunk);
}
+static inline void thunk_free(thunk_t *thunk) {
+ return thunk->free(thunk);
+}
+
#endif
© All Rights Reserved