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 <stddef.h>
19#include <stdint.h>
20
21/*
22 * --- Environment (thread-safe against concurrent get/set) ---
23 *
24 * getenv(3) and setenv(3) are not safe against each other: setenv may
25 * reallocate the environ block a concurrent getenv is reading. These
26 * serialize every get/set on one process-wide mutex, and get COPIES
27 * the value into a caller buffer so the returned data cannot be
28 * invalidated by a later setenv from another thread.
29 *
30 * __os_env_get copies the value of `name` into `buf` (always
31 * NUL-terminated when bufsize > 0, truncating if needed). Returns
32 * XTC_OK when the variable exists, XTC_E_NOTFOUND when it does not
33 * (buf is set to the empty string), XTC_E_INVAL on a NULL argument.
34 *
35 * __os_env_set sets/overwrites `name` to `value`; when overwrite == 0
36 * an existing variable is left unchanged. Returns XTC_OK, or
37 * XTC_E_INVAL / XTC_E_NOMEM.
38 *
39 * PUBLIC: int __os_env_get __P((const char *, char *, size_t));
40 * PUBLIC: int __os_env_set __P((const char *, const char *, int));
41 */
42int __os_env_get(const char *name, char *buf, size_t bufsize);
43int __os_env_set(const char *name, const char *value, int overwrite);
44
45/*
46 * --- Per-thread seedable PRNG ---
47 *
48 * rand(3)/random(3) share process-global state and are not thread-safe.
49 * This is a per-thread splitmix64 stream: each thread has its own state
50 * so there is no cross-thread contention or shared-state race, and
51 * __os_rand_seed makes a thread's stream reproducible. The first use
52 * on a thread that has not been seeded auto-seeds from the monotonic
53 * clock XORed with the thread-local state address, so distinct threads
54 * get distinct streams by default.
55 *
56 * NOTE: this is NOT wired into the DST deterministic-simulation clock
57 * (src/evt/sim.c); a future task can add a sim hook here so a
58 * replayed run draws a reproducible sequence. For now it is simply a
59 * clean, thread-safe, explicitly seedable entropy source.
60 *
61 * PUBLIC: void __os_rand_seed __P((uint64_t));
62 * PUBLIC: uint64_t __os_rand_u64 __P((void));
63 */
64void __os_rand_seed(uint64_t seed);
65uint64_t __os_rand_u64(void);
66
67/*
68 * --- Bounded string copy/cat (BSD strlcpy/strlcat semantics) ---
69 *
70 * strncpy(3) does not NUL-terminate when the source is at least as long
71 * as the buffer; strncat(3) uses a confusing count. These follow the
72 * OpenBSD contract: always NUL-terminate when dstsize > 0, and return
73 * the total length the function TRIED to create -- for strlcpy that is
74 * strlen(src); for strlcat that is the initial strlen(dst) plus
75 * strlen(src). A return value >= dstsize means the result was
76 * truncated. Pure; no allocation.
77 *
78 * PUBLIC: size_t __os_strlcpy __P((char *, const char *, size_t));
79 * PUBLIC: size_t __os_strlcat __P((char *, const char *, size_t));
80 */
81size_t __os_strlcpy(char *dst, const char *src, size_t dstsize);
82size_t __os_strlcat(char *dst, const char *src, size_t dstsize);
83
84#endif /* XTC_OS_SHARP_H */