Created
January 9, 2016 00:10
-
-
Save jarcode-foss/50745a920dbaf27cd250 to your computer and use it in GitHub Desktop.
setjmp stack utility
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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