Index: ossp-pkg/ex/00TODO RCS File: /v/ossp/cvs/ossp-pkg/ex/00TODO,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/ex/00TODO,v' 2>/dev/null --- 00TODO 2002/03/07 15:01:30 1.2 +++ 00TODO 2002/03/07 21:30:09 1.3 @@ -1,29 +1,4 @@ -Idea: deferred exceptions: -o ex_defer BLOCK -o if (ex_deferred) ... - -to avoid having to initialize every variable in this context: - -char *cp1; -char *cp2; -char *cp3; -ex_try { - ex_defer { - cp1 = mymalloc(...); - cp2 = mymalloc(...); - cp3 = mymalloc(...); - } -} -ex_cleanup { - if (cp1 != NULL) - free(cp1); - if (cp2 != NULL) - free(cp2); - if (cp3 != NULL) - free(cp3); -} - **** IMPROVE DOCUMENTATION **** /* BAD EXAMPLE */ Index: ossp-pkg/ex/ex.h RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.h,v rcsdiff -q -kk '-r1.16' '-r1.17' -u '/v/ossp/cvs/ossp-pkg/ex/ex.h,v' 2>/dev/null --- ex.h 2002/02/25 10:33:02 1.16 +++ ex.h 2002/03/07 21:30:09 1.17 @@ -94,6 +94,9 @@ /* declare the context type (private) */ typedef struct { __ex_mctx_t *ctx_mctx; /* permanent machine context of enclosing try/catch */ + int ctx_deferred; /* permanent flag whether exception is deferred */ + int ctx_deferring;/* permanent counter of exception deferring level */ + int ctx_defer; /* temporary flag for exception deferring macro */ int ctx_shielding;/* permanent counter of exception shielding level */ int ctx_shield; /* temporary flag for exception shielding macro */ int ctx_caught; /* temporary flag whether exception was caught */ @@ -103,10 +106,13 @@ /* the static and dynamic initializers for a context structure */ #define EX_CTX_INITIALIZER \ - { NULL, 0, 0, 0, 0, { NULL, NULL, NULL, NULL, 0, NULL } } + { NULL, 0, 0, 0, 0, 0, 0, 0, { NULL, NULL, NULL, NULL, 0, NULL } } #define EX_CTX_INITIALIZE(ctx) \ do { \ (ctx)->ctx_mctx = NULL; \ + (ctx)->ctx_deferred = 0; \ + (ctx)->ctx_deferring = 0; \ + (ctx)->ctx_defer = 0; \ (ctx)->ctx_shielding = 0; \ (ctx)->ctx_shield = 0; \ (ctx)->ctx_caught = 0; \ @@ -178,20 +184,24 @@ /* the throwing of a new exception */ #define ex_throw(c,o,v) \ - (__ex_ctx()->ctx_shielding > 0 ? 0 : \ + (( __ex_ctx()->ctx_shielding > 0 \ + || (__ex_ctx()->ctx_deferring > 0 && __ex_ctx()->ctx_deferred == 1)) ? 0 : \ (__ex_ctx()->ctx_ex.ex_class = (void *)(c), \ __ex_ctx()->ctx_ex.ex_object = (void *)(o), \ __ex_ctx()->ctx_ex.ex_value = (void *)(v), \ __ex_ctx()->ctx_ex.ex_file = __FILE__, \ __ex_ctx()->ctx_ex.ex_line = __LINE__, \ __ex_ctx()->ctx_ex.ex_func = __EX_FUNC__, \ - ( __ex_ctx()->ctx_mctx == NULL \ - ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ - : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) ))) + __ex_ctx()->ctx_deferred = 1, \ + (__ex_ctx()->ctx_deferring > 0 ? 0 : \ + (__ex_ctx()->ctx_mctx == NULL \ + ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ + : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) )))) /* the re-throwing of an already caught exception */ #define ex_rethrow \ - (__ex_ctx()->ctx_shielding > 0 ? 0 : \ + (( __ex_ctx()->ctx_shielding > 0 \ + || __ex_ctx()->ctx_deferring > 0) ? 0 : \ ( __ex_ctx()->ctx_mctx == NULL \ ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) )) @@ -204,11 +214,21 @@ __ex_ctx()->ctx_shield = 0, \ __ex_ctx()->ctx_shielding--) +/* defer immediate exception handling */ +#define ex_defer \ + for (((__ex_ctx()->ctx_deferring)++ == 0 ? __ex_ctx()->ctx_deferred = 0 : 0), \ + __ex_ctx()->ctx_defer = 1; \ + __ex_ctx()->ctx_defer == 1; \ + __ex_ctx()->ctx_defer = 0, \ + ((--(__ex_ctx()->ctx_deferring) == 0 && __ex_ctx()->ctx_deferred == 1) ? ex_rethrow : 0)) + /* exception handling tests */ #define ex_catching \ (__ex_ctx()->ctx_mctx != NULL) #define ex_shielding \ (__ex_ctx()->ctx_shielding > 0) +#define ex_deferring \ + (__ex_ctx()->ctx_deferring > 0) /* optional namespace mapping */ #if defined(__EX_NS_UCCXX__) @@ -218,6 +238,7 @@ #define Throw ex_throw #define Rethrow ex_rethrow #define Shield ex_shield +#define Defer ex_defer #elif defined(__EX_NS_CXX__) || (!defined(__cplusplus) && !defined(__EX_NS_CUSTOM__)) #define try ex_try #define cleanup ex_cleanup @@ -225,6 +246,7 @@ #define throw ex_throw #define rethrow ex_rethrow #define shield ex_shield +#define defer ex_defer #endif #endif /* __EX_H__ */ Index: ossp-pkg/ex/ex.pod RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.pod,v rcsdiff -q -kk '-r1.20' '-r1.21' -u '/v/ossp/cvs/ossp-pkg/ex/ex.pod,v' 2>/dev/null --- ex.pod 2002/02/25 10:30:15 1.20 +++ ex.pod 2002/03/07 21:30:10 1.21 @@ -48,10 +48,14 @@ B; +B I + B I if (B) ... +if (B) ... + if (B) ... =head1 DESCRIPTION @@ -214,6 +218,22 @@ C and C elements of the caught exception are passed through as it would have been never caught. +=item B I + +This directive executes I while deferring the throwing of +exceptions, i.e., inside the dynamic scope of B all +B operations are silently ignored and on leaving the I +the first occurred exception is thrown. + +The B block is a regular B language statement block, +but it is not allowed to jump into it via C or C(3) or +out of it via C, C, C or C(3) because this +would cause the deferral level to become out of sync. Jumping into +an B clause would avoid increasing the exception deferral +level, and jumping out of it would avoid decreasing it. In both cases +the result is an incorrect exception deferral level. Nevertheless you +are allowed to nest B clauses. + =item B I This directive executes I while shielding it against the throwing @@ -235,6 +255,12 @@ of an B clause to test whether the current scope is exception catching. +=item B + +This is a boolean flag which can be checked inside the dynamic scope of +an B clause to test whether the current scope is exception +deferring. + =item B This is a boolean flag which can be checked inside the dynamic scope of @@ -656,7 +682,10 @@ Adam M. Costello Eamc@cs.berkeley.eduE and Cosmin Truta Ecosmin@cs.toronto.eduE. The B clause was inspired by the B C clause. The B feature was inspired by an -C shielding facility used in the B implementation. +C shielding facility used in the B implementation. The +B feature was invented to simplify an application's cleanup +handling if multiple independent resources are allocated and have to be +freed on error. =head1 AUTHORS Index: ossp-pkg/ex/ex_test.c RCS File: /v/ossp/cvs/ossp-pkg/ex/ex_test.c,v rcsdiff -q -kk '-r1.8' '-r1.9' -u '/v/ossp/cvs/ossp-pkg/ex/ex_test.c,v' 2>/dev/null --- ex_test.c 2002/01/30 10:40:07 1.8 +++ ex_test.c 2002/03/07 21:30:10 1.9 @@ -111,6 +111,44 @@ } } +TS_TEST(test_defer) +{ + ex_t ex; + volatile int i1 = 0; + volatile int i2 = 0; + volatile int i3 = 0; + + ts_test_check(TS_CTX, "exception deferring"); + if (ex_deferring) + ts_test_fail(TS_CTX, "unexpected deferring scope"); + ex_try { + ex_defer { + if (!ex_deferring) + ts_test_fail(TS_CTX, "unexpected non-deferring scope"); + ex_defer { + i1 = 1; + ex_throw(0, 0, 4711); + i2 = 2; + ex_throw(0, 0, 0); + i3 = 3; + ex_throw(0, 0, 0); + } + ex_throw(0, 0, 0); + } + ts_test_fail(TS_CTX, "unexpected not occurred deferred throwing"); + } + ex_catch (ex) { + if ((long)ex.ex_value != (long)4711) + ts_test_fail(TS_CTX, "caught exception with value %d, expected 4711", (long)ex.ex_value); + } + if (i1 != 1) + ts_test_fail(TS_CTX, "v.i1 not set (expected 1, got %d)", i1); + if (i2 != 2) + ts_test_fail(TS_CTX, "v.i2 not set (expected 2, got %d)", i2); + if (i3 != 3) + ts_test_fail(TS_CTX, "v.i3 not set (expected 3, got %d)", i3); +} + TS_TEST(test_shield) { ex_t ex; @@ -178,6 +216,7 @@ ts_suite_test(ts, test_controlflow, "basic nested control flow"); ts_suite_test(ts, test_value, "exception value passing"); ts_suite_test(ts, test_variables, "variable value preservation"); + ts_suite_test(ts, test_defer, "exception deferring"); ts_suite_test(ts, test_shield, "exception shielding"); ts_suite_test(ts, test_cleanup, "cleanup handling"); n = ts_suite_run(ts);