Add support for the memsw limits that limit memory+swap
[compctl.git] / cgroup.c
blob882fa6ad57b9b7e8f8c766fb9bb54d2a36571c0c
1 #include <limits.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/mount.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
9 #include "cgroup.h"
10 #include "common.h"
12 #if SWAP_LIMIT
13 #define MEMSW ".memsw"
14 #else
15 #define MEMSW
16 #endif
18 void (*cgroup_perror)(const char *s) = perror;
19 static const char cgroupfs[] = "/sys/fs/cgroup/";
21 int
22 cgroup_setup(const char *chier, const char *controllers)
24 char chierdir[PATH_MAX];
25 snprintf(chierdir, sizeof(chierdir), "%s%s", cgroupfs, chier);
26 if (access(chierdir, F_OK) >= 0)
27 return 0;
29 if (mount("none", cgroupfs, "tmpfs", 0, NULL) < 0) {
30 cgroup_perror(cgroupfs);
31 return -1;
33 if (mkdir(chierdir, 0777) < 0) {
34 cgroup_perror(chierdir);
35 return -1;
37 if (mount("none", chierdir, "cgroup", 0, controllers) < 0) {
38 cgroup_perror(chierdir);
39 return -1;
41 return 1;
44 int
45 cgroup_create(const char *chier, const char *cgroup)
47 char cgroupdir[PATH_MAX];
48 snprintf(cgroupdir, sizeof(cgroupdir), "%s%s/%s", cgroupfs, chier, cgroup);
49 if (access(cgroupdir, F_OK) >= 0)
50 return 0;
51 if (mkdir(cgroupdir, 0777) < 0) {
52 cgroup_perror(cgroupdir);
53 return -1;
55 return 1;
59 int
60 cgroup_add_task(const char *chier, const char *cgroup, pid_t pid)
62 char tasksfile[PATH_MAX];
63 snprintf(tasksfile, sizeof(tasksfile), "%s%s/%s/tasks", cgroupfs, chier, cgroup);
64 FILE *tasks = fopen(tasksfile, "a");
65 if (!tasks) {
66 cgroup_perror(tasksfile);
67 return -1;
69 fprintf(tasks, "%d\n", pid);
70 fclose(tasks);
71 return 1;
74 int
75 cgroup_is_task_in_cgroup(const char *chier, const char *cgroup, pid_t pid)
77 char tasksfile[PATH_MAX];
78 snprintf(tasksfile, sizeof(tasksfile), "%s%s/%s/tasks", cgroupfs, chier, cgroup);
79 FILE *tasks = fopen(tasksfile, "r");
80 if (!tasks) {
81 cgroup_perror(tasksfile);
82 return -1;
85 bool exists = false;
86 char line[128];
87 while (fgets(line, sizeof(line), tasks)) {
88 if (atoi(line) == pid) {
89 exists = true;
90 break;
93 fclose(tasks);
94 return exists;
97 int
98 cgroup_task_list(const char *chier, const char *cgroup, pid_t **tasklist)
100 char tasksfile[PATH_MAX];
101 snprintf(tasksfile, sizeof(tasksfile), "%s%s/%s/tasks", cgroupfs, chier, cgroup);
102 FILE *tasks = fopen(tasksfile, "r");
103 if (!tasks) {
104 cgroup_perror(tasksfile);
105 return -1;
108 int ntasks = 0;
109 *tasklist = NULL;
110 char line[128];
111 while (fgets(line, sizeof(line), tasks)) {
112 if (!(ntasks % 32))
113 *tasklist = realloc(*tasklist, (ntasks + 32) * sizeof(*tasklist));
114 (*tasklist)[ntasks++] = atoi(line);
116 fclose(tasks);
117 return ntasks;
121 size_t
122 cgroup_get_mem_limit(const char *chier, const char *cgroup)
124 char limitfile[PATH_MAX];
125 snprintf(limitfile, sizeof(limitfile), "%s%s/%s/memory"MEMSW".limit_in_bytes", cgroupfs, chier, cgroup);
126 FILE *limit = fopen(limitfile, "r");
127 if (!limit) {
128 cgroup_perror(limitfile);
129 return -1;
131 size_t nlimit = 0;
132 fscanf(limit, "%zu", &nlimit);
133 fclose(limit);
134 return nlimit;
138 cgroup_set_mem_limit_do(const char *chier, const char *cgroup, size_t nlimit, char *memsw)
140 char limitfile[PATH_MAX];
141 snprintf(limitfile, sizeof(limitfile), "%s%s/%s/memory%s.limit_in_bytes", cgroupfs, chier, cgroup, memsw);
142 FILE *limit = fopen(limitfile, "w");
143 if (!limit) {
144 cgroup_perror(limitfile);
145 return -1;
147 fprintf(limit, "%zu\n", nlimit);
148 fclose(limit);
149 return 1;
153 cgroup_set_mem_limit(const char *chier, const char *cgroup, size_t nlimit)
155 /* We need to set both the "normal" and memsw limits, normal first,
156 * since normal <= memsw must hold. */
157 int ret = cgroup_set_mem_limit_do(chier, cgroup, nlimit, "");
158 #if SWAP_LIMIT
159 if (ret >= 0)
160 ret |= cgroup_set_mem_limit_do(chier, cgroup, nlimit, MEMSW);
161 #endif
162 return ret;
165 size_t
166 cgroup_get_mem_usage(const char *chier, const char *cgroup)
168 char usagefile[PATH_MAX];
169 snprintf(usagefile, sizeof(usagefile), "%s%s/%s/memory"MEMSW".usage_in_bytes", cgroupfs, chier, cgroup);
170 FILE *usage = fopen(usagefile, "r");
171 if (!usage) {
172 cgroup_perror(usagefile);
173 return -1;
175 size_t nusage = 0;
176 fscanf(usage, "%zu", &nusage);
177 fclose(usage);
178 return nusage;