diff --git a/src/util/inc/exception.h b/src/util/inc/exception.h index 19c37561d2388519058a47ce7e58795011c416e4..229ba89d04ec28bbcc4ae822f8b74fffc4cf961e 100644 --- a/src/util/inc/exception.h +++ b/src/util/inc/exception.h @@ -25,73 +25,87 @@ extern "C" { #endif /* - * exception handling + * cleanup actions + */ +typedef struct SCleanupAction { + bool failOnly; + uint8_t wrapper; + uint16_t reserved; + void* func; + union { + void* Ptr; + bool Bool; + char Char; + int8_t Int8; + uint8_t Uint8; + int16_t Int16; + uint16_t Uint16; + int Int; + unsigned int Uint; + int32_t Int32; + uint32_t Uint32; + int64_t Int64; + uint64_t Uint64; + float Float; + double Double; + } arg1, arg2; +} SCleanupAction; + +void cleanupPush_void_ptr_ptr ( bool failOnly, void* func, void* arg1, void* arg2 ); +void cleanupPush_void_ptr_bool ( bool failOnly, void* func, void* arg1, bool arg2 ); +void cleanupPush_void_ptr ( bool failOnly, void* func, void* arg ); +void cleanupPush_int_int ( bool failOnly, void* func, int arg ); +void cleanupPush_void ( bool failOnly, void* func ); + +int32_t cleanupGetActionCount(); +void cleanupExecute( bool failed, int32_t toIndex ); + +#define CLEANUP_PUSH_VOID_PTR_PTR( failOnly, func, arg1, arg2 ) cleanupPush_void_ptr_ptr( (failOnly), (void*)(func), (void*)(arg1), (void*)(arg2) ) +#define CLEANUP_PUSH_VOID_PTR_BOOL( failOnly, func, arg1, arg2 ) cleanupPush_void_ptr_bool( (failOnly), (void*)(func), (void*)(arg1), (bool)(arg2) ) +#define CLEANUP_PUSH_VOID_PTR( failOnly, func, arg ) cleanupPush_void_ptr( (failOnly), (void*)(func), (void*)(arg) ) +#define CLEANUP_PUSH_INT_INT( failOnly, func, arg ) cleanupPush_void_ptr( (failOnly), (void*)(func), (int)(arg) ) +#define CLEANUP_PUSH_VOID( failOnly, func ) cleanupPush_void( (failOnly), (void*)(func) ) +#define CLEANUP_PUSH_FREE( failOnly, arg ) cleanupPush_void_ptr( (failOnly), free, (void*)(arg) ) +#define CLEANUP_PUSH_CLOSE( failOnly, arg ) cleanupPush_int_int( (failOnly), close, (int)(arg) ) + +#define CLEANUP_CREATE_ANCHOR() int32_t cleanupAnchor = cleanupGetActionCount() +#define CLEANUP_EXECUTE( failed ) cleanupExecute( cleanupAnchor, (failed) ) + +/* + * exception hander registration */ typedef struct SExceptionNode { struct SExceptionNode* prev; jmp_buf jb; - int code; + int32_t code; + int32_t maxCleanupAction; + int32_t numCleanupAction; + SCleanupAction* cleanupActions; } SExceptionNode; void exceptionPushNode( SExceptionNode* node ); -int exceptionPopNode(); +int32_t exceptionPopNode(); void exceptionThrow( int code ); -#define THROW( x ) exceptionThrow( (x) ) -#define CAUGHT_EXCEPTION() (caught_exception == 1) - -#define TRY do { \ - SExceptionNode expNode = { 0 }; \ - exceptionPushNode( &expNode ); \ - int caught_exception = setjmp(expNode.jb); \ - if( caught_exception == 0 ) +#define TRY(maxCleanupActions) do { \ + SExceptionNode exceptionNode = { 0 }; \ + SDeferedOperation cleanupActions[maxCleanupActions > 0 ? maxCleanupActions : 1]; \ + exceptionNode.maxCleanupAction = maxCleanupActions > 0 ? maxDefered : 1; \ + exceptionNode.cleanupActions = cleanupActions; \ + int32_t cleanupAnchor = 0; \ + exceptionPushNode( &exceptionNode ); \ + int caughtException = setjmp( exceptionNode.jb ); \ + if( caughtException == 0 ) #define CATCH( code ) int code = exceptionPopNode(); \ - if( caught_exception == 1 ) + if( caughtEexception == 1 ) #define FINALLY( code ) int code = exceptionPopNode(); #define END_TRY } while( 0 ); - -/* - * defered operations - */ -typedef struct SDeferedOperation { - void (*wrapper)( struct SDeferedOperation* dp ); - void* func; - void* arg; -} SDeferedOperation; - -void deferExecute( SDeferedOperation* operations, unsigned int numOfOperations ); -void deferWrapper_void_void( SDeferedOperation* dp ); -void deferWrapper_void_ptr( SDeferedOperation* dp ); -void deferWrapper_int_int( SDeferedOperation* dp ); - -#define DEFER_INIT( MaxOperations ) unsigned int maxDeferedOperations = MaxOperations, numOfDeferedOperations = 0; \ - SDeferedOperation deferedOperations[MaxOperations] - -#define DEFER_PUSH( wrapperFunc, deferedFunc, argument ) do { \ - assert( numOfDeferedOperations < maxDeferedOperations ); \ - SDeferedOperation* dp = deferedOperations + numOfDeferedOperations++; \ - dp->wrapper = wrapperFunc; \ - dp->func = (void*)deferedFunc; \ - dp->arg = (void*)argument; \ -} while( 0 ) - -#define DEFER_POP() do { --numOfDeferedOperations; } while( 0 ) - -#define DEFER_EXECUTE() do{ \ - deferExecute( deferedOperations, numOfDeferedOperations ); \ - numOfDeferedOperations = 0; \ -} while( 0 ) - -#define DEFER_PUSH_VOID_PTR( func, arg ) DEFER_PUSH( deferWrapper_void_ptr, func, arg ) -#define DEFER_PUSH_INT_INT( func, arg ) DEFER_PUSH( deferWrapper_int_int, func, arg ) -#define DEFER_PUSH_VOID_VOID( func ) DEFER_PUSH( deferWrapper_void_void, func, 0 ) - -#define DEFER_PUSH_FREE( arg ) DEFER_PUSH( deferWrapper_void_ptr, free, arg ) -#define DEFER_PUSH_CLOSE( arg ) DEFER_PUSH( deferWrapper_int_int, close, arg ) +#define THROW( x ) exceptionThrow( (x) ) +#define CAUGHT_EXCEPTION() ((bool)(caughtEexception == 1)) #ifdef __cplusplus } diff --git a/src/util/src/exception.c b/src/util/src/exception.c index 45ebd349a59336b2673b6fe47fc5e2f57fe98332..b0e8fce371813048123b67e261d72424d26b6777 100644 --- a/src/util/src/exception.c +++ b/src/util/src/exception.c @@ -8,7 +8,7 @@ void exceptionPushNode( SExceptionNode* node ) { expList = node; } -int exceptionPopNode() { +int32_t exceptionPopNode() { SExceptionNode* node = expList; expList = node->prev; return node->code; @@ -19,25 +19,105 @@ void exceptionThrow( int code ) { longjmp( expList->jb, 1 ); } -void deferWrapper_void_ptr( SDeferedOperation* dp ) { - void (*func)( void* ) = dp->func; - func( dp->arg ); + + +static void cleanupWrapper_void_ptr_ptr( SCleanupAction* ca ) { + void (*func)( void*, void* ) = ac->func; + func( ca->arg1.Ptr, ca->arg2.Ptr ); +} + +static void cleanupWrapper_void_ptr_bool( SCleanupAction* ca ) { + void (*func)( void*, bool ) = ca->func; + func( ca->arg1.Ptr, ca->arg2.Bool ); } -void deferWrapper_int_int( SDeferedOperation* dp ) { - int (*func)( int ) = dp->func; - func( (int)(intptr_t)(dp->arg) ); +static void cleanupWrapper_void_ptr( SCleanupAction* ca ) { + void (*func)( void* ) = ca->func; + func( ca->arg1.Ptr ); } -void deferWrapper_void_void( SDeferedOperation* dp ) { - void (*func)() = dp->func; +static void cleanupWrapper_int_int( SCleanupAction* ca ) { + int (*func)( int ) = ca->func; + func( (int)(intptr_t)(ca->arg1.Int) ); +} + +static void cleanupWrapper_void_void( SCleanupAction* ca ) { + void (*func)() = ca->func; func(); } -void deferExecute( SDeferedOperation* operations, unsigned int numOfOperations ) { - while( numOfOperations > 0 ) { - --numOfOperations; - SDeferedOperation* dp = operations + numOfOperations; - dp->wrapper( dp ); +static void (*wrappers)(SCleanupAction*)[] = { + cleanupWrapper_void_ptr_ptr, + cleanupWrapper_void_ptr_bool, + cleanupWrapper_void_ptr, + cleanupWrapper_int_int, + cleanupWrapper_void_void, +}; + + +void cleanupPush_void_ptr_ptr( bool failOnly, void* func, void* arg1, void* arg2 ) { + assert( expList->numCleanupAction < expList->maxCleanupAction ); + + SCleanupAction *ac = expList->cleanupActions + expList->numCleanupAction++; + ac->wrapper = 0; + ac->failOnly = failOnly; + ac->func = func; + ac->arg1.Ptr = arg1; + ac->arg2.Ptr = arg2; +} + +void cleanupPush_void_ptr_bool( bool failOnly, void* func, void* arg1, bool arg2 ) { + assert( expList->numCleanupAction < expList->maxCleanupAction ); + + SCleanupAction *ac = expList->cleanupActions + expList->numCleanupAction++; + ac->wrapper = 1; + ac->failOnly = failOnly; + ac->func = func; + ac->arg1.Ptr = arg1; + ac->arg2.Bool = arg2; +} + +void cleanupPush_void_ptr( bool failOnly, void* func, void* arg ) { + assert( expList->numCleanupAction < expList->maxCleanupAction ); + + SCleanupAction *ac = expList->cleanupActions + expList->numCleanupAction++; + ac->wrapper = 2; + ac->failOnly = failOnly; + ac->func = func; + ac->arg1.Ptr = arg1; +} + +void cleanupPush_int_int( bool failOnly, void* func, int arg ) { + assert( expList->numCleanupAction < expList->maxCleanupAction ); + + SCleanupAction *ac = expList->cleanupActions + expList->numCleanupAction++; + ac->wrapper = 3; + ac->failOnly = failOnly; + ac->func = func; + ac->arg1.Int = arg; +} + +void cleanupPush_void( bool failOnly, void* func ) { + assert( expList->numCleanupAction < expList->maxCleanupAction ); + + SCleanupAction *ac = expList->cleanupActions + expList->numCleanupAction++; + ac->wrapper = 4; + ac->failOnly = failOnly; + ac->func = func; +} + + + +int32 cleanupGetActionCount() { + return expList->numCleanupAction; +} + + +void cleanupExecute( int32_t anchor, bool failed ) { + while( expList->numCleanupAction > anchor ) { + --expList->numCleanupAction; + SCleanupAction *ac = expList->cleanupActions + expList->numCleanupAction; + if( failed || !(ac->failOnly) ) + ac->wrapper( ac ); } }