os: API for listing cgroup controllers

This commit is contained in:
Mitchell Hashimoto
2024-06-04 19:23:18 -07:00
parent 409c958b7e
commit c0b061edd9
2 changed files with 62 additions and 0 deletions

View File

@ -41,9 +41,36 @@ pub fn init(app: *App) ![]const u8 {
errdefer alloc.free(transient);
log.info("transient scope created cgroup={s}", .{transient});
// Enable all of our cgroup controllers. If these fail then
// we just log. We can't reasonably undo what we've done above
// so we log the warning and still return the transient group.
// I don't know a scenario where this fails yet.
try enableControllers(alloc, transient);
return transient;
}
/// Enable all the cgroup controllers for the given cgroup.
fn enableControllers(alloc: Allocator, cgroup: []const u8) !void {
const raw = try internal_os.linux.cgroupControllers(alloc, cgroup);
defer alloc.free(raw);
// Build our string builder for enabling all controllers
var builder = std.ArrayList(u8).init(alloc);
defer builder.deinit();
// Controllers are space-separated
var it = std.mem.splitScalar(u8, raw, ' ');
while (it.next()) |controller| {
try builder.append('+');
try builder.appendSlice(controller);
if (it.rest().len > 0) try builder.append(' ');
}
// TODO
log.warn("enabling controllers={s}", .{builder.items});
}
/// Create a transient systemd scope unit for the current process.
///
/// On success this will return the name of the transient scope

View File

@ -1,4 +1,5 @@
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
/// Returns the path to the cgroup for the given pid.
@ -26,3 +27,37 @@ pub fn cgroupPath(alloc: Allocator, pid: std.os.linux.pid_t) !?[]const u8 {
const result = std.mem.trimRight(u8, contents[idx + 1 ..], " \r\n");
return try alloc.dupe(u8, result);
}
/// Returns all available cgroup controllers for the given cgroup.
/// The cgroup should have a '/'-prefix.
///
/// The returned list of is the raw space-separated list of
/// controllers from the /sys/fs directory. This avoids some extra
/// work since creating an iterator over this is easy and much cheaper
/// than allocating a bunch of copies for an array.
pub fn cgroupControllers(alloc: Allocator, cgroup: []const u8) ![]const u8 {
assert(cgroup[0] == '/');
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
// Read the available controllers. These will be space separated.
const path = try std.fmt.bufPrint(
&buf,
"/sys/fs/cgroup{s}/cgroup.controllers",
.{cgroup},
);
const file = try std.fs.cwd().openFile(path, .{});
defer file.close();
// Read it all into memory -- we don't expect this file to ever
// be that large.
var buf_reader = std.io.bufferedReader(file.reader());
const contents = try buf_reader.reader().readAllAlloc(
alloc,
1 * 1024 * 1024, // 1MB
);
defer alloc.free(contents);
// Return our raw list of controllers
const result = std.mem.trimRight(u8, contents, " \r\n");
return try alloc.dupe(u8, result);
}