#ifndef XXL_H #define XXL_H #ifndef WIN32 /* BEGIN: autoconf substitutions */ #undef HAVE_SETJMP_H #undef HAVE_PTHREAD_H #undef HAVE_SYS_TYPES_H #undef STDC_HEADERS #undef XXL_WITHOUT_THREADS #undef const /* END: autoconf substitutions */ #define XXL_API #else #ifdef XXL_EXPORTS #define XXL_API __declspec(dllexport) #else #define XXL_API __declspec(dllimport) #endif #endif #if !defined(XXL_WITHOUT_THREADS) && !defined(WIN32) && !defined(HAVE_PTHREAD_H) #define XXL_WITHOUT_THREADS #endif #ifdef WIN32 #include #include #endif #include #if defined(HAVE_SYS_TYPES_H) #include #endif #if defined(HAVE_SETJMP_H) || defined(WIN32) #include #endif #if !defined(WIN32) && defined(STDC_HEADERS) #include #endif #if !defined(XXL_WITHOUT_THREADS) && defined(HAVE_PTHREAD_H) #include #endif #define XXL_ERROR_THREAD_CANCELLED 0xFFFFFFFF #define XXL_ERROR_RETRY_EXCEPTION 0xFFFFFFFE #ifdef __cplusplus extern "C" { #endif typedef enum _xxl_assettype_t { XXL_ASSET_PERMANENT, XXL_ASSET_PROMOTE, XXL_ASSET_TEMPORARY, XXL_ASSET_AUTO, XXL_ASSET_DEMOTE } xxl_assettype_t; typedef void (*xxl_assetfreefn_t)(void *, void *); typedef struct _xxl_asset_t xxl_asset_t; typedef struct _xxl_context_t xxl_context_t; typedef struct _xxl_exception_t xxl_exception_t; typedef struct _xxl_tsd_t xxl_tsd_t; struct _xxl_asset_t { void *ptr; xxl_assetfreefn_t freefn; void *arg; xxl_assettype_t type; xxl_asset_t *next; }; struct _xxl_exception_t { int code; void *data; const char *file; unsigned int line; }; struct _xxl_context_t { jmp_buf *context; unsigned int state; xxl_exception_t exception; xxl_exception_t pending; #if !defined(WIN32) && !defined(XXL_WITHOUT_THREADS) int cancel_type; #endif xxl_asset_t *assets; xxl_context_t *next; }; struct _xxl_tsd_t { xxl_context_t *contexts; #if !defined(WIN32) || defined(XXL_WITHOUT_THREADS) xxl_context_t *free_contexts; xxl_asset_t *free_assets; #endif }; #define XXL_ASSET_ALL 0 #define XXL_ASSET_CURRENT 1 #define XXL_ASSET_FIRST 2 /* These are only used internally */ #define XXL_SETJMP_TRY 0x00 #define XXL_SETJMP_ERROR 0x01 #define XXL_SETJMP_RETRY 0x02 #define XXL_SETJMP_PROMOTE 0x03 #define XXL_SETJMP_LEAVE 0x04 #define XXL_SETJMP_PENDING 0x05 #define XXL_SETJMP_MASK 0xFF #define XXL_STATE_HANDLED 0x00000100 #define XXL_STATE_FINALLY 0x00000200 #define XXL_STATE_PENDING 0x00000400 #define XXL_STATE_THROWN 0x00000800 #define XXL_STATE_MASK 0x0000FF00 /* Public Macros */ #define XXL_ASSET_BLOCK_BEGIN \ do \ { \ xxl_push_context(NULL); \ { #define XXL_ASSET_BLOCK_END \ } \ xxl_pop_context(); \ } while (0) #define XXL_ASSET_SAVE(asset, callback, arg, type) \ xxl_push_asset((asset), (xxl_assetfreefn_t)(callback), (arg), (type)) #define XXL_ASSET_UPDATE(old_asset, new_asset) \ xxl_update_asset((old_asset), (new_asset)) #define XXL_ASSET_RELEASE(asset, mode) \ xxl_release_asset((asset), (mode)) #define XXL_THROW_ERROR(code, data) \ xxl_throw_error((code), (data), __FILE__, __LINE__) #define XXL_RETHROW_ERROR() \ xxl_leave_handler(XXL_SETJMP_PROMOTE) #define XXL_LEAVE() \ xxl_leave_handler(XXL_SETJMP_LEAVE) #define XXL_RETRY() \ xxl_leave_handler(XXL_SETJMP_RETRY) #define XXL_EXCEPTION_CODE() xxl_current_error_code() #define XXL_EXCEPTION_DATA() xxl_current_error_data() #define XXL_EXCEPTION_FILE() xxl_current_error_file() #define XXL_EXCEPTION_LINE() xxl_current_error_line() #define XXL_TRY_BEGIN \ for (;;) \ { \ int __xxl_setjmp; \ jmp_buf __xxl_jmpbuf; \ volatile xxl_context_t *__xxl_context; \ \ __xxl_context = xxl_push_context(&__xxl_jmpbuf); \ __xxl_setjmp = setjmp(__xxl_jmpbuf); \ __xxl_context->state = (__xxl_context->state & XXL_STATE_MASK) | \ (__xxl_setjmp & XXL_SETJMP_MASK); \ __xxl_context->state &= ~(XXL_STATE_HANDLED | XXL_STATE_FINALLY); \ \ if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_TRY || \ (__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_RETRY) \ { \ { #define XXL_CATCH(code) \ } \ } \ if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_ERROR && \ !(__xxl_context->state & XXL_STATE_HANDLED) && \ (int)(code) == xxl_current_error_code()) \ { \ __xxl_context->state |= XXL_STATE_HANDLED; \ { #define XXL_EXCEPT \ } \ } \ if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_ERROR && \ !(__xxl_context->state & XXL_STATE_HANDLED)) \ { \ __xxl_context->state |= XXL_STATE_HANDLED; \ { #define XXL_FINALLY \ } \ } \ __xxl_context->state |= XXL_STATE_FINALLY; \ { \ { #define XXL_TRY_END \ } \ } \ __xxl_context->state &= ~XXL_STATE_FINALLY; \ if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_PENDING || \ (__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_PROMOTE || \ ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_ERROR && \ !(__xxl_context->state & XXL_STATE_HANDLED))) \ { \ xxl_leave_handler(XXL_SETJMP_ERROR); \ } \ xxl_pop_contexts(); \ break; \ } \ do {} while (0) /* These are private functions. Do not call them directly. Use the macros * defined above instead. */ extern XXL_API xxl_context_t * xxl_push_context(jmp_buf *); extern XXL_API void xxl_pop_context(void); extern XXL_API void xxl_pop_contexts(void); extern XXL_API void xxl_leave_handler(int); extern XXL_API void xxl_throw_error(int, void *, const char *, unsigned int); extern XXL_API int xxl_current_error_code(void); extern XXL_API void * xxl_current_error_data(void); extern XXL_API const char * xxl_current_error_file(void); extern XXL_API unsigned int xxl_current_error_line(void); extern XXL_API void xxl_push_asset(void *, xxl_assetfreefn_t, void *, xxl_assettype_t); extern XXL_API void xxl_update_asset(void *, void *); extern XXL_API void xxl_release_asset(void *, int); /* These are public "convenience" functions. They are essentially wrappers around * common functions that yield assets. Included among these functions are cleanup * callbacks. */ extern XXL_API void *xxl_malloc(size_t, xxl_assettype_t); extern XXL_API void *xxl_realloc(void *, size_t); extern XXL_API void xxl_free(void *); extern XXL_API void xxl_cleanup_ptr(void *, void *); extern XXL_API FILE *xxl_fopen(const char *, const char *, xxl_assettype_t); extern XXL_API int xxl_fclose(FILE *); extern XXL_API void xxl_cleanup_FILE(void *, void *); #ifndef WIN32 extern XXL_API int xxl_open(const char *, int, mode_t, xxl_assettype_t); #else extern XXL_API int xxl_open(const char *, int, int, xxl_assettype_t); #endif extern XXL_API int xxl_close(int); extern XXL_API void xxl_cleanup_fd(void *, void *); #ifndef WIN32 extern XXL_API int xxl_socket(int, int, int, xxl_assettype_t); extern XXL_API int xxl_shutdown(int, int); extern XXL_API int xxl_closesocket(int); #else extern XXL_API SOCKET xxl_socket(int, int, int, xxl_assettype_t); extern XXL_API int xxl_shutdown(SOCKET, int); extern XXL_API int xxl_closesocket(SOCKET); #endif extern XXL_API void xxl_cleanup_socket(void *, void *); #ifndef XXL_WITHOUT_THREADS #ifdef WIN32 extern XXL_API BOOL xxl_lock(HANDLE, xxl_assettype_t); extern XXL_API BOOL xxl_unlock(HANDLE); #else extern XXL_API int xxl_lock(pthread_mutex_t *, xxl_assettype_t); extern XXL_API int xxl_unlock(pthread_mutex_t *); #endif extern XXL_API void xxl_cleanup_lock(void *, void *); #endif #ifdef WIN32 extern XXL_API HGLOBAL xxl_GlobalAlloc(UINT, DWORD, xxl_assettype_t); extern XXL_API HGLOBAL xxl_GlobalReAlloc(HGLOBAL, DWORD, UINT); extern XXL_API HGLOBAL xxl_GlobalFree(HGLOBAL); extern XXL_API void xxl_cleanup_HGLOBAL(void *, void *); extern XXL_API void *xxl_HeapAlloc(HANDLE, DWORD, DWORD, xxl_assettype_t); extern XXL_API void *xxl_HeapReAlloc(HANDLE, DWORD, void *, DWORD); extern XXL_API void *xxl_HeapFree(HANDLE, void *); extern XXL_API void xxl_cleanup_HeapPtr(void *, void *); extern XXL_API HLOCAL xxl_LocalAlloc(UINT, UINT, xxl_assettype_t); extern XXL_API HLOCAL xxl_LocalReAlloc(HLOCAL, UINT, UINT); extern XXL_API HLOCAL xxl_LocalFree(HLOCAL); extern XXL_API void xxl_cleanup_HLOCAL(void *, void *); extern XXL_API void xxl_cleanup_HANDLE(void *, void *); #endif /* Macros for memory allocation. They're different for different platforms so that * the most appropriate memory allocation routines will be used. */ #ifndef WIN32 #define XXL_MALLOC(nbytes, type) xxl_malloc((nbytes), (type)) #define XXL_REALLOC(ptr, nbytes) xxl_realloc((void *)(ptr), (nbytes)) #define XXL_FREE(ptr) xxl_free((void *)(ptr)) #else #if defined(XXL_USE_GLOBALHEAP) #define XXL_MALLOC(nbytes, type) xxl_GlobalAlloc(GMEM_FIXED, (nbytes), (type)) #define XXL_REALLOC(ptr, nbytes) xxl_GlobalReAlloc((HGLOBAL)(ptr), (nbytes), 0) #define XXL_FREE(ptr) xxl_GlobalFree((HGLOBAL)(ptr)) #elif defined(XXL_USE_LOCALHEAP) #define XXL_MALLOC(nbytes, type) xxl_LocalAlloc(LMEM_FIXED, (nbytes), (type)) #define XXL_REALLOC(ptr, nbytes) xxl_LocalReAlloc((HLOCAL)(ptr), (nbytes), 0) #define XXL_FREE(ptr) xxl_LocalFree((HLOCAL)(ptr)) #else #define XXL_MALLOC(nbytes, type) xxl_HeapAlloc(NULL, 0, (nbytes), (type)) #define XXL_REALLOC(ptr, nbytes) xxl_HeapReAlloc(NULL, 0, (ptr), (nbytes)) #define XXL_FREE(ptr) xxl_HeapFree(NULL, (ptr)) #endif #endif /* Convenience macros that totally trash the namespace if they're used. Have * them included because people are lazy as hell, but allow them to be disabled * in the event of a namespace collision. #define XXL_ENFORCE_PREFIX to * disable the lazy man's API. */ #ifndef XXL_ENFORCE_PREFIX #define TRY XXL_TRY_BEGIN #define CATCH(code) XXL_CATCH(code) #define EXCEPT XXL_EXCEPT #define FINALLY XXL_FINALLY #define END_TRY XXL_TRY_END #define THROW(code, data) XXL_THROW_ERROR(code, data) #define RETHROW() XXL_RETHROW_ERROR() #define EXCEPTION_CODE() XXL_EXCEPTION_CODE() #define EXCEPTION_INFO() XXL_EXCEPTION_INFO() #define EXCEPTION_FILE() XXL_EXCEPTION_FILE() #define EXCEPTION_LINE() XXL_EXCEPTION_LINE() #endif #ifdef __cplusplus } #endif #endif /* XXL_H */