libxtc 0.4.0
Async concurrency for C: Tokio + Seastar + BEAM, in one library
Loading...
Searching...
No Matches
xtc_trace.h
1/*-
2 * Copyright (c) 2026, The XTC Project
3 * @stability stable
4 * Use of this source code is governed by the ISC License.
5 *
6 * src/inc/xtc_trace.h
7 * Causal message tracing -- libxtc's seq_trace. An opt-in,
8 * bounded ring of trace events (message sends and receives,
9 * process spawns and exits), each stamped with a hybrid logical
10 * clock (HLC) so the true happens-before of a request can be
11 * reconstructed across procs and cores even when wall-clock
12 * arrival order lies.
13 *
14 * The HLC is a 64-bit stamp: the high 48 bits are a monotonic
15 * physical-time component (microseconds) and the low 16 bits a
16 * logical counter. Every traced event ticks one global clock, so
17 * a send's stamp is always less than the stamp of the receive it
18 * causes; a RECV record also carries the originating SEND's stamp
19 * in `cause`, so the causal edge is explicit. (A per-shard HLC for
20 * the MVCC data path is a separate, later
21 * use of the same idea.)
22 *
23 * Tracing is OFF by default and costs a single relaxed atomic load
24 * on the message hot path when disabled. When enabled it serializes
25 * ring writes under a lock; enable it to debug, as with recon/dbg
26 * in the BEAM, not as an always-on production tax.
27 *
28 * See docs/guide/debugging.md.
29 */
30
31#ifndef XTC_TRACE_H
32#define XTC_TRACE_H
33
34#include "xtc_export.h"
35
36#include <stddef.h>
37#include <stdint.h>
38
39#include "xtc.h"
40#include "xtc_proc.h"
41
42enum xtc_trace_kind {
43 XTC_TRACE_SEND = 0, /* self sent a message to peer */
44 XTC_TRACE_RECV = 1, /* self received a message from peer */
45 XTC_TRACE_SPAWN = 2, /* self (parent) spawned peer (child) */
46 XTC_TRACE_EXIT = 3 /* self exited; detail = reason */
47};
48
49typedef struct xtc_trace_rec {
50 uint64_t hlc; /* this event's HLC stamp */
51 uint64_t cause; /* RECV: the originating send's HLC; else 0 */
52 int kind; /* enum xtc_trace_kind */
53 xtc_pid_t self; /* the proc the event happened in */
54 xtc_pid_t peer; /* the other proc (dest / source / child) */
55 uint32_t detail; /* SEND/RECV: payload bytes; EXIT: reason */
57
58/* Visit callback: return 0 to continue, nonzero to stop early. */
59typedef int (*xtc_trace_fn)(const xtc_trace_rec_t *rec, void *user);
60
61/*
62 * PUBLIC: int xtc_trace_enable __P((int));
63 * PUBLIC: int xtc_trace_reset __P((void));
64 * PUBLIC: int xtc_trace_dump __P((xtc_trace_fn, void *));
65 * PUBLIC: uint64_t xtc_hlc_now __P((void));
66 */
67
68/* Turn tracing on (on != 0) or off. Returns the previous state. */
69XTC_API int xtc_trace_enable(int on);
70
71/* Drop all buffered trace records. Returns XTC_OK. */
72XTC_API int xtc_trace_reset(void);
73
74/* Visit buffered records in causal (HLC-ascending) order. Returns the
75 * number visited, or a negative XTC_E_* on error. */
76XTC_API int xtc_trace_dump(xtc_trace_fn cb, void *user);
77
78/* The current global HLC value (for tests and display). */
79XTC_API uint64_t xtc_hlc_now(void);
80
81/* ---- A3: async causal trace (per-fiber suspend/resume ring) ----
82 *
83 * Cats Effect keeps a small per-fiber ring of the await/resume call
84 * sites and splices that causal chain onto a fault or fiber dump, so a
85 * dump answers not just WHAT a fiber's state is now but HOW it got here.
86 * This is libxtc's C analog. Where xtc_trace above records the causal
87 * chain of MESSAGES between procs (seq_trace), the causal trace here
88 * records the suspend/resume chain WITHIN one proc: the ordered sites at
89 * which the fiber parked and resumed (mailbox recv, timer sleep, fd
90 * wait, ...). xtc_dump splices each proc's recent chain onto its state
91 * line when the trace is enabled.
92 *
93 * It is OFF by default and ZERO-COST when off: the per-proc ring is
94 * written only when the trace is enabled, so a disabled trace is a
95 * single relaxed-atomic load + branch on the suspend/resume boundary and
96 * touches no memory. The ring is per-proc and core-private -- each
97 * write is one index bump and a store on the owning fiber, no lock, no
98 * atomic on the record, no allocation after spawn. Enable it to debug a
99 * stuck or mis-scheduled fiber, not as an always-on tax.
100 *
101 * See docs/guide/debugging.md.
102 */
103
104/* The kind of suspend/resume boundary a causal record marks. A PARK_*
105 * value names WHY the fiber suspended; RESUME marks the matching wake. */
106enum xtc_causal_kind {
107 XTC_CAUSAL_PARK_MAILBOX = 0, /* parked in xtc_recv* (await a message) */
108 XTC_CAUSAL_PARK_TIMER = 1, /* parked in xtc_proc_sleep (a delay) */
109 XTC_CAUSAL_PARK_FD = 2, /* parked in xtc_proc_wait_fd (I/O) */
110 XTC_CAUSAL_RESUME = 3 /* the fiber resumed after a park */
111};
112
113/* One per-fiber causal record: the boundary kind + a static site label
114 * (the __func__ of the park site, or a caller-supplied string literal --
115 * always a static string, so the ring stores the pointer, never a copy). */
116typedef struct xtc_causal_rec {
117 int kind; /* enum xtc_causal_kind */
118 const char *site; /* static label (e.g. __func__); never freed */
120
121/* Visit callback: return 0 to continue, nonzero to stop early. */
122typedef int (*xtc_causal_fn)(const xtc_causal_rec_t *rec, void *user);
123
124/*
125 * PUBLIC: int xtc_trace_causal_enable __P((int));
126 * PUBLIC: int xtc_trace_causal_dump __P((xtc_pid_t, xtc_causal_fn, void *));
127 */
128
129/* Turn the per-fiber causal trace on (on != 0) or off. Returns the
130 * previous state (1 on, 0 off). Off by default; when off the
131 * suspend/resume boundary pays one relaxed load + branch. */
132XTC_API int xtc_trace_causal_enable(int on);
133
134/* Visit the causal records of proc `pid` oldest-first (the fiber's
135 * recent park/resume chain). Returns the number visited, XTC_E_NOTFOUND
136 * if no live proc has that pid, or XTC_E_INVAL on a NULL callback. When
137 * the trace is disabled a live proc simply has an empty ring (0). */
138XTC_API int xtc_trace_causal_dump(xtc_pid_t pid, xtc_causal_fn cb, void *user);
139
140#endif /* XTC_TRACE_H */