diff options
-rw-r--r-- | LICENSE | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | close_range.c | 19 | ||||
-rw-r--r-- | get_stack_limit.c | 26 | ||||
-rw-r--r-- | get_stack_space.c | 5 | ||||
-rw-r--r-- | libsimple.h | 1 | ||||
-rw-r--r-- | libsimple/definitions.h | 110 | ||||
-rw-r--r-- | libsimple/random.h | 103 | ||||
-rw-r--r-- | libsimple/stack.h | 50 | ||||
-rw-r--r-- | libsimple/time.h | 39 | ||||
-rw-r--r-- | man3/libsimple_close_range.3 | 5 | ||||
-rw-r--r-- | random_bits.c | 6 | ||||
-rw-r--r-- | random_bytes.c | 41 |
13 files changed, 371 insertions, 39 deletions
@@ -1,6 +1,6 @@ ISC License -© 2017, 2018, 2021, 2022, 2023, 2024 Mattias Andrée <maandree@kth.se> +© 2017, 2018, 2021, 2022, 2023, 2024, 2025 Mattias Andrée <m@maandree.se> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -11,7 +11,7 @@ include mk/$(OS).mk LIB_MAJOR = 1 -LIB_MINOR = 7 +LIB_MINOR = 8 LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) LIB_NAME = simple @@ -941,6 +941,7 @@ OBJ =\ qsort_ushortp.o\ qsort_ushortp_nul.o\ random_bits.o\ + random_bytes.o\ random_float.o\ random_signed.o\ random_unsigned.o\ diff --git a/close_range.c b/close_range.c index 540eba0..096aa56 100644 --- a/close_range.c +++ b/close_range.c @@ -73,7 +73,8 @@ libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next) { int saved_errno; - *next = first; + if (next) + *next = first; if (first > last) { errno = EINVAL; @@ -103,10 +104,12 @@ libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next) qsort(fds, n, sizeof(*fds), uintpcmp); for (i = 0; i < n; i++) { if (close((int)fds[i]) && errno != EBADF) { - if (i + 1 < n) - *next = fds[i + 1]; - else - *next = fds[i] + (fds[i] < LIBSIMPLE_CLOSE_RANGE_MAX); + if (next) { + if (i + 1 < n) + *next = fds[i + 1]; + else + *next = fds[i] + (fds[i] < LIBSIMPLE_CLOSE_RANGE_MAX); + } free(fds); return -1; } @@ -118,13 +121,15 @@ libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next) fallback: do { if (close((int)first) && errno != EBADF) { - *next = first + (first < LIBSIMPLE_CLOSE_RANGE_MAX); + if (next) + *next = first + (first < LIBSIMPLE_CLOSE_RANGE_MAX); return -1; } } while (first++ < last); out: - *next = last + (last < LIBSIMPLE_CLOSE_RANGE_MAX); + if (next) + *next = last + (last < LIBSIMPLE_CLOSE_RANGE_MAX); errno = saved_errno; return 0; } diff --git a/get_stack_limit.c b/get_stack_limit.c index 363147a..cb19f2d 100644 --- a/get_stack_limit.c +++ b/get_stack_limit.c @@ -12,7 +12,7 @@ libsimple_get_stack_limit(size_t *restrict soft, size_t *restrict hard) size_t off = 0; size_t lineoff, linelen; - fd = open("/proc/self/limits", O_RDONLY); + fd = open("/proc/thread-self/limits", O_RDONLY); if (fd < 0) return -1; @@ -41,22 +41,30 @@ libsimple_get_stack_limit(size_t *restrict soft, size_t *restrict hard) if (!strcmp(line, "Max stack size ")) goto line_found; } - } - + line_found: close(fd); line = &line[sizeof("Max stack size ") - 1U]; - while (*line == ' ') + while (*line == ' ' || *line == '\t') line++; - if (soft) - *soft = (size_t)strtoull(line, NULL, 10); + if (soft) { + *soft = SIZE_MAX; + if (isdigit(*line)) + *soft = (size_t)strtoull(line, NULL, 10); + } - while (*line == ' ') + while (*line != ' ' && *line != '\t' && *line && *line != '\n') line++; - if (hard) - *hard = (size_t)strtoull(line, NULL, 10); + + while (*line == ' ' || *line == '\t') + line++; + if (hard) { + *hard = SIZE_MAX; + if (isdigit(*line)) + *hard = (size_t)strtoull(line, NULL, 10); + } return 0; } diff --git a/get_stack_space.c b/get_stack_space.c index 7f1fdd3..bb0d92b 100644 --- a/get_stack_space.c +++ b/get_stack_space.c @@ -12,7 +12,7 @@ libsimple_get_stack_space(uintptr_t *restrict low, uintptr_t *restrict high) size_t off = 0; size_t lineoff, linelen; - fd = open("/proc/self/maps", O_RDONLY); + fd = open("/proc/thread-self/maps", O_RDONLY); if (fd < 0) return -1; @@ -41,9 +41,8 @@ libsimple_get_stack_space(uintptr_t *restrict low, uintptr_t *restrict high) if (!strcmp(&line[linelen - (sizeof(" [stack]\n") - 1U)], " [stack]\n")) goto line_found; } - } - + line_found: close(fd); diff --git a/libsimple.h b/libsimple.h index ba01ab5..6d1867e 100644 --- a/libsimple.h +++ b/libsimple.h @@ -211,6 +211,7 @@ libsimple_close(int *fdp__) * @throws Any error for close(3) except EBADF * * @since 1.6 + * @since 1.8 `next` can be `NULL` */ int libsimple_close_range(unsigned int first, unsigned int last, unsigned int *next); #define LIBSIMPLE_CLOSE_RANGE_MAX (~0U) diff --git a/libsimple/definitions.h b/libsimple/definitions.h index 6fbc17f..b0f816b 100644 --- a/libsimple/definitions.h +++ b/libsimple/definitions.h @@ -218,13 +218,117 @@ * * This macro does not support the wide-character strings * - * @param STR:const char [] The string, must be a literal - * @return :size_t The value of `strlen(STR)` as a constant expression + * @param STR:string literal The string (must be a literal) + * @return :size_t The value of `strlen(STR)` as a constant expression * * @since 1.0 */ #ifndef STRLEN -# define STRLEN(STR) (sizeof(STR) - 1) +# define STRLEN(STR) (sizeof(STR) - 1U) +#endif + + +/** + * Get the length of a string, stored in as a + * character array, that might not be NUL-termianted + * + * Note that since arrays are passed as pointers + * in function arguments, function parameters + * declared as arrays are actually pointers and + * cannot be used with this macro + * + * Using this macro when `S` is a pointer, + * will cause the returned length to be truncated + * to at most `sizeof(void *)` + * + * @param S:char[] The string to get the legnth of + * @return The length of `S` + * + * @since 1.8 + */ +#ifndef BUFSTRLEN +# define BUFSTRLEN(S) (strnlen((S), sizeof(S))) /* TODO man */ +#endif + + +/** + * This macro doesn't really do anything, but + * it can be used to mark that a poorly named + * constant is the length of a string including + * the NUL byte + * + * @param X:size_t Any value + * @return :size_t `X` as is + * + * @since 1.8 + */ +#ifndef ISSTRSIZE +# define ISSTRSIZE(X) (X) /* TODO man */ +#endif + + +/** + * Macro that can be used to mark that a value + * is the length of a string excluding the NUL + * byte, but adds one to convert it to the + * length of the string inlcuding the NUL byte + * + * @param X:size_t String length excluding NUL byte + * @return :size_t String length including NUL byte + * + * @since 1.8 + */ +#ifndef TOSTRSIZE +# define TOSTRSIZE(X) ((X) + 1U) /* TODO man */ +#endif + + +/** + * This macro doesn't really do anything, but + * it can be used to mark that a poorly named + * constant is the length of a string excluding + * the NUL byte + * + * @param X:size_t Any value + * @return :size_t `X` as is + * + * @since 1.8 + */ +#ifndef ISSTRLEN +# define ISSTRLEN(X) (X) /* TODO man */ +#endif + + +/** + * Macro that can be used to mark that a value + * is the length of a string including the NUL + * byte, but substracts one to convert it to the + * length of the string exlcuding the NUL byte + * + * @param X:size_t String length including NUL byte + * @return :size_t String length excluding NUL byte + * + * @since 1.8 + */ +#ifndef TOSTRLEN +# define TOSTRLEN(X) ((X) - 1U) /* TODO man */ +#endif + + +/** + * Limit a value to an inclusive range + * + * @param MINIMUM The minimum allowed value + * @param X The value to limit + * @param MAXIMUM The maximum allowed value + * @return `X` except no less than `MINIMUM` and no greater than `MAXIMUM` + * + * `MAXIMUM` must be at least `MINIMUM` + * + * @since 1.8 + */ +#ifndef LIMITRANGE +# define LIMITRANGE(MINIMUM, X, MAXIMUM) (MIN(MAX((MINIMUM), (X)), (MAXIMUM))) /* TODO man */ #endif diff --git a/libsimple/random.h b/libsimple/random.h index 29e3bbf..d3cc008 100644 --- a/libsimple/random.h +++ b/libsimple/random.h @@ -9,8 +9,7 @@ * @since 1.6 */ LIBSIMPLE_GCC_ONLY__(__attribute__((__warn_unused_result__))) -unsigned int libsimple_generate_seed(void); /* TODO add man page */ - +unsigned int libsimple_generate_seed(void); /* TODO man */ /** * Wrapper for srand(3) that creates a pseudo-random @@ -20,14 +19,102 @@ unsigned int libsimple_generate_seed(void); /* TODO add man page */ * @since 1.6 */ inline void -libsimple_srand(void) /* TODO add man page */ +libsimple_srand(void) /* TODO man */ { srand(libsimple_generate_seed()); } +/** + * Generate a set of uniformly random bits + * + * @param bits The number of bits to generate + * @param unused This parameter is unused, but is provided so that + * the function has a prototype that is compatible + * with alternative functions that need an extra + * argument to make it reenterent + * @return An integer with it's lowest `bits` bits independently + * randomly set, each bit has a 50 % chance of being + * cleared and 50 a % chance of being set, any excess + * bit will be cleared + * + * @since 1.6 + */ +uintmax_t libsimple_random_bits(size_t bits, void *unused); /* TODO man */ -/* TODO doc, man (since 1.6) (libsimple_random_float requires -lm) */ -uintmax_t libsimple_random_bits(size_t bits, void *unused); -uintmax_t libsimple_random_unsigned(uintmax_t (*rng)(size_t bits, void *user), void *user, uintmax_t min, uintmax_t max); -intmax_t libsimple_random_signed(uintmax_t (*rng)(size_t bits, void *user), void *user, intmax_t min, intmax_t max); -long double libsimple_random_float(uintmax_t (*rng)(size_t bits, void *user), void *user, long double min, long double postmax); +/** + * Generate a uniformally random, unsigned integer with [`min`, `max`] + * + * @param rng Random bit generating function, `libsimple_random_bits` + * can be used, if any other function is used, it must + * have the same specification: the first argument is + * the number of bits to generate, the second argument + * will be `user` and is either unused or defined by the + * function, and the returned value shall have it's `bits` + * lowest bits randomly set and all other bits cleared + * @param user Pass into `*rng` as it's second argument + * @param min The lower, inclusive, boundary for the random value + * @param max The upper, inclusive, boundary for the random value + * @return A uniformally random, unsigned integer within [`min`, `max`] + * + * @since 1.6 + */ +uintmax_t libsimple_random_unsigned(uintmax_t (*rng)(size_t bits, void *user), void *user, uintmax_t min, uintmax_t max); /* TODO man */ + +/** + * Generate a uniformally random, signed integer with [`min`, `max`] + * + * @param rng Random bit generating function, `libsimple_random_bits` + * can be used, if any other function is used, it must + * have the same specification: the first argument is + * the number of bits to generate, the second argument + * will be `user` and is either unused or defined by the + * function, and the returned value shall have it's `bits` + * lowest bits randomly set and all other bits cleared + * @param user Pass into `*rng` as it's second argument + * @param min The lower, inclusive, boundary for the random value + * @param max The upper, inclusive, boundary for the random value + * @return A uniformally random, signed integer within [`min`, `max`] + * + * @since 1.6 + */ +intmax_t libsimple_random_signed(uintmax_t (*rng)(size_t bits, void *user), void *user, intmax_t min, intmax_t max); /* TODO man */ + +/** + * Generate a uniformally random, real number with [`min`, `postmax`) + * + * @param rng Random bit generating function, `libsimple_random_bits` + * can be used, if any other function is used, it must + * have the same specification: the first argument is + * the number of bits to generate, the second argument + * will be `user` and is either unused or defined by the + * function, and the returned value shall have it's `bits` + * lowest bits randomly set and all other bits cleared + * @param user Pass into `*rng` as it's second argument + * @param min The lower, inclusive, boundary for the random value + * @param max The upper, exclusive, boundary for the random value + * @return A uniformally random, real number within [`min`, `postmax`) + * + * @linkwith -lm + * + * @since 1.6 + */ +long double libsimple_random_float(uintmax_t (*rng)(size_t bits, void *user), void *user, long double min, long double postmax); /* TODO man */ + +/** + * Generate a set uniformally random bytes + * + * @param rng Random bit generating function, `libsimple_random_bits` + * can be used, if any other function is used, it must + * have the same specification: the first argument is + * the number of bits to generate, the second argument + * will be `user` and is either unused or defined by the + * function, and the returned value shall have it's `bits` + * lowest bits randomly set and all other bits cleared + * @param user Pass into `*rng` as it's second argument + * @param buffer Output buffer for the random bytes + * @param bytes The number of bytes to generate + * @return The end of `buffer` + * + * @since 1.7 + */ +void *libsimple_random_bytes(uintmax_t (*rng)(size_t bits, void *user), void *user, void *buffer, size_t bytes); /* TODO man */ diff --git a/libsimple/stack.h b/libsimple/stack.h index a7b1294..bb082f6 100644 --- a/libsimple/stack.h +++ b/libsimple/stack.h @@ -1,11 +1,53 @@ /* See LICENSE file for copyright and license details. */ -int libsimple_get_stack_space(uintptr_t *restrict, uintptr_t *restrict); /* TODO man, doc (since 1.7) */ -int libsimple_get_stack_limit(size_t *restrict, size_t *restrict); /* TODO man, doc (since 1.7) */ -int libsimple_get_stack_direction(void); /* TODO man, doc (since 1.7) */ +/** + * Get area of the the thread's stack space + * + * @param low Output parameter for the address of the beginning of the stack space + * @param high Output parameter for the address immediately after the last byte in the stack space + * @return 0 on success, -1 on failure + * + * @since 1.7 + */ +LIBSIMPLE_GCC_ONLY__(__attribute__((__nonnull__))) +int libsimple_get_stack_space(uintptr_t *restrict low, uintptr_t *restrict high); /* TODO man */ -int libsimple_needstack(size_t); /* TODO man, doc (since 1.7) */ +/** + * Get the stack size limit for the thread + * + * @param soft Output parameter for the soft limit, or `NULL` + * @param hard Output parameter for the hard limit, or `NULL` + * @return 0 on success, -1 on failure + * + * @since 1.7 + */ +int libsimple_get_stack_limit(size_t *restrict soft, size_t *restrict hard); /* TODO man */ + +/** + * Get the direction the stack grows in + * + * @return +1 if the stack grows upwards (higher addresses), + * -1 if the stack grows downwards (lower addresses), + * 0 on failure + * + * @throws ENOTSUP Unable to determine stack growth direction + * + * @since 1.7 + */ +int libsimple_get_stack_direction(void); /* TODO man */ + +/** + * Check if the some amount of memory can be allowed on the stack + * + * @param n The amount of memory + * @return 1 if `n` bytes can be allocated, + * 0 if `n` bytes may or may not be allocated, + * -1 on failure + * + * @since 1.7 + */ +int libsimple_needstack(size_t n); /* TODO man */ #ifndef needstack # define needstack libsimple_needstack #endif diff --git a/libsimple/time.h b/libsimple/time.h index b873635..5317cfc 100644 --- a/libsimple/time.h +++ b/libsimple/time.h @@ -1,6 +1,45 @@ /* See LICENSE file for copyright and license details. */ +/* TODO man, doc (since 1.8) */ +#define LIBSIMPLE_NANOSECONDS_PER_NANOSECOND UINT64_C(1) +#define LIBSIMPLE_NANOSECONDS_PER_MICROSECOND UINT64_C(1000) +#define LIBSIMPLE_NANOSECONDS_PER_MILLISECOND (LIBSIMPLE_NANOSECONDS_PER_MICROSECOND * UINT64_C(1000)) +#define LIBSIMPLE_NANOSECONDS_PER_SECOND (LIBSIMPLE_NANOSECONDS_PER_MILLISECOND * UINT64_C(1000)) +#define LIBSIMPLE_NANOSECONDS_PER_MINUTE (LIBSIMPLE_NANOSECONDS_PER_SECOND * UINT64_C(60)) +#define LIBSIMPLE_NANOSECONDS_PER_HOUR (LIBSIMPLE_NANOSECONDS_PER_MINUTE * UINT64_C(60)) +#define LIBSIMPLE_NANOSECONDS_PER_DAY (LIBSIMPLE_NANOSECONDS_PER_HOUR * UINT64_C(24)) +#define LIBSIMPLE_NANOSECONDS_PER_WEEK (LIBSIMPLE_NANOSECONDS_PER_DAY * UINT64_C(7)) +#define LIBSIMPLE_MICROSECONDS_PER_MICROSECOND UINT64_C(1) +#define LIBSIMPLE_MICROSECONDS_PER_MILLISECOND UINT64_C(1000) +#define LIBSIMPLE_MICROSECONDS_PER_SECOND (LIBSIMPLE_MICROSECONDS_PER_MICROSECOND * UINT64_C(1000)) +#define LIBSIMPLE_MICROSECONDS_PER_MINUTE (LIBSIMPLE_MICROSECONDS_PER_SECOND * UINT64_C(60)) +#define LIBSIMPLE_MICROSECONDS_PER_HOUR (LIBSIMPLE_MICROSECONDS_PER_MINUTE * UINT64_C(60)) +#define LIBSIMPLE_MICROSECONDS_PER_DAY (LIBSIMPLE_MICROSECOND_PER_HOUR * UINT64_C(24)) +#define LIBSIMPLE_MICROSECONDS_PER_WEEK (LIBSIMPLE_MICROSECOND_PER_DAY * UINT64_C(7)) +#define LIBSIMPLE_MILLISECONDS_PER_MILLISECONDS UINT64_C(1) +#define LIBSIMPLE_MILLISECONDS_PER_SECOND UINT64_C(1000) +#define LIBSIMPLE_MILLISECONDS_PER_MINUTE (LIBSIMPLE_MILLISECONDS_PER_SECOND * UINT64_C(60)) +#define LIBSIMPLE_MILLISECONDS_PER_HOUR (LIBSIMPLE_MILLISECONDS_PER_MINUTE * UINT64_C(60)) +#define LIBSIMPLE_MILLISECONDS_PER_DAY (LIBSIMPLE_MILLISECONDS_PER_HOUR * UINT64_C(24)) +#define LIBSIMPLE_MILLISECONDS_PER_WEEK (LIBSIMPLE_MILLISECONDS_PER_DAY * UINT64_C(7)) +#define LIBSIMPLE_SECONDS_PER_SECOND UINT64_C(1) +#define LIBSIMPLE_SECONDS_PER_MINUTE UINT64_C(60) +#define LIBSIMPLE_SECONDS_PER_HOUR (LIBSIMPLE_SECONDS_PER_MINUTE * UINT64_C(60)) +#define LIBSIMPLE_SECONDS_PER_DAY (LIBSIMPLE_SECONDS_PER_HOUR * UINT64_C(24)) +#define LIBSIMPLE_SECONDS_PER_WEEK (LIBSIMPLE_SECONDS_PER_DAY * UINT64_C(7)) +#define LIBSIMPLE_MINUTES_PER_MINUTE UINT64_C(1) +#define LIBSIMPLE_MINUTES_PER_HOUR UINT64_C(60) +#define LIBSIMPLE_MINUTES_PER_DAY (LIBSIMPLE_MINUTES_PER_HOUR * UINT64_C(24)) +#define LIBSIMPLE_MINUTES_PER_WEEK (LIBSIMPLE_MINUTES_PER_DAY * UINT64_C(7)) +#define LIBSIMPLE_HOURS_PER_HOUR UINT64_C(1) +#define LIBSIMPLE_HOURS_PER_DAY UINT64_C(24) +#define LIBSIMPLE_HOURS_PER_WEEK (LIBSIMPLE_HOURS_PER_DAY * UINT64_C(7)) +#define LIBSIMPLE_DAYS_PER_DAY UINT64_C(1) +#define LIBSIMPLE_DAYS_PER_WEEK UINT64_C(7) +#define LIBSIMPLE_WEEKS_PER_WEEK UINT64_C(1) + + /** * Calculates the sum of two `struct timespec`s * diff --git a/man3/libsimple_close_range.3 b/man3/libsimple_close_range.3 index 76094d0..a1b172c 100644 --- a/man3/libsimple_close_range.3 +++ b/man3/libsimple_close_range.3 @@ -69,7 +69,10 @@ None. libsimple 1.6 .SH BUGS -None. +.I next +could not be +.I NULL +before version 1.8 of libsimple. .SH SEE ALSO .BR close_range (2), diff --git a/random_bits.c b/random_bits.c index 528b09e..a6d95a2 100644 --- a/random_bits.c +++ b/random_bits.c @@ -14,8 +14,10 @@ libsimple_random_bits(size_t bits, void *unused) bits -= 8; } - ret <<= bits; - ret |= (uintmax_t)(rand() & ((1 << bits) - 1)); + if (bits) { + ret <<= bits; + ret |= (uintmax_t)(rand() & ((1 << bits) - 1)); + } (void) unused; return ret; diff --git a/random_bytes.c b/random_bytes.c new file mode 100644 index 0000000..723fc63 --- /dev/null +++ b/random_bytes.c @@ -0,0 +1,41 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +void * +libsimple_random_bytes(uintmax_t (*rng)(size_t bits, void *user), void *user, void *buffer, size_t bytes) +{ + char *buf = buffer; + uintmax_t rnd; + + while (bytes >= sizeof(uintmax_t)) { + rnd = (*rng)(sizeof(uintmax_t) * 8U, user); + memcpy(buf, &rnd, sizeof(uintmax_t)); + bytes -= sizeof(uintmax_t); + buf = &buf[sizeof(uintmax_t)]; + } + + if (bytes) { + rnd = (*rng)(bytes * 8U, user); + while (bytes) { + *buf++ = (char)(rnd & 255U); + bytes--; + rnd >>= 8; + } + } + + return buf; +} + + +#else +#include "test.h" + +int +main(void) +{ + return 0; +} + +#endif |