exception
This commit is contained in:
parent
0fae01c975
commit
a6b327fb69
|
@ -13,8 +13,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TD_UTIL_EXCEPTION_H
|
||||
#define _TD_UTIL_EXCEPTION_H
|
||||
#ifndef _TD_UTIL_EXCEPTION_H_
|
||||
#define _TD_UTIL_EXCEPTION_H_
|
||||
|
||||
#include "os.h"
|
||||
|
||||
|
@ -26,100 +26,106 @@ extern "C" {
|
|||
* 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;
|
||||
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;
|
||||
|
||||
|
||||
/*
|
||||
* exception hander registration
|
||||
*/
|
||||
typedef struct SExceptionNode {
|
||||
struct SExceptionNode* prev;
|
||||
jmp_buf jb;
|
||||
int32_t code;
|
||||
int32_t maxCleanupAction;
|
||||
int32_t numCleanupAction;
|
||||
SCleanupAction* cleanupActions;
|
||||
struct SExceptionNode* prev;
|
||||
jmp_buf jb;
|
||||
int32_t code;
|
||||
int32_t maxCleanupAction;
|
||||
int32_t numCleanupAction;
|
||||
SCleanupAction* cleanupActions;
|
||||
} SExceptionNode;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// functions & macros for auto-cleanup
|
||||
|
||||
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 );
|
||||
void cleanupPush_int_ptr ( bool failOnly, void* func, void* arg );
|
||||
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);
|
||||
void cleanupPush_int_ptr(bool failOnly, void* func, void* arg);
|
||||
|
||||
int32_t cleanupGetActionCount();
|
||||
void cleanupExecuteTo( int32_t anchor, bool failed );
|
||||
void cleanupExecute( SExceptionNode* node, bool failed );
|
||||
bool cleanupExceedLimit();
|
||||
void cleanupExecuteTo(int32_t anchor, bool failed);
|
||||
void cleanupExecute(SExceptionNode* node, bool failed);
|
||||
bool cleanupExceedLimit();
|
||||
|
||||
#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_INT_PTR( failOnly, func, arg ) cleanupPush_int_ptr( (failOnly), (void*)(func), (void*)(arg) )
|
||||
#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_PUSH_FCLOSE( failOnly, arg ) cleanupPush_int_ptr( (failOnly), fclose, (void*)(arg) )
|
||||
#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_INT_PTR(failOnly, func, arg) cleanupPush_int_ptr((failOnly), (void*)(func), (void*)(arg))
|
||||
#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_PUSH_FCLOSE(failOnly, arg) cleanupPush_int_ptr((failOnly), fclose, (void*)(arg))
|
||||
|
||||
#define CLEANUP_GET_ANCHOR() cleanupGetActionCount()
|
||||
#define CLEANUP_EXECUTE_TO( anchor, failed ) cleanupExecuteTo( (anchor), (failed) )
|
||||
#define CLEANUP_EXCEED_LIMIT() cleanupExceedLimit()
|
||||
#define CLEANUP_GET_ANCHOR() cleanupGetActionCount()
|
||||
#define CLEANUP_EXECUTE_TO(anchor, failed) cleanupExecuteTo((anchor), (failed))
|
||||
#define CLEANUP_EXCEED_LIMIT() cleanupExceedLimit()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// functions & macros for exception handling
|
||||
|
||||
void exceptionPushNode( SExceptionNode* node );
|
||||
void exceptionPushNode(SExceptionNode* node);
|
||||
int32_t exceptionPopNode();
|
||||
void exceptionThrow( int32_t code );
|
||||
void exceptionThrow(int32_t code);
|
||||
|
||||
#define TRY(maxCleanupActions) do { \
|
||||
SExceptionNode exceptionNode = { 0 }; \
|
||||
SCleanupAction cleanupActions[(maxCleanupActions) > 0 ? (maxCleanupActions) : 1]; \
|
||||
#define TRY(maxCleanupActions) \
|
||||
do { \
|
||||
SExceptionNode exceptionNode = {0}; \
|
||||
SCleanupAction cleanupActions[(maxCleanupActions) > 0 ? (maxCleanupActions) : 1]; \
|
||||
exceptionNode.maxCleanupAction = (maxCleanupActions) > 0 ? (maxCleanupActions) : 1; \
|
||||
exceptionNode.cleanupActions = cleanupActions; \
|
||||
exceptionPushNode( &exceptionNode ); \
|
||||
int caughtException = setjmp( exceptionNode.jb ); \
|
||||
if( caughtException == 0 )
|
||||
exceptionNode.cleanupActions = cleanupActions; \
|
||||
exceptionPushNode(&exceptionNode); \
|
||||
int caughtException = setjmp(exceptionNode.jb); \
|
||||
if (caughtException == 0)
|
||||
|
||||
#define CATCH( code ) int32_t code = exceptionPopNode(); \
|
||||
if( caughtException == 1 )
|
||||
#define CATCH(code) \
|
||||
int32_t code = exceptionPopNode(); \
|
||||
if (caughtException == 1)
|
||||
|
||||
#define FINALLY( code ) int32_t code = exceptionPopNode();
|
||||
#define FINALLY(code) int32_t code = exceptionPopNode();
|
||||
|
||||
#define END_TRY } while( 0 );
|
||||
#define END_TRY \
|
||||
} \
|
||||
while (0) \
|
||||
;
|
||||
|
||||
#define THROW( x ) exceptionThrow( (x) )
|
||||
#define CAUGHT_EXCEPTION() ((bool)(caughtException == 1))
|
||||
#define CLEANUP_EXECUTE() cleanupExecute( &exceptionNode, CAUGHT_EXCEPTION() )
|
||||
#define THROW(x) exceptionThrow((x))
|
||||
#define CAUGHT_EXCEPTION() ((bool)(caughtException == 1))
|
||||
#define CLEANUP_EXECUTE() cleanupExecute(&exceptionNode, CAUGHT_EXCEPTION())
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*_TD_UTIL_EXCEPTION_H*/
|
||||
#endif /*_TD_UTIL_EXCEPTION_H_*/
|
||||
|
|
|
@ -13,154 +13,137 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "os.h"
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "exception.h"
|
||||
|
||||
static threadlocal SExceptionNode* expList;
|
||||
|
||||
void exceptionPushNode( SExceptionNode* node ) {
|
||||
node->prev = expList;
|
||||
expList = node;
|
||||
void exceptionPushNode(SExceptionNode* node) {
|
||||
node->prev = expList;
|
||||
expList = node;
|
||||
}
|
||||
|
||||
int32_t exceptionPopNode() {
|
||||
SExceptionNode* node = expList;
|
||||
expList = node->prev;
|
||||
return node->code;
|
||||
SExceptionNode* node = expList;
|
||||
expList = node->prev;
|
||||
return node->code;
|
||||
}
|
||||
|
||||
void exceptionThrow( int32_t code ) {
|
||||
expList->code = code;
|
||||
longjmp( expList->jb, 1 );
|
||||
void exceptionThrow(int32_t code) {
|
||||
expList->code = code;
|
||||
longjmp(expList->jb, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void cleanupWrapper_void_ptr_ptr( SCleanupAction* ca ) {
|
||||
void (*func)( void*, void* ) = ca->func;
|
||||
func( ca->arg1.Ptr, ca->arg2.Ptr );
|
||||
static void cleanupWrapper_void_ptr_ptr(SCleanupAction* ca) {
|
||||
void (*func)(void*, void*) = ca->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 );
|
||||
static void cleanupWrapper_void_ptr_bool(SCleanupAction* ca) {
|
||||
void (*func)(void*, bool) = ca->func;
|
||||
func(ca->arg1.Ptr, ca->arg2.Bool);
|
||||
}
|
||||
|
||||
static void cleanupWrapper_void_ptr( SCleanupAction* ca ) {
|
||||
void (*func)( void* ) = ca->func;
|
||||
func( ca->arg1.Ptr );
|
||||
static void cleanupWrapper_void_ptr(SCleanupAction* ca) {
|
||||
void (*func)(void*) = ca->func;
|
||||
func(ca->arg1.Ptr);
|
||||
}
|
||||
|
||||
static void cleanupWrapper_int_int( SCleanupAction* ca ) {
|
||||
int (*func)( int ) = ca->func;
|
||||
func( ca->arg1.Int );
|
||||
static void cleanupWrapper_int_int(SCleanupAction* ca) {
|
||||
int32_t (*func)(int32_t) = ca->func;
|
||||
func(ca->arg1.Int);
|
||||
}
|
||||
|
||||
static void cleanupWrapper_void( SCleanupAction* ca ) {
|
||||
void (*func)() = ca->func;
|
||||
func();
|
||||
static void cleanupWrapper_void(SCleanupAction* ca) {
|
||||
void (*func)() = ca->func;
|
||||
func();
|
||||
}
|
||||
|
||||
static void cleanupWrapper_int_ptr( SCleanupAction* ca ) {
|
||||
int (*func)( void* ) = ca->func;
|
||||
func( ca->arg1.Ptr );
|
||||
static void cleanupWrapper_int_ptr(SCleanupAction* ca) {
|
||||
int32_t (*func)(void*) = ca->func;
|
||||
func(ca->arg1.Ptr);
|
||||
}
|
||||
|
||||
typedef void (*wrapper)(SCleanupAction*);
|
||||
static wrapper wrappers[] = {
|
||||
cleanupWrapper_void_ptr_ptr,
|
||||
cleanupWrapper_void_ptr_bool,
|
||||
cleanupWrapper_void_ptr,
|
||||
cleanupWrapper_int_int,
|
||||
cleanupWrapper_void,
|
||||
cleanupWrapper_int_ptr,
|
||||
cleanupWrapper_void_ptr_ptr, cleanupWrapper_void_ptr_bool, cleanupWrapper_void_ptr,
|
||||
cleanupWrapper_int_int, cleanupWrapper_void, cleanupWrapper_int_ptr,
|
||||
};
|
||||
|
||||
void cleanupPush_void_ptr_ptr(bool failOnly, void* func, void* arg1, void* arg2) {
|
||||
assert(expList->numCleanupAction < expList->maxCleanupAction);
|
||||
|
||||
void cleanupPush_void_ptr_ptr( bool failOnly, void* func, void* arg1, void* arg2 ) {
|
||||
assert( expList->numCleanupAction < expList->maxCleanupAction );
|
||||
|
||||
SCleanupAction *ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 0;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg1;
|
||||
ca->arg2.Ptr = arg2;
|
||||
SCleanupAction* ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 0;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg1;
|
||||
ca->arg2.Ptr = arg2;
|
||||
}
|
||||
|
||||
void cleanupPush_void_ptr_bool( bool failOnly, void* func, void* arg1, bool arg2 ) {
|
||||
assert( expList->numCleanupAction < expList->maxCleanupAction );
|
||||
void cleanupPush_void_ptr_bool(bool failOnly, void* func, void* arg1, bool arg2) {
|
||||
assert(expList->numCleanupAction < expList->maxCleanupAction);
|
||||
|
||||
SCleanupAction *ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 1;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg1;
|
||||
ca->arg2.Bool = arg2;
|
||||
SCleanupAction* ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 1;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg1;
|
||||
ca->arg2.Bool = arg2;
|
||||
}
|
||||
|
||||
void cleanupPush_void_ptr( bool failOnly, void* func, void* arg ) {
|
||||
assert( expList->numCleanupAction < expList->maxCleanupAction );
|
||||
void cleanupPush_void_ptr(bool failOnly, void* func, void* arg) {
|
||||
assert(expList->numCleanupAction < expList->maxCleanupAction);
|
||||
|
||||
SCleanupAction *ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 2;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg;
|
||||
SCleanupAction* ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 2;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg;
|
||||
}
|
||||
|
||||
void cleanupPush_int_int( bool failOnly, void* func, int arg ) {
|
||||
assert( expList->numCleanupAction < expList->maxCleanupAction );
|
||||
void cleanupPush_int_int(bool failOnly, void* func, int32_t arg) {
|
||||
assert(expList->numCleanupAction < expList->maxCleanupAction);
|
||||
|
||||
SCleanupAction *ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 3;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Int = arg;
|
||||
SCleanupAction* ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 3;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Int = arg;
|
||||
}
|
||||
|
||||
void cleanupPush_void( bool failOnly, void* func ) {
|
||||
assert( expList->numCleanupAction < expList->maxCleanupAction );
|
||||
void cleanupPush_void(bool failOnly, void* func) {
|
||||
assert(expList->numCleanupAction < expList->maxCleanupAction);
|
||||
|
||||
SCleanupAction *ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 4;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
SCleanupAction* ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 4;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
}
|
||||
|
||||
void cleanupPush_int_ptr( bool failOnly, void* func, void* arg ) {
|
||||
assert( expList->numCleanupAction < expList->maxCleanupAction );
|
||||
void cleanupPush_int_ptr(bool failOnly, void* func, void* arg) {
|
||||
assert(expList->numCleanupAction < expList->maxCleanupAction);
|
||||
|
||||
SCleanupAction *ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 5;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg;
|
||||
SCleanupAction* ca = expList->cleanupActions + expList->numCleanupAction++;
|
||||
ca->wrapper = 5;
|
||||
ca->failOnly = failOnly;
|
||||
ca->func = func;
|
||||
ca->arg1.Ptr = arg;
|
||||
}
|
||||
|
||||
int32_t cleanupGetActionCount() { return expList->numCleanupAction; }
|
||||
|
||||
int32_t cleanupGetActionCount() {
|
||||
return expList->numCleanupAction;
|
||||
}
|
||||
|
||||
|
||||
static void doExecuteCleanup( SExceptionNode* node, int32_t anchor, bool failed ) {
|
||||
while( node->numCleanupAction > anchor ) {
|
||||
--node->numCleanupAction;
|
||||
SCleanupAction *ca = node->cleanupActions + node->numCleanupAction;
|
||||
if( failed || !(ca->failOnly) ) {
|
||||
wrappers[ca->wrapper]( ca );
|
||||
}
|
||||
static void doExecuteCleanup(SExceptionNode* node, int32_t anchor, bool failed) {
|
||||
while (node->numCleanupAction > anchor) {
|
||||
--node->numCleanupAction;
|
||||
SCleanupAction* ca = node->cleanupActions + node->numCleanupAction;
|
||||
if (failed || !(ca->failOnly)) {
|
||||
wrappers[ca->wrapper](ca);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cleanupExecuteTo( int32_t anchor, bool failed ) {
|
||||
doExecuteCleanup( expList, anchor, failed );
|
||||
}
|
||||
void cleanupExecuteTo(int32_t anchor, bool failed) { doExecuteCleanup(expList, anchor, failed); }
|
||||
|
||||
void cleanupExecute( SExceptionNode* node, bool failed ) {
|
||||
doExecuteCleanup( node, 0, failed );
|
||||
}
|
||||
bool cleanupExceedLimit() {
|
||||
return expList->numCleanupAction >= expList->maxCleanupAction;
|
||||
}
|
||||
void cleanupExecute(SExceptionNode* node, bool failed) { doExecuteCleanup(node, 0, failed); }
|
||||
bool cleanupExceedLimit() { return expList->numCleanupAction >= expList->maxCleanupAction; }
|
||||
|
|
Loading…
Reference in New Issue