chiark / gitweb /
util: place a couple of _likely_ around cache TLS vars
[elogind.git] / src / cgroup-util.c
index 6abb6b5..fd0ac98 100644 (file)
@@ -166,12 +166,12 @@ int cg_rmdir(const char *controller, const char *path) {
         return r < 0 ? -errno : 0;
 }
 
-int cg_kill(const char *controller, const char *path, int sig, bool ignore_self) {
+int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
         bool done = false;
-        Set *s;
         int r, ret = 0;
         pid_t my_pid;
         FILE *f = NULL;
+        Set *allocated_set = NULL;
 
         assert(controller);
         assert(path);
@@ -181,13 +181,14 @@ int cg_kill(const char *controller, const char *path, int sig, bool ignore_self)
          * is repeated until no further processes are added to the
          * tasks list, to properly handle forking processes */
 
-        if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
-                return -ENOMEM;
+        if (!s)
+                if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
 
         my_pid = getpid();
 
         do {
-                pid_t pid;
+                pid_t pid = 0;
                 done = true;
 
                 if ((r = cg_enumerate_processes(controller, path, &f)) < 0) {
@@ -210,8 +211,13 @@ int cg_kill(const char *controller, const char *path, int sig, bool ignore_self)
                         if (kill(pid, sig) < 0) {
                                 if (ret >= 0 && errno != ESRCH)
                                         ret = -errno;
-                        } else if (ret == 0)
+                        } else if (ret == 0) {
+
+                                if (sigcont)
+                                        kill(pid, SIGCONT);
+
                                 ret = 1;
+                        }
 
                         done = false;
 
@@ -240,7 +246,8 @@ int cg_kill(const char *controller, const char *path, int sig, bool ignore_self)
         } while (!done);
 
 finish:
-        set_free(s);
+        if (allocated_set)
+                set_free(allocated_set);
 
         if (f)
                 fclose(f);
@@ -248,16 +255,21 @@ finish:
         return ret;
 }
 
-int cg_kill_recursive(const char *controller, const char *path, int sig, bool ignore_self, bool rem) {
+int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
         int r, ret = 0;
         DIR *d = NULL;
         char *fn;
+        Set *allocated_set = NULL;
 
         assert(path);
         assert(controller);
         assert(sig >= 0);
 
-        ret = cg_kill(controller, path, sig, ignore_self);
+        if (!s)
+                if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
+                        return -ENOMEM;
+
+        ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
 
         if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) {
                 if (ret >= 0 && r != -ENOENT)
@@ -279,7 +291,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool ig
                         goto finish;
                 }
 
-                r = cg_kill_recursive(controller, p, sig, ignore_self, rem);
+                r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
                 free(p);
 
                 if (r != 0 && ret >= 0)
@@ -291,7 +303,9 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool ig
 
         if (rem)
                 if ((r = cg_rmdir(controller, path)) < 0) {
-                        if (ret >= 0 && r != -ENOENT)
+                        if (ret >= 0 &&
+                            r != -ENOENT &&
+                            r != -EBUSY)
                                 ret = r;
                 }
 
@@ -299,6 +313,9 @@ finish:
         if (d)
                 closedir(d);
 
+        if (allocated_set)
+                set_free(allocated_set);
+
         return ret;
 }
 
