Changes in / [838ef08:bf70aa9]


Ignore:
Location:
doc/working/exception
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • doc/working/exception/impl/exception.c

    r838ef08 rbf70aa9  
    2222
    2323void __throw_resume(exception except) {
    24 
    25         // DEBUG
    26         printf("Throwing resumption exception %d\n", except);
     24        void noop() { printf("do nothing\n");}
     25        struct __cleanup_hook __blarg __attribute__((cleanup(noop)));
    2726
    2827        struct __try_resume_node * original_head = shared_stack.current_resume;
     
    4645}
    4746
     47/* __try_resume_node functions:
     48 * Currently I was planning to generate this code inline, and even if I don't
     49 * putting it in the header so it can be inlined might be worth while.
     50 * And if we put them in Cforall code we can use the operators.
     51 */
     52void __try_resume_node_new(struct __try_resume_node * node,
     53                _Bool (*handler)(exception except)) {
     54        node->next = shared_stack.top_resume;
     55        shared_stack.top_resume = node;
     56        node->try_to_handle = handler;
     57}
     58
     59void __try_resume_node_delete(struct __try_resume_node * node) {
     60        shared_stack.top_resume = node->next;
     61}
     62
    4863
    4964// TERMINATION ===============================================================
    5065
    5166// Requires -fexceptions to work.
    52 
    53 // Global which defines the current exception
    54 // Currently an int just to make matching easier
    55 //int this_exception; (became shared_stack.current_exception)
    56 
    57 // We need a piece of storage to raise the exception
    58 struct _Unwind_Exception this_exception_storage;
    59 
    60 // Function needed by force unwind
    61 // It basically says to unwind the whole stack and then exit when we reach the end of the stack
    62 static _Unwind_Reason_Code _Stop_Fn(
    63                 int version,
    64                 _Unwind_Action actions,
    65                 _Unwind_Exception_Class exceptionClass,
    66                 struct _Unwind_Exception * unwind_exception,
    67                 struct _Unwind_Context * context,
    68                 void * some_param) {
    69         if( actions & _UA_END_OF_STACK  ) exit(1);
    70         if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
    71 
    72         return _URC_FATAL_PHASE2_ERROR;
    73 }
    74 
    75 // Example throw routine
    76 void __throw_terminate( int val ) {
    77         // Store the current exception
    78         shared_stack.current_exception = val;
    79 
    80         // DEBUG
    81         printf("Throwing termination exception %d\n", val);
    82 
    83         // Call stdlibc to raise the exception
    84         _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
    85 
    86         // If we reach here it means something happened
    87         // For resumption to work we need to find a way to return back to here
    88         // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
    89         // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
    90         // If we just pretend no handler was found that would work but may be expensive for no reason since we will always
    91         // search the whole stack
    92 
    93         if( ret == _URC_END_OF_STACK ) {
    94                 // No proper handler was found
    95                 // This can be handled in several way
    96                 // C++ calls std::terminate
    97                 // Here we force unwind the stack, basically raising a cancellation
    98                 printf("Uncaught exception %p\n", &this_exception_storage);
    99 
    100                 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
    101                 printf("UNWIND ERROR %d after force unwind\n", ret);
    102                 abort();
    103         }
    104 
    105         // We did not simply reach the end of the stack without finding a handler,
    106         // Something wen't wrong
    107         printf("UNWIND ERROR %d after raise exception\n", ret);
    108         abort();
    109 }
    110 
    111 // This is our personality routine
    112 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
    113 // This function will be called twice when unwinding
    114 // Once in the search phased and once in the cleanup phase
    115 _Unwind_Reason_Code __gcfa_personality_v0 (
    116                 int version, _Unwind_Action actions, unsigned long long exceptionClass,
    117                 struct _Unwind_Exception* unwind_exception,
    118                 struct _Unwind_Context* context)
    119 {
    120 
    121         // DEBUG
    122         //printf("CFA: 0x%lx\n", _Unwind_GetCFA(context));
    123         printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
    124 
    125         // If we've reached the end of the stack then there is nothing much we can do...
    126         if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
    127 
    128         // DEBUG
    129         if (actions & _UA_SEARCH_PHASE) {
    130                 printf(" lookup phase");
    131         }
    132         // DEBUG
    133         else if (actions & _UA_CLEANUP_PHASE) {
    134                 printf(" cleanup phase");
    135         }
    136         // Just in case, probably can't actually happen
    137         else {
    138                 printf(" error\n");
    139                 return _URC_FATAL_PHASE1_ERROR;
    140         }
    141 
    142         // Get a pointer to the language specific data from which we will read what we need
    143         const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
    144 
    145         if( !lsd ) {    //Nothing to do, keep unwinding
    146                 printf(" no LSD");
    147                 goto UNWIND;
    148         }
    149 
    150         // Get the instuction pointer and a reading pointer into the exception table
    151         lsda_header_info lsd_info;
    152         const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
    153         _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
    154 
    155         // Linearly search the table for stuff to do
    156         while( cur_ptr < lsd_info.action_table ) {
    157                 _Unwind_Ptr callsite_start;
    158                 _Unwind_Ptr callsite_len;
    159                 _Unwind_Ptr callsite_landing_pad;
    160                 _uleb128_t  callsite_action;
    161 
    162                 // Decode the common stuff we have in here
    163                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
    164                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
    165                 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
    166                 cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
    167 
    168                 // Have we reach the correct frame info yet?
    169                 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
    170                         //DEBUG BEGIN
    171                         void * ls = (void*)lsd_info.Start;
    172                         void * cs = (void*)callsite_start;
    173                         void * cl = (void*)callsite_len;
    174                         void * bp = (void*)lsd_info.Start + callsite_start;
    175                         void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
    176                         void * ip = (void*)instruction_ptr;
    177                         printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
    178                         //DEBUG END
    179                         continue;
    180                 }
    181 
    182                 // Have we gone too far
    183                 if( lsd_info.Start + callsite_start > instruction_ptr ) {
    184                         printf(" gone too far");
    185                         break;
    186                 }
    187 
    188                 // Something to do?
    189                 if( callsite_landing_pad ) {
    190                         // Which phase are we in
    191                         if (actions & _UA_SEARCH_PHASE) {
    192                                 // Search phase, this means we probably found a potential handler and must check if it is a match
    193 
    194                                 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
    195                                 // This doesn't seem to conflict the gcc default behavior
    196                                 if (callsite_action != 0) {
    197                                         // Now we want to run some code to see if the handler matches
    198                                         // This is the tricky part where we want to the power to run arbitrary code
    199                                         // However, generating a new exception table entry and try routine every time
    200                                         // is way more expansive than we might like
    201                                         // The information we have is :
    202                                         //  - The GR (Series of registers)
    203                                         //    GR1=GP Global Pointer of frame ref by context
    204                                         //  - The instruction pointer
    205                                         //  - The instruction pointer info (???)
    206                                         //  - The CFA (Canonical Frame Address)
    207                                         //  - The BSP (Probably the base stack pointer)
    208 
    209 
    210                                         // The current apprach uses one exception table entry per try block
    211                                         _uleb128_t imatcher;
    212                                         // Get the relative offset to the
    213                                         cur_ptr = read_uleb128 (cur_ptr, &imatcher);
    214 
    215                                         // Get a function pointer from the relative offset and call it
    216                                         // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;                                   
    217 
    218                                         _Unwind_Reason_Code (*matcher)() =
    219                                                 MATCHER_FROM_CONTEXT(context);
    220                                         int index = matcher(shared_stack.current_exception);
    221                                         _Unwind_Reason_Code ret = (0 == index)
    222                                                 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    223                                         shared_stack.current_handler_index = index;
    224 
    225                                         // Based on the return value, check if we matched the exception
    226                                         if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");
    227                                         else printf(" no handler\n");
    228                                         return ret;
    229                                 }
    230 
    231                                 // This is only a cleanup handler, ignore it
    232                                 printf(" no action");
    233                         }
    234                         else if (actions & _UA_CLEANUP_PHASE) {
    235 
    236                                 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
    237                                         // If this is a potential exception handler
    238                                         // but not the one that matched the exception in the seach phase,
    239                                         // just ignore it
    240                                         goto UNWIND;
    241                                 }
    242 
    243                                 // We need to run some clean-up or a handler
    244                                 // These statment do the right thing but I don't know any specifics at all
    245                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
    246                                 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
    247 
    248                                 // I assume this sets the instruction pointer to the adress of the landing pad
    249                                 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
    250                                 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
    251 
    252                                 // DEBUG
    253                                 printf(" action\n");
    254 
    255                                 // Return have some action to run
    256                                 return _URC_INSTALL_CONTEXT;
    257                         }
    258                 }
    259 
    260                 // Nothing to do, move along
    261                 printf(" no landing pad");
    262         }
    263         // No handling found
    264         printf(" table end reached\n");
    265 
    266         // DEBUG
    267         UNWIND:
    268         printf(" unwind\n");
    269 
    270         // Keep unwinding the stack
    271         return _URC_CONTINUE_UNWIND;
    272 }
    27367
    27468// Try statements are hoisted out see comments for details
     
    347141        "       .size   __try_terminate, .-__try_terminate\n"
    348142        "       .ident  \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n"
    349 //      "       .section        .note.GNU-stack,\"x\",@progbits\n"
     143        "       .section        .note.GNU-stack,\"x\",@progbits\n"
    350144);
     145
     146// Global which defines the current exception
     147// Currently an int just to make matching easier
     148int this_exception;
     149
     150// We need a piece of storage to raise the exception
     151struct _Unwind_Exception this_exception_storage;
     152
     153// Function needed by force unwind
     154// It basically says to unwind the whole stack and then exit when we reach the end of the stack
     155static _Unwind_Reason_Code _Stop_Fn(
     156                int version,
     157                _Unwind_Action actions,
     158                _Unwind_Exception_Class exceptionClass,
     159                struct _Unwind_Exception * unwind_exception,
     160                struct _Unwind_Context * context,
     161                void * some_param) {
     162        if( actions & _UA_END_OF_STACK  ) exit(1);
     163        if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;
     164
     165        return _URC_FATAL_PHASE2_ERROR;
     166}
     167
     168// Example throw routine
     169void __throw_terminate( int val ) {
     170        // Store the current exception
     171        this_exception = val;
     172
     173        // DEBUG
     174        printf("Throwing exception %d\n", this_exception);
     175
     176        // Call stdlibc to raise the exception
     177        _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );
     178
     179        // If we reach here it means something happened
     180        // For resumption to work we need to find a way to return back to here
     181        // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.
     182        // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.
     183        // If we just pretend no handler was found that would work but may be expensive for no reason since we will always
     184        // search the whole stack
     185
     186        if( ret == _URC_END_OF_STACK ) {
     187                // No proper handler was found
     188                // This can be handled in several way
     189                // C++ calls std::terminate
     190                // Here we force unwind the stack, basically raising a cancellation
     191                printf("Uncaught exception %p\n", &this_exception_storage);
     192
     193                ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
     194                printf("UNWIND ERROR %d after force unwind\n", ret);
     195                abort();
     196        }
     197
     198        // We did not simply reach the end of the stack without finding a handler,
     199        // Something wen't wrong
     200        printf("UNWIND ERROR %d after raise exception\n", ret);
     201        abort();
     202}
     203
     204// This is our personality routine
     205// For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"
     206// This function will be called twice when unwinding
     207// Once in the search phased and once in the cleanup phase
     208_Unwind_Reason_Code __gcfa_personality_v0 (
     209                int version, _Unwind_Action actions, unsigned long long exceptionClass,
     210                struct _Unwind_Exception* unwind_exception,
     211                struct _Unwind_Context* context)
     212{
     213        printf("CFA: 0x%lx\n", _Unwind_GetCFA(context));
     214
     215        // DEBUG
     216        printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);
     217
     218        // If we've reached the end of the stack then there is nothing much we can do...
     219        if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;
     220
     221        // DEBUG
     222        if (actions & _UA_SEARCH_PHASE) {
     223                printf(" lookup phase");
     224        }
     225        // DEBUG
     226        else if (actions & _UA_CLEANUP_PHASE) {
     227                printf(" cleanup phase");
     228        }
     229        // Just in case, probably can't actually happen
     230        else {
     231                printf(" error\n");
     232                return _URC_FATAL_PHASE1_ERROR;
     233        }
     234
     235        // Get a pointer to the language specific data from which we will read what we need
     236        const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );
     237
     238        if( !lsd ) {    //Nothing to do, keep unwinding
     239                printf(" no LSD");
     240                goto UNWIND;
     241        }
     242
     243        // Get the instuction pointer and a reading pointer into the exception table
     244        lsda_header_info lsd_info;
     245        const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);
     246        _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );
     247
     248        // Linearly search the table for stuff to do
     249        while( cur_ptr < lsd_info.action_table ) {
     250                _Unwind_Ptr callsite_start;
     251                _Unwind_Ptr callsite_len;
     252                _Unwind_Ptr callsite_landing_pad;
     253                _uleb128_t  callsite_action;
     254
     255                // Decode the common stuff we have in here
     256                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);
     257                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);
     258                cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);
     259                cur_ptr = read_uleb128 (cur_ptr, &callsite_action);
     260
     261                // Have we reach the correct frame info yet?
     262                if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {
     263                        //DEBUG BEGIN
     264                        void * ls = (void*)lsd_info.Start;
     265                        void * cs = (void*)callsite_start;
     266                        void * cl = (void*)callsite_len;
     267                        void * bp = (void*)lsd_info.Start + callsite_start;
     268                        void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;
     269                        void * ip = (void*)instruction_ptr;
     270                        printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);
     271                        //DEBUG END
     272                        continue;
     273                }
     274
     275                // Have we gone too far
     276                if( lsd_info.Start + callsite_start > instruction_ptr ) {
     277                        printf(" gone too far");
     278                        break;
     279                }
     280
     281                // Something to do?
     282                if( callsite_landing_pad ) {
     283                        // Which phase are we in
     284                        if (actions & _UA_SEARCH_PHASE) {
     285                                // Search phase, this means we probably found a potential handler and must check if it is a match
     286
     287                                // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler
     288                                // This doesn't seem to conflict the gcc default behavior
     289                                if (callsite_action != 0) {
     290                                        // Now we want to run some code to see if the handler matches
     291                                        // This is the tricky part where we want to the power to run arbitrary code
     292                                        // However, generating a new exception table entry and try routine every time
     293                                        // is way more expansive than we might like
     294                                        // The information we have is :
     295                                        //  - The GR (Series of registers)
     296                                        //    GR1=GP Global Pointer of frame ref by context
     297                                        //  - The instruction pointer
     298                                        //  - The instruction pointer info (???)
     299                                        //  - The CFA (Canonical Frame Address)
     300                                        //  - The BSP (Probably the base stack pointer)
     301
     302
     303                                        // The current apprach uses one exception table entry per try block
     304                                        _uleb128_t imatcher;
     305                                        // Get the relative offset to the
     306                                        cur_ptr = read_uleb128 (cur_ptr, &imatcher);
     307
     308                                        // Get a function pointer from the relative offset and call it
     309                                        // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;                                   
     310
     311                                        _Unwind_Reason_Code (*matcher)() =
     312                                                MATCHER_FROM_CONTEXT(context);
     313                                        int index = matcher(shared_stack.current_exception);
     314                                        _Unwind_Reason_Code ret = (0 == index)
     315                                                ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
     316                                        shared_stack.current_handler_index = index;
     317
     318
     319                                        // Based on the return value, check if we matched the exception
     320                                        if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");
     321                                        else printf(" no handler\n");
     322                                        return ret;
     323                                }
     324
     325                                // This is only a cleanup handler, ignore it
     326                                printf(" no action");
     327                        }
     328                        else if (actions & _UA_CLEANUP_PHASE) {
     329
     330                                if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){
     331                                        // If this is a potential exception handler
     332                                        // but not the one that matched the exception in the seach phase,
     333                                        // just ignore it
     334                                        goto UNWIND;
     335                                }
     336
     337                                // We need to run some clean-up or a handler
     338                                // These statment do the right thing but I don't know any specifics at all
     339                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );
     340                                _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );
     341
     342                                // I assume this sets the instruction pointer to the adress of the landing pad
     343                                // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT
     344                                _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );
     345
     346                                // DEBUG
     347                                printf(" action\n");
     348
     349                                // Return have some action to run
     350                                return _URC_INSTALL_CONTEXT;
     351                        }
     352                }
     353
     354                // Nothing to do, move along
     355                printf(" no landing pad");
     356        }
     357        // No handling found
     358        printf(" table end reached\n");
     359
     360        // DEBUG
     361        UNWIND:
     362        printf(" unwind\n");
     363
     364        // Keep unwinding the stack
     365        return _URC_CONTINUE_UNWIND;
     366}
  • doc/working/exception/impl/exception.h

    r838ef08 rbf70aa9  
    3232};
    3333
    34 extern struct shared_stack_t shared_stack;
     34extern struct shared_stack_t stared_stack;
  • doc/working/exception/impl/test-main.c

    r838ef08 rbf70aa9  
    11#include "exception.h"
    22
    3 // Use: gcc -fexceptions -Wall -Werror -g exception.c test-main.c
    4 
    53#include <stdio.h>
    6 #include <stdbool.h>
    74
    85// Translation Helpers:
     
    107        struct __cleanup_hook __hidden_hook __attribute__((cleanup(function)))
    118
    12 #define SET_UP_RESUME_NODE(handler_function) \
    13         struct __try_resume_node node \
    14                 __attribute__((cleanup(__try_resume_node_delete))); \
    15         __try_resume_node_new(&node, handler_function)
    16 
    17 void __try_resume_node_new(struct __try_resume_node * node,
    18         _Bool (*handler)(exception except)) {
    19     node->next = shared_stack.top_resume;
    20     shared_stack.top_resume = node;
    21     node->try_to_handle = handler;
    22 }
    23 
    24 void __try_resume_node_delete(struct __try_resume_node * node) {
    25     shared_stack.top_resume = node->next;
    26 }
    279
    2810// Local Print On Exit:
     
    3719#define raii_t __attribute__((cleanup(raii_dtor))) struct raii_base_type
    3820
    39 // ===========================================================================
    4021// Runtime code (post-translation).
    4122void terminate(int except_value) {
     
    5334// Termination Test: Two handlers: no catch, catch
    5435void bar() {
    55         raii_t a = {"bar function"};
    56         {
    57                 void bar_try1() {
    58                         terminate(4);
     36        void bar_try1() {
     37                terminate(4);
     38        }
     39        void bar_catch1(int index, exception except) {
     40                switch(except) {
     41                case 1:
     42                        printf("bar caught exception.\n");
     43                        break;
     44                default:
     45                        printf("INVALID INDEX in bar: %d\n", except);
    5946                }
    60                 void bar_catch1(int index, exception except) {
    61                         switch(except) {
    62                         case 1:
    63                                 printf("bar caught exception 3.\n");
    64                                 break;
    65                         default:
    66                                 printf("INVALID INDEX in bar: %d (%d)\n", index, except);
    67                         }
     47        }
     48        int bar_match1(exception except) {
     49                if (3 == except) {
     50                        return 1;
     51                } else {
     52                        return 0;
    6853                }
    69                 int bar_match1(exception except) {
    70                         if (3 == except) {
    71                                 return 1;
    72                         } else {
    73                                 return 0;
    74                         }
    75                 }
    76                 __try_terminate(bar_try1, bar_catch1, bar_match1);
    7754        }
     55        __try_terminate(bar_try1, bar_catch1, bar_match1);
    7856}
    7957
    8058void foo() {
    81         raii_t a = {"foo function"};
    82         {
    83                 void foo_try1() {
    84                         bar();
     59        void foo_try1() {
     60                bar();
     61        }
     62        void foo_catch1(int index, exception except) {
     63                switch(except) {
     64                case 1:
     65                        printf("foo caught exception 4.\n");
     66                        break;
     67                case 2:
     68                        printf("foo caught exception 2.\n");
     69                        break;
     70                default:
     71                        printf("INVALID INDEX in foo: %d\n", except);
    8572                }
    86                 void foo_catch1(int index, exception except) {
    87                         switch(index) {
    88                         case 1:
    89                                 printf("foo caught exception 4.\n");
    90                                 break;
    91                         case 2:
    92                                 printf("foo caught exception 2.\n");
    93                                 break;
    94                         default:
    95                                 printf("INVALID INDEX in foo: %d (%d)\n", index, except);
    96                         }
     73        }
     74        int foo_match1(exception except) {
     75                if (4 == except) {
     76                        return 1;
     77                } else if (2 == except) {
     78                        return 2;
     79                } else {
     80                        return 0;
    9781                }
    98                 int foo_match1(exception except) {
    99                         if (4 == except) {
    100                                 return 1;
    101                         } else if (2 == except) {
    102                                 return 2;
    103                         } else {
    104                                 return 0;
    105                         }
    106                 }
    107                 __try_terminate(foo_try1, foo_catch1, foo_match1);
    10882        }
     83        __try_terminate(foo_try1, foo_catch1, foo_match1);
    10984}
    11085
    111 // Resumption Two Handler Test: no catch, catch.
    112 void beta() {
    113         raii_t a = {"beta function"};
    114         {
    115                 bool beta_handle1(exception except) {
    116                         if (3 == except) {
    117                                 printf("beta caught exception 3\n");
    118                                 return true;
    119                         } else {
    120                                 return false;
    121                         }
    122                 }
    123                 struct __try_resume_node node
    124                         __attribute__((cleanup(__try_resume_node_delete)));
    125                 __try_resume_node_new(&node, beta_handle1);
    126                 {
    127                         resume(4);
    128                 }
    129         }
    130 }
    131 void alpha() {
    132         raii_t a = {"alpha function"};
    133         {
    134                 bool alpha_handle1(exception except) {
    135                         if (2 == except) {
    136                                 printf("alpha caught exception 2\n");
    137                                 return true;
    138                         } else if (4 == except) {
    139                                 printf("alpha caught exception 4\n");
    140                                 return true;
    141                         } else {
    142                                 return false;
    143                         }
    144                 }
    145                 struct __try_resume_node node
    146                         __attribute__((cleanup(__try_resume_node_delete)));
    147                 __try_resume_node_new(&node, alpha_handle1);
    148                 {
    149                         beta();
    150                 }
    151         }
    152 }
    153 
    154 // Finally Test:
    155 void farewell() {
    156         {
    157                 void farewell_finally1() {
    158                         printf("See you next time\n");
    159                 }
    160                 struct __cleanup_hook __hidden_hook
    161                         __attribute__((cleanup(farewell_finally1)));
    162                 {
    163                         printf("walk out of farewell\n");
    164                 }
    165         }
    166 }
    167 
    168 // Resume-to-Terminate Test:
    169 void fallback() {
    170         {
    171                 void fallback_try1() {
    172                         resume(1);
    173                 }
    174                 void fallback_catch1(int index, exception except) {
    175                         switch (index) {
    176                         case 1:
    177                                 printf("fallback caught termination 1\n");
    178                                 break;
    179                         default:
    180                                 printf("INVALID INDEX in fallback: %d (%d)\n", index, except);
    181                         }
    182                 }
    183                 int fallback_match1(exception except) {
    184                         if (1 == except) {
    185                                 return 1;
    186                         } else {
    187                                 return 0;
    188                         }
    189                 }
    190                 __try_terminate(fallback_try1, fallback_catch1, fallback_match1);
    191         }
    192 }
    193 
    194 // Terminate Throw New Exception:
    195 void terminate_swap() {
    196         raii_t a = {"terminate_swap"};
    197         {
    198                 void fn_try1() {
    199                         terminate(2);
    200                 }
    201                 void fn_catch1(int index, exception except) {
    202                         switch (index) {
    203                         case 1:
    204                                 terminate(1);
    205                                 break;
    206                         default:
    207                                 printf("INVALID INDEX in terminate_swap: %d (%d)\n",
    208                                         index, except);
    209                         }
    210                 }
    211                 int fn_match1(exception except) {
    212                         if (2 == except) {
    213                                 return 1;
    214                         } else {
    215                                 return 0;
    216                         }
    217                 }
    218                 __try_terminate(fn_try1, fn_catch1, fn_match1);
    219         }
    220 }
    221 
    222 void terminate_swapped() {
    223         raii_t a = {"terminate_swapped"};
    224         {
    225                 void fn_try1() {
    226                         terminate_swap();
    227                 }
    228                 void fn_catch1(int index, exception except) {
    229                         switch (index) {
    230                         case 1:
    231                                 printf("terminate_swapped caught exception 1\n");
    232                                 break;
    233                         default:
    234                                 printf("INVALID INDEX in terminate_swapped: %d (%d)\n",
    235                                         index, except);
    236                         }
    237                 }
    238                 int fn_match1(exception except) {
    239                         if (1 == except) {
    240                                 return 1;
    241                         } else {
    242                                 return 0;
    243                         }
    244                 }
    245                 __try_terminate(fn_try1, fn_catch1, fn_match1);
    246         }
    247 }
    248 
    249 // Resume Throw New Exception:
    250 void resume_swap() {
    251         raii_t a = {"terminate_swap"};
    252         {
    253                 bool fn_handle1(exception except) {
    254                         if (2 == except) {
    255                                 resume(1);
    256                                 return true;
    257                         } else {
    258                                 return false;
    259                         }
    260                 }
    261                 struct __try_resume_node node
    262                         __attribute__((cleanup(__try_resume_node_delete)));
    263                 __try_resume_node_new(&node, fn_handle1);
    264                 {
    265                         resume(2);
    266                 }
    267         }
    268 }
    269 
    270 void resume_swapped() {
    271         {
    272                 bool fn_handle1(exception except) {
    273                         if (1 == except) {
    274                                 printf("resume_swapped caught exception 1\n");
    275                                 return true;
    276                         } else {
    277                                 return false;
    278                         }
    279                 }
    280                 struct __try_resume_node node
    281                         __attribute__((cleanup(__try_resume_node_delete)));
    282                 __try_resume_node_new(&node, fn_handle1);
    283                 {
    284                         resume_swap();
    285                 }
    286         }
    287 }
    288 
    289 // Terminate Rethrow:
    290 // I don't have an implementation for this.
    291 
    292 // Resume Rethrow:
    293 void reresume() {
    294         {
    295                 bool reresume_handle1(exception except) {
    296                         if (1 == except) {
    297                                 printf("reresume 1 caught exception 1\n");
    298                                 return true;
    299                         } else {
    300                                 return false;
    301                         }
    302                 }
    303                 struct __try_resume_node node
    304                         __attribute__((cleanup(__try_resume_node_delete)));
    305                 __try_resume_node_new(&node, reresume_handle1);
    306                 {
    307                         bool reresume_handle2(exception except) {
    308                                 if (1 == except) {
    309                                         printf("reresume 2 caught and rethrows exception 1\n");
    310                                         return false;
    311                                 } else {
    312                                         return false;
    313                                 }
    314                         }
    315                         struct __try_resume_node node
    316                                 __attribute__((cleanup(__try_resume_node_delete)));
    317                         __try_resume_node_new(&node, reresume_handle2);
    318                         {
    319                                 resume(1);
    320                         }
    321                 }
    322         }
    323 }
    324 
    325 // Terminate-Resume interaction:
    326 void fum() {
    327         // terminate block, call resume
    328         {
    329                 void fum_try1() {
    330                         resume(3);
    331                 }
    332                 void fum_catch1(int index, exception except) {
    333                         switch (index) {
    334                         case 1:
    335                                 printf("fum caught exception 3\n");
    336                                 break;
    337                         default:
    338                                 printf("INVALID INDEX in fum: %d (%d)\n", index, except);
    339                         }
    340                 }
    341                 int fum_match1(exception except) {
    342                         if (3 == except) {
    343                                 return 1;
    344                         } else {
    345                                 return 0;
    346                         }
    347                 }
    348                 __try_terminate(fum_try1, fum_catch1, fum_match1);
    349         }
    350 }
    351 
    352 void foe() {
    353         // resume block, call terminate
    354         {
    355                 bool foe_handle1(exception except) {
    356                         if (3 == except) {
    357                                 printf("foe caught exception 3\n");
    358                                 return true;
    359                         } else {
    360                                 return false;
    361                         }
    362                 }
    363                 struct __try_resume_node node
    364                         __attribute__((cleanup(__try_resume_node_delete)));
    365                 __try_resume_node_new(&node, foe_handle1);
    366                 {
    367                         terminate(3);
    368                 }
    369         }
    370 }
    371 
    372 void fy() {
    373         // terminate block calls fum, call foe
    374         {
    375                 void fy_try1() {
    376                         foe();
    377                 }
    378                 void fy_catch1(int index, exception except) {
    379                         switch (index) {
    380                         case 1:
    381                                 printf("fy caught exception 3\n");
    382                                 fum();
    383                                 break;
    384                         default:
    385                                 printf("INVALID INDEX in fy: %d (%d)\n", index, except);
    386                         }
    387                 }
    388                 int fy_match1(exception except) {
    389                         if (3 == except) {
    390                                 return 1;
    391                         } else {
    392                                 return 0;
    393                         }
    394                 }
    395                 __try_terminate(fy_try1, fy_catch1, fy_match1);
    396         }
    397 }
    398 
    399 void fee() {
    400         // resume block, call fy
    401         {
    402                 bool fee_handle1(exception except) {
    403                         if (3 == except) {
    404                                 printf("fee caught exception 3\n");
    405                                 return true;
    406                         } else {
    407                                 return false;
    408                         }
    409                 }
    410                 struct __try_resume_node node
    411                         __attribute__((cleanup(__try_resume_node_delete)));
    412                 __try_resume_node_new(&node, fee_handle1);
    413                 {
    414                         fy();
    415                 }
    416         }
    417 }
    418 
    419 
    420 // main: choose which tests to run
    42186int main(int argc, char * argv[]) {
    42287        raii_t a = {"main function"};
    42388
    424         foo(); printf("\n");
    425         alpha(); printf("\n");
    426         farewell(); printf("\n");
    427         fallback(); printf("\n");
    428         terminate_swapped(); printf("\n");
    429         resume_swapped(); printf("\n");
    430         reresume(); printf("\n");
    431         fee(); printf("\n");
    432         // Uncaught termination test.
    433         terminate(7);
     89        foo();
    43490}
  • doc/working/exception/translate.c

    r838ef08 rbf70aa9  
    237237                }
    238238                void finally1() {
    239                         // Finally, because of timing, also works for resume.
    240                         // However this might not actually be better in any way.
     239                        // (Finally, because of timing, also work for resume.)
    241240                        __try_resume_cleanup();
    242241
Note: See TracChangeset for help on using the changeset viewer.