summaryrefslogtreecommitdiff
path: root/9proc/src/linux/runtime.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-19 23:28:22 -0300
committerGabriel Schneider <[email protected]>2026-09-19 23:28:22 -0300
commitba996acfcad1698adbf4a1834fe50e73b1c6cab9 (patch)
tree282ba00ce5b10d7416aecb9f2f0f0a439340a57d /9proc/src/linux/runtime.zig
parentb05abcba3ea09ea106ad28364c6e40a3ec31b890 (diff)
downloadcloud9-ba996acfcad1698adbf4a1834fe50e73b1c6cab9.tar.gz
cloud9-ba996acfcad1698adbf4a1834fe50e73b1c6cab9.zip
Rename programs: 9player -> 9ns, introspect -> 9proc, app -> web (9web)
Directories, binaries, build options (-D9ns, -D9proc), step names, module name (9proc), thread and fs names, env var NINEPLAYER_MOUNT -> NINE_MOUNT, docs and test scripts. Browser assets move to web/static. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to '9proc/src/linux/runtime.zig')
-rw-r--r--9proc/src/linux/runtime.zig90
1 files changed, 90 insertions, 0 deletions
diff --git a/9proc/src/linux/runtime.zig b/9proc/src/linux/runtime.zig
new file mode 100644
index 0000000..503d6c2
--- /dev/null
+++ b/9proc/src/linux/runtime.zig
@@ -0,0 +1,90 @@
+//! Generators for `Config.runtime`: /runtime/{pid,ppid,uptime,argv,cwd,env,clients}.
+//! The core passes every generator `Shared.ctx`; `Fns(Ctx, field)` casts it
+//! to `*Ctx` and reads the `Info` stored in `@field(ctx, field)`.
+const std = @import("std");
+const linux = std.os.linux;
+const Writer = std.Io.Writer;
+
+/// What the generators report. Texts are borrowed for the server's lifetime.
+pub const Info = struct {
+ /// argv, one argument per line.
+ argv: []const u8 = "",
+ /// Environment, one KEY=VALUE per line.
+ env: []const u8 = "",
+ cwd: []const u8 = "",
+ /// Monotonic seconds at startup; /runtime/uptime is the difference.
+ start_mono: i64 = 0,
+ /// Live client count, published by the probe.
+ clients: ?*const std.atomic.Value(u32) = null,
+
+ pub fn now() Info {
+ return .{ .start_mono = monotonicSecs() };
+ }
+};
+
+pub fn monotonicSecs() i64 {
+ var ts: linux.timespec = undefined;
+ _ = linux.clock_gettime(.MONOTONIC, &ts);
+ return ts.sec;
+}
+
+/// Seconds since the epoch, clamped to u32 (for atime/mtime and `fn/now`).
+pub fn realtimeSecs() u32 {
+ var ts: linux.timespec = undefined;
+ _ = linux.clock_gettime(.REALTIME, &ts);
+ return @intCast(std.math.clamp(ts.sec, 0, std.math.maxInt(u32)));
+}
+
+/// The `Config.runtime` type: `Ctx` is the type behind `Shared.ctx`, `field`
+/// the name of its `Info` field.
+pub fn Fns(comptime Ctx: type, comptime field: []const u8) type {
+ return struct {
+ fn info(ctx: *anyopaque) *const Info {
+ const c: *Ctx = @ptrCast(@alignCast(ctx));
+ return &@field(c, field);
+ }
+ pub fn pid(_: *anyopaque, w: *Writer) anyerror!void {
+ try w.print("{d}", .{linux.getpid()});
+ }
+ pub fn ppid(_: *anyopaque, w: *Writer) anyerror!void {
+ try w.print("{d}", .{linux.getppid()});
+ }
+ pub fn uptime(ctx: *anyopaque, w: *Writer) anyerror!void {
+ try w.print("{d}", .{monotonicSecs() - info(ctx).start_mono});
+ }
+ pub fn argv(ctx: *anyopaque, w: *Writer) anyerror!void {
+ try w.writeAll(info(ctx).argv);
+ }
+ pub fn cwd(ctx: *anyopaque, w: *Writer) anyerror!void {
+ try w.writeAll(info(ctx).cwd);
+ }
+ pub fn env(ctx: *anyopaque, w: *Writer) anyerror!void {
+ try w.writeAll(info(ctx).env);
+ }
+ pub fn clients(ctx: *anyopaque, w: *Writer) anyerror!void {
+ const n: u32 = if (info(ctx).clients) |c| c.load(.acquire) else 0;
+ try w.print("{d}", .{n});
+ }
+ };
+}
+
+test "runtime generators read Info through the context" {
+ const Ctx = struct { x: u32, info: Info };
+ var count: std.atomic.Value(u32) = .init(3);
+ var ctx: Ctx = .{ .x = 0, .info = .{ .argv = "a\nb\n", .cwd = "/tmp", .env = "K=V\n", .start_mono = monotonicSecs(), .clients = &count } };
+ const F = Fns(Ctx, "info");
+ var buf: [64]u8 = undefined;
+ var w: Writer = .fixed(&buf);
+ try F.clients(&ctx, &w);
+ try std.testing.expectEqualStrings("3", w.buffered());
+ w = .fixed(&buf);
+ try F.argv(&ctx, &w);
+ try std.testing.expectEqualStrings("a\nb\n", w.buffered());
+ w = .fixed(&buf);
+ try F.uptime(&ctx, &w);
+ try std.testing.expect(w.buffered().len >= 1);
+ w = .fixed(&buf);
+ try F.pid(&ctx, &w);
+ try std.testing.expectEqual(linux.getpid(), try std.fmt.parseInt(i32, w.buffered(), 10));
+ try std.testing.expectEqual(@as(usize, 7), @typeInfo(F).@"struct".decls.len);
+}