summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-30 10:41:29 +0300
committerPaul Buetow <paul@buetow.org>2026-05-30 10:41:29 +0300
commit1491f883fc6feee512e92bde9af884852502dd0b (patch)
tree0c455542b712e019b9ba03ab14791fd91ef9a5fe
parent48434d3767c6b15e8d86b1f3d06d9498337d2301 (diff)
Document Process-vs-Misc boundary; keep set_tid_address in Process (task 920)
Resolve the family-split question for set_tid_address vs its per-thread registration siblings rseq/set_robust_list/get_robust_list (Misc). DECISION: keep set_tid_address in FamilyProcess. The 520 registration-vs- operation rule governs the IPC-vs-Misc boundary (does the syscall perform the futex/sync op?), not Process-vs-Misc. set_tid_address registers clear_child_tid, the kernel's primary thread-EXIT notification mechanism (zeroed + FUTEX_WAKEd at teardown), set by the C runtime for essentially every thread via clone(2) CLONE_CHILD_CLEARTID, and returns the caller's tid like gettid/getpid -- mandatory thread-lifecycle plumbing belonging with clone/fork/exit/gettid. rseq (scheduling optimization) and robust_list (opt-in futex cleanup) are OPTIONAL per-thread features and stay Misc. - family.go: add Process-vs-Misc boundary-rule block (mandatory-thread- lifecycle vs optional-opt-in-feature axis) next to set_tid_address. - family_test.go: lock in set_tid_address enter+exit as Process with a WHY comment contrasting it against the rseq/robust_list Misc cluster. No generated-artifact or docs drift: classification unchanged (Process list in docs/syscall-tracing-plan.md already correct); mage generate is idempotent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
-rw-r--r--internal/generate/family.go33
-rw-r--r--internal/generate/family_test.go18
2 files changed, 50 insertions, 1 deletions
diff --git a/internal/generate/family.go b/internal/generate/family.go
index dafbe13..daa7ab8 100644
--- a/internal/generate/family.go
+++ b/internal/generate/family.go
@@ -101,7 +101,38 @@ var syscallFamilies = map[string]SyscallFamily{
"ioprio_get": FamilyProcess, "ioprio_set": FamilyProcess,
"kcmp": FamilyProcess, "personality": FamilyProcess, "pivot_root": FamilyProcess,
"prctl": FamilyProcess, "prlimit64": FamilyProcess, "reboot": FamilyProcess,
- "restart_syscall": FamilyProcess, "set_tid_address": FamilyProcess,
+ "restart_syscall": FamilyProcess,
+ // Boundary rule for the Process vs Misc split of PER-THREAD POINTER
+ // REGISTRATION syscalls (keep consistent — distinct from the futex IPC-vs-
+ // Misc rule documented in the futex block above):
+ //
+ // - set_tid_address(2) stays Process. Although it "merely" hands the
+ // kernel a tidptr it consults later, that pointer is the kernel's
+ // primary THREAD-EXIT notification mechanism: it sets clear_child_tid,
+ // which the kernel zeroes and FUTEX_WAKEs at thread teardown. The C
+ // runtime sets it (via clone(2) CLONE_CHILD_CLEARTID, or this syscall)
+ // for essentially every thread, the call returns the caller's thread ID
+ // (a pid_t, like gettid/getpid), and it is mandatory thread-lifecycle
+ // plumbing. It therefore belongs with the core process/thread lifecycle
+ // cluster — clone/clone3/fork/vfork/exit/exit_group/wait4/waitid/gettid
+ // — not with optional opt-in features.
+ //
+ // - rseq(2) and set_robust_list/get_robust_list(2) stay Misc (absent from
+ // this table by design; see ClassifySyscallFamily's default and the
+ // assertions in family_test.go). They register OPTIONAL, opt-in
+ // per-thread feature areas: rseq a restartable-sequences scheduling
+ // optimization, robust_list a futex-cleanup list a program only uses if
+ // it opts into robust mutexes. They are not part of the mandatory
+ // thread-lifecycle path and a thread runs fine without ever calling
+ // them.
+ //
+ // The split axis here is mandatory-thread-lifecycle vs optional-opt-in-
+ // feature, NOT pointer-registration-vs-operation (which would lump all
+ // three into Misc). Do not move set_tid_address to Misc for "registration
+ // consistency" with rseq/robust_list: registration is the surface form, but
+ // set_tid_address is core thread lifecycle while the others are optional
+ // features.
+ "set_tid_address": FamilyProcess,
"setfsuid": FamilyProcess, "setfsgid": FamilyProcess, "setgid": FamilyProcess,
"setgroups": FamilyProcess, "setns": FamilyProcess, "setpgid": FamilyProcess,
"setpriority": FamilyProcess, "setregid": FamilyProcess, "setresgid": FamilyProcess,
diff --git a/internal/generate/family_test.go b/internal/generate/family_test.go
index 4bff095..ee92740 100644
--- a/internal/generate/family_test.go
+++ b/internal/generate/family_test.go
@@ -166,6 +166,24 @@ func TestClassifySyscallFamily(t *testing.T) {
{"sys_exit_rseq", FamilyMisc},
{"sys_enter_set_robust_list", FamilyMisc},
{"sys_enter_get_robust_list", FamilyMisc},
+ // set_tid_address(2) is the deliberate counterpoint to the
+ // rseq/robust_list cluster above: it shares the surface form
+ // ("per-thread registration of a pointer the kernel consults later")
+ // but stays Process, NOT Misc. WHY: the tidptr it registers is
+ // clear_child_tid — the kernel's primary thread-EXIT notification
+ // mechanism (zeroed + FUTEX_WAKEd at thread teardown), set by the C
+ // runtime for essentially every thread (clone(2) CLONE_CHILD_CLEARTID),
+ // and the call returns the caller's thread ID like gettid/getpid. It is
+ // mandatory thread-lifecycle plumbing and belongs with
+ // clone/fork/exit/gettid, whereas rseq (scheduling optimization) and
+ // robust_list (opt-in futex cleanup) are OPTIONAL per-thread features a
+ // thread runs fine without. The Process-vs-Misc axis here is
+ // mandatory-lifecycle vs optional-opt-in-feature, not registration-vs-
+ // operation. Assert enter+exit so a stray move to Misc trips this test.
+ // See the Process-vs-Misc boundary block in family.go and keep in sync
+ // with the Process list in docs/syscall-tracing-plan.md.
+ {"sys_enter_set_tid_address", FamilyProcess},
+ {"sys_exit_set_tid_address", FamilyProcess},
// sysinfo(2) returns overall system statistics (memory/swap usage and
// load averages) into a single userspace struct sysinfo *info pointer
// (an output buffer, not an fd/path). It is not in the explicit family