Skip to content

Instantly share code, notes, and snippets.

@jarcode-foss
Created January 9, 2016 00:10
Show Gist options
  • Save jarcode-foss/50745a920dbaf27cd250 to your computer and use it in GitHub Desktop.
Save jarcode-foss/50745a920dbaf27cd250 to your computer and use it in GitHub Desktop.
setjmp stack utility
/*
An extremely simple set of macros for jumping and setting jmp_buf's in a stack to simulate very
basic exception handling
*/
#ifndef LUAB_JMP_H_
#define LUAB_JMP_H_
typedef struct {
jmp_buf *buf_stack;
int buf_idx = -1;
} pthread_jmp_stack;
#define LUAB_CALL_ERRORS(R) R == LUA_ERRRUN || R == LUA_ERRMEM || R == LUA_ERRERR
// create jmp_buf stack
#define JMP_STACK(N, S) \
jmp_buf N##_buf_stack[S]; \
int N##_buf_idx = -1; \
static inline int* N##_buf_loc(void) { \
return &N##_buf_idx; \
} \
static inline jmp_buf[] N##_buf_stack_loc(void) { \
return N##_buf_stack; \
}
#ifdef __cplusplus
#define EXT_JMP_STACK(N) EXT_JMP_STACK_CPP(N)
#define THREAD_EXT_JMP_STACK(N) THREAD_EXT_JMP_STACK_CPP(N)
#else
#define EXT_JMP_STACK(N) EXT_JMP_STACK_C(N)
#define THREAD_EXT_JMP_STACK(N) THREAD_EXT_JMP_STACK_C(N)
#endif // __cplusplus
#define DEF_JMP_STACK(N, S) \
jmp_buf N##_buf_stack[S]; \
int N##_buf_idx = -1;
/* probably worth redefining */
#define THREAD_KEY_FAIL \
fprintf(stderr, "failed to create pthread key for jmp stack"); \
exit(EXIT_FAILIURE)
/* defines functions required for each thread to have their own jmp_stack */
#define THREAD_DEF_JMP_STACK(N, S) \
static pthread_key_t N##_key; \
static pthread_once_t N##_key_once = PTHREAD_ONCE_INIT; \
static void N##_jmp_destruct(void* ptr) { \
free(((pthread_jmp_stack) ptr)->buf_stack); \
free(ptr); \
} \
static void N##_jmp_setup(void) { \
if (pthread_key_create(&N##_key, &N##_jmp_destruct)) { \
THREAD_KEY_FAIL; \
} \
} \
static pthread_jmp_stack* N##_jmp_get_specific(void) { \
pthread_once(&N##_key_once, &N##_jmp_setup); \
pthread_jmp_stack* ptr = pthread_getspecific(N##_key); \
if (!ptr) { \
ptr = malloc(sizeof(pthread_jmp_stack)); \
ptr->N##_buf_stack = malloc(sizeof(jmp_buf) * S); \
ptr->N##_buf_idx = -1; \
pthread_setspecific(N##_key, ptr); \
} \
return ptr; \
} \
int* N##_buf_loc(void) { \
return &(N##_jmp_get_specific()->buf_idx); \
} \
int* N##_buf_stack_loc(void) { \
return N##_jmp_get_specific()->buf_stack; \
}
#define EXT_JMP_STACK_C(N) \
extern jmp_buf* N##_buf_stack; \
extern int N##_buf_idx; \
static inline int* N##_buf_loc(void) { \
return &N##_buf_idx; \
} \
static inline jmp_buf[] N##_buf_stack_loc(void) { \
return N##_buf_stack; \
}
#define EXT_JMP_STACK_CPP(N) \
extern "C" jmp_buf* N##_buf_stack; \
extern "C" int N##_buf_idx; \
static inline int* N##_buf_loc(void) { \
return &N##_buf_idx; \
} \
static inline jmp_buf[] N##_buf_stack_loc(void) { \
return N##_buf_stack; \
}
#define THREAD_EXT_JMP_STACK_C(N) \
extern int* N##_buf_loc(void); \
extern jmp_buf[] N##_buf_stack_loc(void);
#define THREAD_EXT_JMP_STACK_CPP(N) \
extern "C" int* N##_buf_loc(void); \
extern "C" jmp_buf[] N##_buf_stack_loc(void);
/* set next jmp env in the stack */
#define nextjmp(N, V) \
int V; \
*(N##_buf_loc())++; \
if (!(V = setjmp(N##_buf_stack_loc()[*(N##_buf_loc())])))
/* return from jmp */
#define retjmp(N) *(N##_buf_loc())--
/* get last set env buf */
#define getjmp(N) N##_buf_stack[N##_buf_idx]
/* jump to last position set in the stack */
#define lastjmp(N, X) longjmp(N##_buf_stack[N##_buf_idx], X)
#endif // LUAB_JMP_H_
/*
USAGE:
nextjmp(STACK, ret) {
... error-prone code here ...
}
retjmp(STACK); // returns the stack pointer to the correct position
... cleanup code here ...
// if we are looking for certain error codes, we can
// re-jump into the next buffer if we didn't find them
if (ret > 3) {
lastjmp(STACK, ret);
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment