140 lines
7.2 KiB
C
140 lines
7.2 KiB
C
#if !defined(DN_OS_TLS_H)
|
|
#define DN_OS_TLS_H
|
|
|
|
// NOTE: DN_OSErrSink /////////////////////////////////////////////////////////////////////////////
|
|
enum DN_OSErrSinkMode
|
|
{
|
|
DN_OSErrSinkMode_Nil, // Default behaviour to accumulate errors into the sink
|
|
DN_OSErrSinkMode_DebugBreakOnEndAndLog, // Debug break (int3) when error is encountered and the sink is ended by the 'end and log' functions.
|
|
DN_OSErrSinkMode_ExitOnError, // When an error is encountered, exit the program with the error code of the error that was caught.
|
|
};
|
|
|
|
struct DN_OSErrSinkMsg
|
|
{
|
|
DN_I32 error_code;
|
|
DN_Str8 msg;
|
|
DN_CallSite call_site;
|
|
DN_OSErrSinkMsg *next;
|
|
DN_OSErrSinkMsg *prev;
|
|
};
|
|
|
|
struct DN_OSErrSinkNode
|
|
{
|
|
DN_CallSite call_site; // Call site that the node was created
|
|
DN_OSErrSinkMode mode; // Controls how the sink behaves when an error is registered onto the sink.
|
|
DN_OSErrSinkMsg *msg_sentinel; // List of error messages accumulated for the current scope
|
|
DN_U64 arena_pos; // Position to reset the arena when the scope is ended
|
|
};
|
|
|
|
struct DN_OSErrSink
|
|
{
|
|
DN_Arena * arena; // Dedicated allocator from the thread's local storage
|
|
DN_OSErrSinkNode stack[128]; // Each entry contains errors accumulated between a [begin, end] region of the active sink.
|
|
DN_USize stack_size;
|
|
};
|
|
|
|
enum DN_OSTLSArena
|
|
{
|
|
DN_OSTLSArena_Main, // NOTE: Arena for permanent allocations
|
|
DN_OSTLSArena_ErrorSink, // NOTE: Arena for logging error information for this thread
|
|
|
|
// NOTE: Per-thread scratch arenas (2 to prevent aliasing)
|
|
DN_OSTLSArena_TMem0,
|
|
DN_OSTLSArena_TMem1,
|
|
|
|
DN_OSTLSArena_Count,
|
|
};
|
|
|
|
struct DN_OSTLS
|
|
{
|
|
DN_B32 init; // Flag to track if TLS has been initialised
|
|
DN_U64 thread_id;
|
|
DN_CallSite call_site; // Stores call-site information when requested by thread
|
|
DN_OSErrSink err_sink; // Error handling state
|
|
DN_Arena arenas[DN_OSTLSArena_Count]; // Default arenas that the thread has access to implicitly
|
|
DN_Arena * arena_stack[8]; // Active stack of arenas push/popped arenas on into the TLS
|
|
DN_USize arena_stack_index;
|
|
|
|
DN_Arena * frame_arena;
|
|
char name[64];
|
|
DN_U8 name_size;
|
|
};
|
|
|
|
// Push the temporary memory arena when retrieved, popped when the arena goes
|
|
// out of scope. Pushed arenas are used automatically as the allocator in TLS
|
|
// suffixed function.
|
|
enum DN_OSTLSPushTMem
|
|
{
|
|
DN_OSTLSPushTMem_No,
|
|
DN_OSTLSPushTMem_Yes,
|
|
};
|
|
|
|
struct DN_OSTLSTMem
|
|
{
|
|
DN_OSTLSTMem(DN_OSTLS *context, uint8_t context_index, DN_OSTLSPushTMem push_scratch);
|
|
~DN_OSTLSTMem();
|
|
DN_Arena *arena;
|
|
DN_B32 destructed;
|
|
DN_OSTLSPushTMem push_arena;
|
|
DN_ArenaTempMem temp_mem;
|
|
};
|
|
|
|
struct DN_OSTLSInitArgs
|
|
{
|
|
DN_U64 reserve;
|
|
DN_U64 commit;
|
|
DN_U64 err_sink_reserve;
|
|
DN_U64 err_sink_commit;
|
|
};
|
|
|
|
// NOTE: DN_OSTLS ////////////////////////////////////////////////////////////////////////////////////
|
|
DN_API void DN_OS_TLSInit (DN_OSTLS *tls, DN_OSTLSInitArgs args);
|
|
DN_API void DN_OS_TLSDeinit (DN_OSTLS *tls);
|
|
DN_API DN_OSTLS * DN_OS_TLSGet ();
|
|
DN_API void DN_OS_TLSSetCurrentThreadTLS (DN_OSTLS *tls);
|
|
DN_API DN_Arena * DN_OS_TLSArena ();
|
|
DN_API DN_OSTLSTMem DN_OS_TLSGetTMem (void const *conflict_arena, DN_OSTLSPushTMem push_tmp_mem);
|
|
DN_API void DN_OS_TLSPushArena (DN_Arena *arena);
|
|
DN_API void DN_OS_TLSPopArena ();
|
|
DN_API DN_Arena * DN_OS_TLSTopArena ();
|
|
DN_API void DN_OS_TLSBeginFrame (DN_Arena *frame_arena);
|
|
DN_API DN_Arena * DN_OS_TLSFrameArena ();
|
|
#define DN_OS_TLSSaveCallSite do { DN_OS_TLSGet()->call_site = DN_CALL_SITE; } while (0)
|
|
#define DN_OS_TLSTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_No)
|
|
#define DN_OS_TLSPushTMem(...) DN_OS_TLSGetTMem(__VA_ARGS__, DN_OSTLSPushTMem_Yes)
|
|
|
|
// NOTE: DN_OS_ErrSink ////////////////////////////////////////////////////////////////////////////
|
|
DN_API DN_OSErrSink * DN_OS_ErrSinkBegin_ (DN_OSErrSinkMode mode, DN_CallSite call_site);
|
|
#define DN_OS_ErrSinkBegin(mode) DN_OS_ErrSinkBegin_(mode, DN_CALL_SITE)
|
|
#define DN_OS_ErrSinkBeginDefault() DN_OS_ErrSinkBegin(DN_OSErrSinkMode_Nil)
|
|
DN_API bool DN_OS_ErrSinkHasError (DN_OSErrSink *err);
|
|
DN_API DN_OSErrSinkMsg *DN_OS_ErrSinkEnd (DN_Arena *arena, DN_OSErrSink *err);
|
|
DN_API DN_Str8 DN_OS_ErrSinkEndStr8 (DN_Arena *arena, DN_OSErrSink *err);
|
|
DN_API void DN_OS_ErrSinkEndAndIgnore (DN_OSErrSink *err);
|
|
DN_API bool DN_OS_ErrSinkEndAndLogError_ (DN_OSErrSink *err, DN_CallSite call_site, DN_Str8 msg);
|
|
DN_API bool DN_OS_ErrSinkEndAndLogErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args);
|
|
DN_API bool DN_OS_ErrSinkEndAndLogErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...);
|
|
DN_API void DN_OS_ErrSinkEndAndExitIfErrorF_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, ...);
|
|
DN_API void DN_OS_ErrSinkEndAndExitIfErrorFV_ (DN_OSErrSink *err, DN_CallSite call_site, DN_U32 exit_val, DN_FMT_ATTRIB char const *fmt, va_list args);
|
|
DN_API void DN_OS_ErrSinkAppendFV_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, va_list args);
|
|
DN_API void DN_OS_ErrSinkAppendF_ (DN_OSErrSink *err, DN_U32 error_code, DN_FMT_ATTRIB char const *fmt, ...);
|
|
#define DN_OS_ErrSinkEndAndLogError(err, err_msg) DN_OS_ErrSinkEndAndLogError_(err, DN_CALL_SITE, err_msg)
|
|
#define DN_OS_ErrSinkEndAndLogErrorFV(err, fmt, args) DN_OS_ErrSinkEndAndLogErrorFV_(err, DN_CALL_SITE, fmt, args)
|
|
#define DN_OS_ErrSinkEndAndLogErrorF(err, fmt, ...) DN_OS_ErrSinkEndAndLogErrorF_(err, DN_CALL_SITE, fmt, ##__VA_ARGS__)
|
|
#define DN_OS_ErrSinkEndAndExitIfErrorFV(err, exit_val, fmt, args) DN_OS_ErrSinkEndAndExitIfErrorFV_(err, DN_CALL_SITE, exit_val, fmt, args)
|
|
#define DN_OS_ErrSinkEndAndExitIfErrorF(err, exit_val, fmt, ...) DN_OS_ErrSinkEndAndExitIfErrorF_(err, DN_CALL_SITE, exit_val, fmt, ##__VA_ARGS__)
|
|
|
|
#define DN_OS_ErrSinkAppendFV(error, error_code, fmt, args) \
|
|
do { \
|
|
DN_OS_TLSSaveCallSite; \
|
|
DN_OS_ErrSinkAppendFV_(error, error_code, fmt, args); \
|
|
} while (0)
|
|
|
|
#define DN_OS_ErrSinkAppendF(error, error_code, fmt, ...) \
|
|
do { \
|
|
DN_OS_TLSSaveCallSite; \
|
|
DN_OS_ErrSinkAppendF_(error, error_code, fmt, ##__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#endif // defined(DN_OS_TLS_H)
|