Skip to content

Instantly share code, notes, and snippets.

@dymk
Last active August 29, 2015 14:15
Show Gist options
  • Select an option

  • Save dymk/d73fea039d79235bc436 to your computer and use it in GitHub Desktop.

Select an option

Save dymk/d73fea039d79235bc436 to your computer and use it in GitHub Desktop.
Basic implementation of exceptions and scope guards in C using POSIX setjmp/longjmp
#include <setjmp.h>
#include <stdio.h>
#include <jumptests.h>
static jmp_buf *last_buf = NULL;
static jmp_buf *scope_buf = NULL;
void second() {
printf("--> enter second\n");
throw(1);
printf("--> exit second\n");
}
void first() {
printf("--> enter first\n");
second();
printf("--> exit first\n");
}
void prima() {
printf("--> enter prima\n");
on_exit({
printf("--> exit prima, first on_exit()\n");
})
on_exit({
printf("--> exit prima, second on_exit()\n");
})
try({
printf("--> from prima, calling second\n");
second();
}, {
printf("--> prima 'catch' block\n");
})
second();
printf("--> exit prima\n");
frame_end();
}
int main() {
printf("--> enter main\n");
try({
first();
}, {
printf("--> main 'catch' block\n");
})
prima();
printf("--> exit main\n");
frame_end();
return 0;
}
#define MERGE_(a,b) a##b
#define frame_end() \
if(scope_buf) longjmp(*scope_buf, 1);
#define try_impl(try_block, catch_block, unique) \
jmp_buf *MERGE_(_tmp_try_buf_, unique) = last_buf; \
jmp_buf MERGE_(_try_buf_, unique); \
last_buf = &MERGE_(_try_buf_, unique); \
do { \
if(setjmp(*last_buf) == 0) { \
try_block; \
} else { \
catch_block; \
} \
} while(0); \
last_buf = MERGE_(_tmp_try_buf_, unique);
#define try(try_block, catch_block) \
try_impl(try_block, catch_block, __LINE__)
#define throw(val) longjmp(*last_buf, val)
#define on_exit_impl(exit_block, unique) \
jmp_buf MERGE_(_scope_buf_, unique); \
jmp_buf *MERGE_(_tmp_scope_last_buf_, unique) = last_buf; \
jmp_buf *MERGE_(_tmp_scope_scope_buf_, unique) = scope_buf; \
last_buf = &MERGE_(_scope_buf_, unique); \
scope_buf = &MERGE_(_scope_buf_, unique); \
do { \
if(setjmp(*scope_buf) != 0) { \
exit_block; \
last_buf = MERGE_(_tmp_scope_last_buf_, unique); \
scope_buf = MERGE_(_tmp_scope_scope_buf_, unique); \
if(scope_buf) { longjmp(*scope_buf, 1); } \
else { return; } \
} \
} while(0);
#define on_exit(exit_block) \
on_exit_impl(exit_block, __LINE__)
--> enter main
--> enter first
--> enter second
--> main 'catch' block
--> enter prima
--> from prima, calling second
--> enter second
--> prima 'catch' block
--> enter second
--> exit prima, second on_exit()
--> exit prima, first on_exit()
--> exit main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment