libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
os_sharp.h
1/*-
2 * Copyright (c) 2026, The XTC Project
3 * Use of this source code is governed by the ISC License.
4 *
5 * src/inc/os_sharp.h
6 * POSIX/libc "sharp edges" abstraction: thread-safe environment
7 * access, a per-thread seedable PRNG, and BSD-semantics bounded
8 * string copy/cat. These smooth three well-known threaded-C
9 * footguns (getenv/setenv races, the process-global non-reentrant
10 * rand(), and strncpy's missing NUL terminator). The public
11 * complement is xtc_env_get / xtc_env_set / xtc_rand_u64 /
12 * xtc_rand_seed / xtc_strlcpy / xtc_strlcat.
13 */
14
15#ifndef XTC_OS_SHARP_H
16#define XTC_OS_SHARP_H
17
18#include "xtc_export.h"
19
20#include <stddef.h>
21#include <stdint.h>
22
23/*
24 * --- Environment (thread-safe against concurrent get/set) ---
25 *
26 * getenv(3) and setenv(3) are not safe against each other: setenv may
27 * reallocate the environ block a concurrent getenv is reading. These
28 * serialize every get/set on one process-wide mutex, and get COPIES
29 * the value into a caller buffer so the returned data cannot be
30 * invalidated by a later setenv from another thread.
31 *
32 * __os_env_get copies the value of `name` into `buf` (always
33 * NUL-terminated when bufsize > 0, truncating if needed). Returns
34 * XTC_OK when the variable exists, XTC_E_NOTFOUND when it does not
35 * (buf is set to the empty string), XTC_E_INVAL on a NULL argument.
36 *
37 * __os_env_set sets/overwrites `name` to `value`; when overwrite == 0
38 * an existing variable is left unchanged. Returns XTC_OK, or
39 * XTC_E_INVAL / XTC_E_NOMEM.
40 *
41 * PUBLIC: int __os_env_get __P((const char *, char *, size_t));
42 * PUBLIC: int __os_env_set __P((const char *, const char *, int));
43 */
44XTC_API int __os_env_get(const char *name, char *buf, size_t bufsize);
45XTC_API int __os_env_set(const char *name, const char *value, int overwrite);
46
47/*
48 * --- Per-thread seedable PRNG ---
49 *
50 * rand(3)/random(3) share process-global state and are not thread-safe.
51 * This is a per-thread splitmix64 stream: each thread has its own state
52 * so there is no cross-thread contention or shared-state race, and
53 * __os_rand_seed makes a thread's stream reproducible. The first use
54 * on a thread that has not been seeded auto-seeds from the monotonic
55 * clock XORed with the thread-local state address, so distinct threads
56 * get distinct streams by default.
57 *
58 * NOTE: this is NOT wired into the DST deterministic-simulation clock
59 * (src/evt/sim.c); a future task can add a sim hook here so a
60 * replayed run draws a reproducible sequence. For now it is simply a
61 * clean, thread-safe, explicitly seedable entropy source.
62 *
63 * PUBLIC: void __os_rand_seed __P((uint64_t));
64 * PUBLIC: uint64_t __os_rand_u64 __P((void));
65 */
66XTC_API void __os_rand_seed(uint64_t seed);
67XTC_API uint64_t __os_rand_u64(void);
68
69/*
70 * --- Bounded string copy/cat (BSD strlcpy/strlcat semantics) ---
71 *
72 * strncpy(3) does not NUL-terminate when the source is at least as long
73 * as the buffer; strncat(3) uses a confusing count. These follow the
74 * OpenBSD contract: always NUL-terminate when dstsize > 0, and return
75 * the total length the function TRIED to create -- for strlcpy that is
76 * strlen(src); for strlcat that is the initial strlen(dst) plus
77 * strlen(src). A return value >= dstsize means the result was
78 * truncated. Pure; no allocation.
79 *
80 * PUBLIC: size_t __os_strlcpy __P((char *, const char *, size_t));
81 * PUBLIC: size_t __os_strlcat __P((char *, const char *, size_t));
82 */
83XTC_API size_t __os_strlcpy(char *dst, const char *src, size_t dstsize);
84XTC_API size_t __os_strlcat(char *dst, const char *src, size_t dstsize);
85
86#endif /* XTC_OS_SHARP_H */