Last active
August 29, 2015 14:15
-
-
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
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
| #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; | |
| } |
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
| #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__) | |
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
| --> 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