1#ifndef XXL_H
2#define XXL_H
3
4#ifndef WIN32
5/* BEGIN:   autoconf substitutions */
6#undef HAVE_SETJMP_H
7#undef HAVE_PTHREAD_H
8#undef HAVE_SYS_TYPES_H
9#undef STDC_HEADERS
10#undef XXL_WITHOUT_THREADS
11#undef const
12/* END:     autoconf substitutions */
13#define XXL_API
14#else
15#ifdef XXL_EXPORTS
16#define XXL_API __declspec(dllexport)
17#else
18#define XXL_API __declspec(dllimport)
19#endif
20#endif
21
22#if !defined(XXL_WITHOUT_THREADS) && !defined(WIN32) && !defined(HAVE_PTHREAD_H)
23#define XXL_WITHOUT_THREADS
24#endif
25
26#ifdef WIN32
27#include <windows.h>
28#include <winsock.h>
29#endif
30#include <stdio.h>
31#if defined(HAVE_SYS_TYPES_H)
32#include <sys/types.h>
33#endif
34#if defined(HAVE_SETJMP_H) || defined(WIN32)
35#include <setjmp.h>
36#endif
37#if !defined(WIN32) && defined(STDC_HEADERS)
38#include <errno.h>
39#endif
40#if !defined(XXL_WITHOUT_THREADS) && defined(HAVE_PTHREAD_H)
41#include <pthread.h>
42#endif
43
44#define XXL_ERROR_THREAD_CANCELLED      0xFFFFFFFF
45#define XXL_ERROR_RETRY_EXCEPTION       0xFFFFFFFE
46
47#ifdef __cplusplus
48extern "C" {
49#endif
50
51typedef enum _xxl_assettype_t
52{
53    XXL_ASSET_PERMANENT,
54    XXL_ASSET_PROMOTE,
55    XXL_ASSET_TEMPORARY,
56    XXL_ASSET_AUTO,
57    XXL_ASSET_DEMOTE
58} xxl_assettype_t;
59
60typedef void (*xxl_assetfreefn_t)(void *, void *);
61
62typedef struct _xxl_asset_t     xxl_asset_t;
63typedef struct _xxl_context_t   xxl_context_t;
64typedef struct _xxl_exception_t xxl_exception_t;
65typedef struct _xxl_tsd_t       xxl_tsd_t;
66
67struct _xxl_asset_t
68{
69    void                *ptr;
70    xxl_assetfreefn_t   freefn;
71    void                *arg;
72    xxl_assettype_t     type;
73    xxl_asset_t         *next;
74};
75
76struct _xxl_exception_t
77{
78    int                 code;
79    void                *data;
80    const char          *file;
81    unsigned int        line;
82};
83
84struct _xxl_context_t
85{
86    jmp_buf             *context;
87    unsigned int        state;
88    xxl_exception_t     exception;
89    xxl_exception_t     pending;
90#if !defined(WIN32) && !defined(XXL_WITHOUT_THREADS)
91    int                 cancel_type;
92#endif
93    xxl_asset_t         *assets;
94    xxl_context_t       *next;
95};
96
97struct _xxl_tsd_t
98{
99    xxl_context_t       *contexts;
100#if !defined(WIN32) || defined(XXL_WITHOUT_THREADS)
101    xxl_context_t       *free_contexts;
102    xxl_asset_t         *free_assets;
103#endif
104};
105
106#define XXL_ASSET_ALL       0
107#define XXL_ASSET_CURRENT   1
108#define XXL_ASSET_FIRST     2
109
110/* These are only used internally */
111#define XXL_SETJMP_TRY      0x00
112#define XXL_SETJMP_ERROR    0x01
113#define XXL_SETJMP_RETRY    0x02
114#define XXL_SETJMP_PROMOTE  0x03
115#define XXL_SETJMP_LEAVE    0x04
116#define XXL_SETJMP_PENDING  0x05
117#define XXL_SETJMP_MASK     0xFF
118
119#define XXL_STATE_HANDLED   0x00000100
120#define XXL_STATE_FINALLY   0x00000200
121#define XXL_STATE_PENDING   0x00000400
122#define XXL_STATE_THROWN    0x00000800
123#define XXL_STATE_MASK      0x0000FF00
124
125/* Public Macros */
126#define XXL_ASSET_BLOCK_BEGIN                                               \
127    do                                                                      \
128    {                                                                       \
129        xxl_push_context(NULL);                                             \
130        {
131
132#define XXL_ASSET_BLOCK_END                                                 \
133        }                                                                   \
134        xxl_pop_context();                                                  \
135    } while (0)
136
137#define XXL_ASSET_SAVE(asset, callback, arg, type)                          \
138    xxl_push_asset((asset), (xxl_assetfreefn_t)(callback), (arg), (type))
139#define XXL_ASSET_UPDATE(old_asset, new_asset)                              \
140    xxl_update_asset((old_asset), (new_asset))
141#define XXL_ASSET_RELEASE(asset, mode)                                      \
142    xxl_release_asset((asset), (mode))
143
144#define XXL_THROW_ERROR(code, data)                                         \
145    xxl_throw_error((code), (data), __FILE__, __LINE__)
146#define XXL_RETHROW_ERROR()                                                 \
147    xxl_leave_handler(XXL_SETJMP_PROMOTE)
148#define XXL_LEAVE()                                                         \
149    xxl_leave_handler(XXL_SETJMP_LEAVE)
150#define XXL_RETRY()                                                         \
151    xxl_leave_handler(XXL_SETJMP_RETRY)
152
153#define XXL_EXCEPTION_CODE()    xxl_current_error_code()
154#define XXL_EXCEPTION_DATA()    xxl_current_error_data()
155#define XXL_EXCEPTION_FILE()    xxl_current_error_file()
156#define XXL_EXCEPTION_LINE()    xxl_current_error_line()
157
158#define XXL_TRY_BEGIN                                                           \
159    for (;;)                                                                    \
160    {                                                                           \
161        int                     __xxl_setjmp;                                   \
162        jmp_buf                 __xxl_jmpbuf;                                   \
163        volatile xxl_context_t  *__xxl_context;                                 \
164                                                                                \
165        __xxl_context = xxl_push_context(&__xxl_jmpbuf);                        \
166        __xxl_setjmp  = setjmp(__xxl_jmpbuf);                                   \
167        __xxl_context->state  = (__xxl_context->state & XXL_STATE_MASK) |       \
168                                (__xxl_setjmp & XXL_SETJMP_MASK);               \
169        __xxl_context->state &= ~(XXL_STATE_HANDLED | XXL_STATE_FINALLY);       \
170                                                                                \
171        if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_TRY ||       \
172            (__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_RETRY)       \
173        {                                                                       \
174            {
175
176#define XXL_CATCH(code)                                                         \
177            }                                                                   \
178        }                                                                       \
179        if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_ERROR &&     \
180            !(__xxl_context->state & XXL_STATE_HANDLED) &&                      \
181            (int)(code) == xxl_current_error_code())                            \
182        {                                                                       \
183            __xxl_context->state |= XXL_STATE_HANDLED;                          \
184            {
185
186#define XXL_EXCEPT                                                              \
187            }                                                                   \
188        }                                                                       \
189        if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_ERROR &&     \
190            !(__xxl_context->state & XXL_STATE_HANDLED))                        \
191        {                                                                       \
192            __xxl_context->state |= XXL_STATE_HANDLED;                          \
193            {
194
195#define XXL_FINALLY                                                             \
196            }                                                                   \
197        }                                                                       \
198        __xxl_context->state |= XXL_STATE_FINALLY;                              \
199        {                                                                       \
200            {
201
202#define XXL_TRY_END                                                             \
203            }                                                                   \
204        }                                                                       \
205        __xxl_context->state &= ~XXL_STATE_FINALLY;                             \
206        if ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_PENDING ||   \
207            (__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_PROMOTE ||   \
208            ((__xxl_context->state & XXL_SETJMP_MASK) == XXL_SETJMP_ERROR &&    \
209             !(__xxl_context->state & XXL_STATE_HANDLED)))                      \
210        {                                                                       \
211            xxl_leave_handler(XXL_SETJMP_ERROR);                                \
212        }                                                                       \
213        xxl_pop_contexts();                                                     \
214        break;                                                                  \
215    }                                                                           \
216    do {} while (0)
217
218/* These are private functions.  Do not call them directly.  Use the macros
219 * defined above instead.
220 */
221extern XXL_API xxl_context_t *  xxl_push_context(jmp_buf *);
222extern XXL_API void             xxl_pop_context(void);
223extern XXL_API void             xxl_pop_contexts(void);
224extern XXL_API void             xxl_leave_handler(int);
225extern XXL_API void             xxl_throw_error(int, void *, const char *, unsigned int);
226extern XXL_API int              xxl_current_error_code(void);
227extern XXL_API void *           xxl_current_error_data(void);
228extern XXL_API const char *     xxl_current_error_file(void);
229extern XXL_API unsigned int     xxl_current_error_line(void);
230extern XXL_API void             xxl_push_asset(void *, xxl_assetfreefn_t, void *, xxl_assettype_t);
231extern XXL_API void             xxl_update_asset(void *, void *);
232extern XXL_API void             xxl_release_asset(void *, int);
233
234/* These are public "convenience" functions.  They are essentially wrappers around
235 * common functions that yield assets.  Included among these functions are cleanup
236 * callbacks.
237 */
238extern XXL_API void *xxl_malloc(size_t, xxl_assettype_t);
239extern XXL_API void *xxl_realloc(void *, size_t);
240extern XXL_API void xxl_free(void *);
241extern XXL_API void xxl_cleanup_ptr(void *, void *);
242
243extern XXL_API FILE *xxl_fopen(const char *, const char *, xxl_assettype_t);
244extern XXL_API int  xxl_fclose(FILE *);
245extern XXL_API void xxl_cleanup_FILE(void *, void *);
246
247#ifndef WIN32
248extern XXL_API int  xxl_open(const char *, int, mode_t, xxl_assettype_t);
249#else
250extern XXL_API int  xxl_open(const char *, int, int, xxl_assettype_t);
251#endif
252extern XXL_API int  xxl_close(int);
253extern XXL_API void xxl_cleanup_fd(void *, void *);
254
255#ifndef WIN32
256extern XXL_API int  xxl_socket(int, int, int, xxl_assettype_t);
257extern XXL_API int  xxl_shutdown(int, int);
258extern XXL_API int  xxl_closesocket(int);
259#else
260extern XXL_API SOCKET xxl_socket(int, int, int, xxl_assettype_t);
261extern XXL_API int    xxl_shutdown(SOCKET, int);
262extern XXL_API int    xxl_closesocket(SOCKET);
263#endif
264extern XXL_API void   xxl_cleanup_socket(void *, void *);
265
266#ifndef XXL_WITHOUT_THREADS
267#ifdef WIN32
268extern XXL_API BOOL xxl_lock(HANDLE, xxl_assettype_t);
269extern XXL_API BOOL xxl_unlock(HANDLE);
270#else
271extern XXL_API int xxl_lock(pthread_mutex_t *, xxl_assettype_t);
272extern XXL_API int xxl_unlock(pthread_mutex_t *);
273#endif
274extern XXL_API void xxl_cleanup_lock(void *, void *);
275#endif
276
277#ifdef WIN32
278extern XXL_API HGLOBAL xxl_GlobalAlloc(UINT, DWORD, xxl_assettype_t);
279extern XXL_API HGLOBAL xxl_GlobalReAlloc(HGLOBAL, DWORD, UINT);
280extern XXL_API HGLOBAL xxl_GlobalFree(HGLOBAL);
281extern XXL_API void    xxl_cleanup_HGLOBAL(void *, void *);
282
283extern XXL_API void    *xxl_HeapAlloc(HANDLE, DWORD, DWORD, xxl_assettype_t);
284extern XXL_API void    *xxl_HeapReAlloc(HANDLE, DWORD, void *, DWORD);
285extern XXL_API void    *xxl_HeapFree(HANDLE, void *);
286extern XXL_API void    xxl_cleanup_HeapPtr(void *, void *);
287
288extern XXL_API HLOCAL  xxl_LocalAlloc(UINT, UINT, xxl_assettype_t);
289extern XXL_API HLOCAL  xxl_LocalReAlloc(HLOCAL, UINT, UINT);
290extern XXL_API HLOCAL  xxl_LocalFree(HLOCAL);
291extern XXL_API void    xxl_cleanup_HLOCAL(void *, void *);
292
293extern XXL_API void    xxl_cleanup_HANDLE(void *, void *);
294#endif
295
296/* Macros for memory allocation.  They're different for different platforms so that
297 * the most appropriate memory allocation routines will be used.
298 */
299#ifndef WIN32
300#define XXL_MALLOC(nbytes, type)    xxl_malloc((nbytes), (type))
301#define XXL_REALLOC(ptr, nbytes)    xxl_realloc((void *)(ptr), (nbytes))
302#define XXL_FREE(ptr)               xxl_free((void *)(ptr))
303#else
304#if defined(XXL_USE_GLOBALHEAP)
305#define XXL_MALLOC(nbytes, type)    xxl_GlobalAlloc(GMEM_FIXED, (nbytes), (type))
306#define XXL_REALLOC(ptr, nbytes)    xxl_GlobalReAlloc((HGLOBAL)(ptr), (nbytes), 0)
307#define XXL_FREE(ptr)               xxl_GlobalFree((HGLOBAL)(ptr))
308#elif defined(XXL_USE_LOCALHEAP)
309#define XXL_MALLOC(nbytes, type)    xxl_LocalAlloc(LMEM_FIXED, (nbytes), (type))
310#define XXL_REALLOC(ptr, nbytes)    xxl_LocalReAlloc((HLOCAL)(ptr), (nbytes), 0)
311#define XXL_FREE(ptr)               xxl_LocalFree((HLOCAL)(ptr))
312#else
313#define XXL_MALLOC(nbytes, type)    xxl_HeapAlloc(NULL, 0, (nbytes), (type))
314#define XXL_REALLOC(ptr, nbytes)    xxl_HeapReAlloc(NULL, 0, (ptr), (nbytes))
315#define XXL_FREE(ptr)               xxl_HeapFree(NULL, (ptr))
316#endif
317#endif
318
319
320/* Convenience macros that totally trash the namespace if they're used.  Have
321 * them included because people are lazy as hell, but allow them to be disabled
322 * in the event of a namespace collision.  #define XXL_ENFORCE_PREFIX to
323 * disable the lazy man's API.
324 */
325#ifndef XXL_ENFORCE_PREFIX
326#define TRY                 XXL_TRY_BEGIN
327#define CATCH(code)         XXL_CATCH(code)
328#define EXCEPT              XXL_EXCEPT
329#define FINALLY             XXL_FINALLY
330#define END_TRY             XXL_TRY_END
331#define THROW(code, data)   XXL_THROW_ERROR(code, data)
332#define RETHROW()           XXL_RETHROW_ERROR()
333#define EXCEPTION_CODE()    XXL_EXCEPTION_CODE()
334#define EXCEPTION_INFO()    XXL_EXCEPTION_INFO()
335#define EXCEPTION_FILE()    XXL_EXCEPTION_FILE()
336#define EXCEPTION_LINE()    XXL_EXCEPTION_LINE()
337#endif
338
339#ifdef __cplusplus
340}
341#endif
342
343#endif  /* XXL_H */
344