1 module symmetry.linux.cgroups;
2 import symmetry.sildoc;
3 
4 version(Posix):
5 
6 import symmetry.linux.file : fdopen, fdclose;
7 
8 struct CGroupSetting
9 {
10 	string name;
11 	string value;
12 }
13 
14 alias CGroupSettings = CGroupSetting[];
15 alias CGroups = CGroupSettings[string];
16 
17 enum CGroupSetting addToTasks = {
18 	name: "tasks",
19 };
20 
21 struct ChildConfig
22 {
23 	int fd;
24 	string mountDir;
25 	string hostname;
26 	int uid;
27 	int gid;
28 	CGroups cGroups;
29 	int rlimitMax = 64;
30 	int rlimitCur = 64;
31 }
32 
33 enum MEMORY = "1073741824";
34 enum SHARES = "256";
35 enum PIDS = "64";
36 enum WEIGHT = "10";
37 
38 enum CGroups defaultCGroups =
39 [
40 	"memory":	[		CGroupSetting("memory.limit_in_bytes",MEMORY),
41 					CGroupSetting("memory.kmem.limit_in_bytes",MEMORY),
42 					addToTasks,
43 			],
44 
45 	"cpu":		[
46 					CGroupSetting("cpu.shares",SHARES),
47 					addToTasks,
48 			],
49 	
50 	"pids":		[
51 					CGroupSetting("pids.max",PIDS),
52 					addToTasks,
53 			],
54 
55 	"blkio":	[
56 					CGroupSetting("blkio.weight",PIDS),
57 					addToTasks,
58 			],
59 ];
60 
61 
62 void setCGroups(in ChildConfig config)
63 {
64 	import std.stdio: stderr,writeln,writefln;
65 	import std.exception : enforce;
66 	import std.format : format;
67 	import std.file : mkdir;
68 	import core.sys.posix.unistd : write, close;
69 	import core.sys.posix.fcntl : O_WRONLY;
70 	import core.sys.posix.sys.resource: setrlimit, rlimit, RLIMIT_NOFILE;
71 	import std..string : fromStringz, toStringz;
72 
73 	version(Trace) stderr.writeln("=> setting cgroups...");
74 
75 	foreach(cGroup; config.cGroups.byKeyValue)
76 	{
77 		version(Trace) stderr.writefln("%s...", cGroup.key);
78 		string dir = format!"/sys/fs/cgroup/%s/%s"(cGroup.key, config.hostname);
79 		mkdir(dir); // FIXME , S_IRUSR | S_IWUSR | S_IXUSR);
80 
81 		foreach(cGroupSetting; cGroup.value)
82 		{
83 			auto path = format!"%s/%s"(dir,cGroupSetting.name);
84 			auto fd = fdopen(path,O_WRONLY);
85 			enforce(fd !=-1, format!"opening %s failed"(path));
86 			{
87 				scope(exit) close(fd);
88 				auto result = write(fd, cGroupSetting.value.toStringz,cGroupSetting.value.length);
89 				enforce(result != -1,format!"writing to %s failed"(path));
90 			}
91 		}
92 	}
93 	version(Trace) stderr.writeln("done.");
94 	version(Trace) stderr.writeln("=> setting rlimit...");
95 	rlimit lim = {
96 		rlim_max: config.rlimitMax,
97 		rlim_cur: config.rlimitCur,
98 	};
99 	enforce(!setrlimit(RLIMIT_NOFILE, &lim), format!"failed");
100 	version(Trace) stderr.writeln("done");
101 }
102 
103 void freeCGroups(in ChildConfig config)
104 {
105 	import std.exception : enforce;
106 	import std..string : fromStringz, toStringz;
107 	import std.stdio : stderr,writeln,writefln;
108 	import std.format : format;
109 	import core.sys.posix.unistd : write, close;
110 	import core.sys.posix.fcntl: open, O_WRONLY;
111 	import std.file: rmdir;
112 	version(Trace) stderr.writeln("=> cleaning cgroups...");
113 	foreach(cGroup; config.cGroups.byKeyValue)
114 	{
115 		int task_fd = 0;
116 		string dir = format!"/sys/fs/cgroup/%s/%s"(cGroup.key,config.hostname);
117 		string task = format!"/sys/fs/cgroup/%s/tasks"(cGroup.key);
118 		task_fd = open(task.toStringz, O_WRONLY);
119 		enforce(task_fd !=-1, format!"opening %s failed:"(task));
120 		{
121 			scope(exit)
122 				close(task_fd);
123 			auto result = write(task_fd, "0".ptr, 2);
124 			enforce(result !=-1, format!"writing to %s failed"(task));
125 		}
126 		rmdir(dir);
127 	}
128 	version(Trace) stderr.writeln("freeResources done");
129 }