@@ -309,24 +326,25 @@ int cg_kill_recursive_and_wait(const char *controller, const char *path, bool re
         assert(controller);
 
         /* This safely kills all processes; first it sends a SIGTERM,
-         * then checks 8 times after 50ms whether the group is
-         * now empty, and finally kills everything that is left with
-         * SIGKILL */
+         * then checks 8 times after 200ms whether the group is now
+         * empty, then kills everything that is left with SIGKILL and
+         * finally checks 5 times after 200ms each whether the group
+         * is finally empty. */
 
-        for (i = 0; i < 10; i++) {
+        for (i = 0; i < 15; i++) {
                 int sig, r;
 
                 if (i <= 0)
                         sig = SIGTERM;
-                else if (i >= 9)
+                else if (i == 9)
                         sig = SIGKILL;
                 else
                         sig = 0;
 
-                if ((r = cg_kill_recursive(controller, path, sig, true, rem)) <= 0)
+                if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0)
                         return r;
 
-                usleep(50 * USEC_PER_MSEC);
+                usleep(200 * USEC_PER_MSEC);
         }
 
         return 0;
@@ -349,7 +367,7 @@ int cg_migrate(const char *controller, const char *from, const char *to, bool ig
         my_pid = getpid();
 
         do {
-                pid_t pid;
+                pid_t pid = 0;
                 done = true;
 
                 if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) {
@@ -449,7 +467,9 @@ int cg_migrate_recursive(const char *controller, const char *from, const char *t
 
         if (rem)
                 if ((r = cg_rmdir(controller, from)) < 0) {
-                        if (ret >= 0 && r != -ENOENT)
+                        if (ret >= 0 &&
+                            r != -ENOENT &&
+                            r != -EBUSY)
                                 ret = r;
                 }
 
@@ -462,12 +482,26 @@ finish:
 
 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
         const char *p;
-        char *mp;
-        int r;
+        char *t;
+        static __thread bool good = false;
 
         assert(controller);
         assert(fs);
 
+        if (_unlikely_(!good)) {
+                int r;
+
+                r = path_is_mount_point("/sys/fs/cgroup");
+                if (r <= 0)
+                        return r < 0 ? r : -ENOENT;
+
+                /* Cache this to save a few stat()s */
+                good = true;
+        }
+
+        if (isempty(controller))
+                return -EINVAL;
+
         /* This is a very minimal lookup from controller names to
          * paths. Since we have mounted most hierarchies ourselves
          * should be kinda safe, but eventually we might want to
@@ -481,29 +515,22 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
         else
                 p = controller;
 
-        if (asprintf(&mp, "/sys/fs/cgroup/%s", p) < 0)
-                return -ENOMEM;
-
-        if ((r = path_is_mount_point(mp)) <= 0) {
-                free(mp);
-                return r < 0 ? r : -ENOENT;
-        }
-
         if (path && suffix)
-                r = asprintf(fs, "%s/%s/%s", mp, path, suffix);
+                t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
         else if (path)
-                r = asprintf(fs, "%s/%s", mp, path);
+                t = join("/sys/fs/cgroup/", p, "/", path, NULL);
         else if (suffix)
-                r = asprintf(fs, "%s/%s", mp, suffix);
-        else {
-                path_kill_slashes(mp);
-                *fs = mp;
-                return 0;
-        }
+                t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
+        else
+                t = join("/sys/fs/cgroup/", p, NULL);
+
+        if (!t)
+                return -ENOMEM;
+
+        path_kill_slashes(t);
 
-        free(mp);
-        path_kill_slashes(*fs);
-        return r < 0 ? -ENOMEM : 0;
+        *fs = t;
+        return 0;
 }
 
 int cg_trim(const char *controller, const char *path, bool delete_root) {
@@ -767,9 +794,9 @@ finish:
 }
 
 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
-        pid_t pid;
+        pid_t pid = 0;
         int r;
-        FILE *f;
+        FILE *f = NULL;
         bool found = false;
 
         assert(controller);
@@ -947,3 +974,31 @@ int cg_fix_path(const char *path, char **result) {
 
         return r;
 }
+
+int cg_get_user_path(char **path) {
+        char *root, *p;
+
+        assert(path);
+
+        /* Figure out the place to put user cgroups below. We use the
+         * same as PID 1 has but with the "/system" suffix replaced by
+         * "/user" */
+
+        if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
+                p = strdup("/user");
+        else {
+                if (endswith(root, "/system"))
+                        root[strlen(root) - 7] = 0;
+                else if (streq(root, "/"))
+                        root[0] = 0;
+
+                p = strappend(root, "/user");
+                free(root);
+        }
+
+        if (!p)
+                return -ENOMEM;
+
+        *path = p;
+        return 0;
+}