diff options
Diffstat (limited to 'include/library.h')
-rw-r--r-- | include/library.h | 364 |
1 files changed, 262 insertions, 102 deletions
diff --git a/include/library.h b/include/library.h index 8a055eb8..1edd3757 100644 --- a/include/library.h +++ b/include/library.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2018-2021 Gavin D. Howard and contributors. + * Copyright (c) 2018-2023 Gavin D. Howard and contributors. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,138 +36,256 @@ #ifndef LIBBC_PRIVATE_H #define LIBBC_PRIVATE_H +#ifndef _WIN32 + +#include <pthread.h> + +#endif // _WIN32 + #include <bcl.h> #include <num.h> +#include <vm.h> + +#if BC_ENABLE_MEMCHECK + +/** + * A typedef for Valgrind builds. This is to add a generation index for error + * checking. + */ +typedef struct BclNum +{ + /// The number. + BcNum n; + + /// The generation index. + size_t gen_idx; + +} BclNum; + +/** + * Clears the generation byte in a BclNumber and returns the value. + * @param n The BclNumber. + * @return The value of the index. + */ +#define BCL_NO_GEN(n) \ + ((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT))) + +/** + * Gets the generation index in a BclNumber. + * @param n The BclNumber. + * @return The generation index. + */ +#define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT)) /** - * A header for functions that need to lock and setjmp(). It also sets the - * variable that tells bcl that it is running. - * @param l The label to jump to on error. + * Turns a BclNumber into a BcNum. + * @param c The context. + * @param n The BclNumber. */ -#define BC_FUNC_HEADER_LOCK(l) \ - do { \ - BC_SIG_LOCK; \ - BC_SETJMP_LOCKED(l); \ - vm.err = BCL_ERROR_NONE; \ - vm.running = 1; \ - } while (0) +#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n))) /** - * A footer to unlock and stop the jumping if an error happened. It also sets - * the variable that tells bcl that it is running. - * @param e The error variable to set. + * Clears the generation index top byte in the BclNumber. + * @param n The BclNumber. */ -#define BC_FUNC_FOOTER_UNLOCK(e) \ - do { \ - BC_SIG_ASSERT_LOCKED; \ - e = vm.err; \ - vm.running = 0; \ - BC_UNSETJMP; \ - BC_LONGJMP_STOP; \ - vm.sig_lock = 0; \ - } while (0) +#define BCL_CLEAR_GEN(n) \ + do \ + { \ + (n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \ + } \ + while (0) + +#define BCL_CHECK_NUM_GEN(c, bn) \ + do \ + { \ + size_t gen_ = BCL_GET_GEN(bn); \ + BclNum* ptr_ = BCL_NUM(c, bn); \ + if (BCL_NUM_ARRAY(ptr_) == NULL) \ + { \ + bcl_nonexistentNum(); \ + } \ + if (gen_ != ptr_->gen_idx) \ + { \ + bcl_invalidGeneration(); \ + } \ + } \ + while (0) + +#define BCL_CHECK_NUM_VALID(c, bn) \ + do \ + { \ + size_t idx_ = BCL_NO_GEN(bn); \ + if ((c)->nums.len <= idx_) \ + { \ + bcl_numIdxOutOfRange(); \ + } \ + BCL_CHECK_NUM_GEN(c, bn); \ + } \ + while (0) /** - * A header that sets a jump and sets running. - * @param l The label to jump to on error. + * Returns the limb array of the number. + * @param bn The number. + * @return The limb array. */ -#define BC_FUNC_HEADER(l) \ - do { \ - BC_SETJMP(l); \ - vm.err = BCL_ERROR_NONE; \ - vm.running = 1; \ - } while (0) +#define BCL_NUM_ARRAY(bn) ((bn)->n.num) /** - * A header that assumes that signals are already locked. It sets a jump and - * running. - * @param l The label to jump to on error. + * Returns the limb array of the number for a non-pointer. + * @param bn The number. + * @return The limb array. */ -#define BC_FUNC_HEADER_INIT(l) \ - do { \ - BC_SETJMP_LOCKED(l); \ - vm.err = BCL_ERROR_NONE; \ - vm.running = 1; \ - } while (0) +#define BCL_NUM_ARRAY_NP(bn) ((bn).n.num) /** - * A footer for functions that do not return an error code. It clears running - * and unlocks the signals. It also stops the jumping. + * Returns the BcNum pointer. + * @param bn The number. + * @return The BcNum pointer. */ -#define BC_FUNC_FOOTER_NO_ERR \ - do { \ - vm.running = 0; \ - BC_UNSETJMP; \ - BC_LONGJMP_STOP; \ - vm.sig_lock = 0; \ - } while (0) +#define BCL_NUM_NUM(bn) (&(bn)->n) /** - * A footer for functions that *do* return an error code. It clears running and - * unlocks the signals. It also stops the jumping. - * @param e The error variable to set. + * Returns the BcNum pointer for a non-pointer. + * @param bn The number. + * @return The BcNum pointer. */ -#define BC_FUNC_FOOTER(e) \ - do { \ - e = vm.err; \ - BC_FUNC_FOOTER_NO_ERR; \ - } while (0) +#define BCL_NUM_NUM_NP(bn) (&(bn).n) + +// These functions only abort. They exist to give developers some idea of what +// went wrong when bugs are found, if they look at the Valgrind stack trace. + +BC_NORETURN void +bcl_invalidGeneration(void); + +BC_NORETURN void +bcl_nonexistentNum(void); + +BC_NORETURN void +bcl_numIdxOutOfRange(void); + +#else // BC_ENABLE_MEMCHECK + +/** + * A typedef for non-Valgrind builds. + */ +typedef BcNum BclNum; + +#define BCL_NO_GEN(n) ((n).i) +#define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i)) +#define BCL_CLEAR_GEN(n) ((void) (n)) + +#define BCL_CHECK_NUM_GEN(c, bn) +#define BCL_CHECK_NUM_VALID(c, n) + +#define BCL_NUM_ARRAY(bn) ((bn)->num) +#define BCL_NUM_ARRAY_NP(bn) ((bn).num) + +#define BCL_NUM_NUM(bn) (bn) +#define BCL_NUM_NUM_NP(bn) (&(bn)) + +#endif // BC_ENABLE_MEMCHECK + +/** + * A header that sets a jump. + * @param vm The thread data. + * @param l The label to jump to on error. + */ +#define BC_FUNC_HEADER(vm, l) \ + do \ + { \ + BC_SETJMP(vm, l); \ + vm->err = BCL_ERROR_NONE; \ + } \ + while (0) + +/** + * A footer for functions that do not return an error code. + */ +#define BC_FUNC_FOOTER_NO_ERR(vm) \ + do \ + { \ + BC_UNSETJMP(vm); \ + } \ + while (0) + +/** + * A footer for functions that *do* return an error code. + * @param vm The thread data. + * @param e The error variable to set. + */ +#define BC_FUNC_FOOTER(vm, e) \ + do \ + { \ + e = vm->err; \ + BC_FUNC_FOOTER_NO_ERR(vm); \ + } \ + while (0) /** * A footer that sets up n based the value of e and sets up the return value in * idx. * @param c The context. * @param e The error. - * @param n The number. + * @param bn The number. * @param idx The idx to set as the return value. */ -#define BC_MAYBE_SETUP(c, e, n, idx) \ - do { \ - if (BC_ERR((e) != BCL_ERROR_NONE)) { \ - if ((n).num != NULL) bc_num_free(&(n)); \ - idx.i = 0 - (size_t) (e); \ - } \ - else idx = bcl_num_insert(c, &(n)); \ - } while (0) +#define BC_MAYBE_SETUP(c, e, bn, idx) \ + do \ + { \ + if (BC_ERR((e) != BCL_ERROR_NONE)) \ + { \ + if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \ + idx.i = 0 - (size_t) (e); \ + } \ + else idx = bcl_num_insert(c, &(bn)); \ + } \ + while (0) /** * A header to check the context and return an error encoded in a number if it * is bad. * @param c The context. */ -#define BC_CHECK_CTXT(c) \ - do { \ - c = bcl_context(); \ - if (BC_ERR(c == NULL)) { \ - BclNumber n_num; \ - n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \ - return n_num; \ - } \ - } while (0) - +#define BC_CHECK_CTXT(vm, c) \ + do \ + { \ + c = bcl_contextHelper(vm); \ + if (BC_ERR(c == NULL)) \ + { \ + BclNumber n_num_; \ + n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \ + return n_num_; \ + } \ + } \ + while (0) /** * A header to check the context and return an error directly if it is bad. * @param c The context. */ -#define BC_CHECK_CTXT_ERR(c) \ - do { \ - c = bcl_context(); \ - if (BC_ERR(c == NULL)) { \ +#define BC_CHECK_CTXT_ERR(vm, c) \ + do \ + { \ + c = bcl_contextHelper(vm); \ + if (BC_ERR(c == NULL)) \ + { \ return BCL_ERROR_INVALID_CONTEXT; \ } \ - } while (0) + } \ + while (0) /** * A header to check the context and abort if it is bad. * @param c The context. */ -#define BC_CHECK_CTXT_ASSERT(c) \ - do { \ - c = bcl_context(); \ - assert(c != NULL); \ - } while (0) +#define BC_CHECK_CTXT_ASSERT(vm, c) \ + do \ + { \ + c = bcl_contextHelper(vm); \ + assert(c != NULL); \ + } \ + while (0) /** * A header to check the number in the context and return an error encoded as a @@ -176,16 +294,24 @@ * @param n The BclNumber. */ #define BC_CHECK_NUM(c, n) \ - do { \ - if (BC_ERR((n).i >= (c)->nums.len)) { \ + do \ + { \ + size_t no_gen_ = BCL_NO_GEN(n); \ + if (BC_ERR(no_gen_ >= (c)->nums.len)) \ + { \ if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \ - else { \ - BclNumber n_num; \ - n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \ - return n_num; \ + else \ + { \ + BclNumber n_num_; \ + n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \ + return n_num_; \ } \ } \ - } while (0) + BCL_CHECK_NUM_GEN(c, n); \ + } \ + while (0) + +//clang-format off /** * A header to check the number in the context and return an error directly if @@ -194,30 +320,47 @@ * @param n The BclNumber. */ #define BC_CHECK_NUM_ERR(c, n) \ - do { \ - if (BC_ERR((n).i >= (c)->nums.len)) { \ + do \ + { \ + size_t no_gen_ = BCL_NO_GEN(n); \ + if (BC_ERR(no_gen_ >= (c)->nums.len)) \ + { \ if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \ + { \ return (BclError) (0 - (n).i); \ + } \ else return BCL_ERROR_INVALID_NUM; \ } \ - } while (0) + BCL_CHECK_NUM_GEN(c, n); \ + } \ + while (0) + +//clang-format on /** - * Turns a BclNumber into a BcNum. + * Grows the context's nums array if necessary. * @param c The context. - * @param n The BclNumber. */ -#define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i)) +#define BCL_GROW_NUMS(c) \ + do \ + { \ + if ((c)->free_nums.len == 0) \ + { \ + bc_vec_grow(&((c)->nums), 1); \ + } \ + } \ + while (0) /** * Frees a BcNum for bcl. This is a destructor. * @param num The BcNum to free, as a void pointer. */ -void bcl_num_destruct(void *num); +void +bcl_num_destruct(void* num); /// The actual context struct. -typedef struct BclCtxt { - +typedef struct BclCtxt +{ /// The context's scale. size_t scale; @@ -236,4 +379,21 @@ typedef struct BclCtxt { } BclCtxt; +/** + * Returns the @a BcVm for the current thread. + * @return The vm for the current thread. + */ +BcVm* +bcl_getspecific(void); + +#ifndef _WIN32 + +typedef pthread_key_t BclTls; + +#else // _WIN32 + +typedef DWORD BclTls; + +#endif // _WIN32 + #endif // LIBBC_PRIVATE_H |