$ git diff 3ad849c5d6a24ef66152004eb3149d2cff973b1c..082c04e0a1c31115417af9fd348ae83ee8ecc397 --stat sh/init.sh.Linux.in | 10 +++++++++ sh/runscript.sh.in | 54 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-)

+# Setup Kernel Support for CGroups +if grep -qs cgroup /proc/filesystems; then + ebegin "Mounting CGroup filesystem" + mkdir -p /dev/cgroup + mount -n -t cgroup -o nodev,noexec,nosuid \ + OpenRC-CGroup /dev/cgroup + eend $? +fi

+# Attach to CGroup - dir existing is enough for us +if [ -d /dev/cgroup ]; then + # use the svcname unless overriden in conf.d + SVC_CGROUP=${CGROUP:-$RC_SVCNAME} + mkdir -p /dev/cgroup/${SVC_CGROUP} + # now attach self to cgroup - any children of this process will inherit this + echo $$ > /dev/cgroup/${SVC_CGROUP}/tasks + # TODO: set res limits from conf.d +fi

+# CGroup cleanup +if [ -d /dev/cgroup ]; then + # use the svcname unless overriden in conf.d + SVC_CGROUP=${CGROUP:-$RC_SVCNAME} + # reattach ourself to root cgroup + echo $$ > /dev/cgroup/tasks + # remove cgroup if empty, will fail if any task attached + rmdir /dev/cgroup/${SVC_CGROUP} 2>/dev/null +fi +# need to exit cleanly +exit 0

+# Kill everything in the CGroup with maximum prejudice until it is dead +# This is very naughty if multiple init scripts were to share a CGroup ... +terminate() +{ + if ! [ -d /dev/cgroup ]; then + return 0 + else + SVC_CGROUP=${CGROUP:-$RC_SVCNAME} + # we want to survive and thus must not be killed dead + echo $$ > /dev/cgroup/tasks + for signal in TERM KILL; do + for i in `cat /dev/cgroup/${SVC_CGROUP}/tasks`; do + kill -s $signal $i + done + done + fi + # if anyone survived here we could try task_freezer; SIGTERM; unfreeze + # to be sure everyone really got the message that they are dead +}

+ # cpuset support try 1 + if [ -v CGROUP_CPUS ] && [ -e /dev/cgroup/${SVC_CGROUP}/cpuset.cpus ]; then + echo $CGROUP_CPUS > /dev/cgroup/${SVC_CGROUP}/cpuset.cpus + fi

During a train ride I spent some time implementing a prototype for CGroups support for OpenRC - the big awesome feature for SysTemD that people seem to desire the most.Here's the most amusing bit:So I've managed to stay below my initial estimate of "under 100 lines of shell" - I don't quite get what the big deal is. Of course the initial patch is a bit rough, there are some things that just don't feel clean to me - but it works.To explain the patch a bit - sh/init.sh.Linux.in:We need to mount a CGroup pseudofilesystem somewhere, I figured out that we better do it as early as possible (although procfs and sysfs init scripts aren't wrong per se). So we mount a cgroupfs named "OpenRC-CGroup" - that's just a nice marker so you see who did it. So much for setup.Now when a service starts we just need to take the parent process (which is conveniently the runscript.sh process that runs the init script) and push it into its own group. Although, maybe, it makes sense to let some init scripts be in the same group, right?Look, ma, no hands!We allow users to set CGROUP in conf.d files, but if it's not set we just use RC_SVCNAME, which is the name of the init script usually. Then we create a subdirectory (but we don't care if it already exists) and throw ourselves into it.Tadaah!There's one little downside, we create directories but don't remove them. So let's add a little cleanup at the end of runscript.sh:The exit 0 is a bit naughty, but I think it's the right way to terminate. Otherwise the rmdir might give us a bad return value which makes it look like things fail even when they don't ...There's a neat trick in it - we are still in that cgroup, so we take ourselves and move us back to the root cgroup - otherwise the cgroup will never be empty. Duh! :)And here's a more, let's say, controversial part. It's a bit exquisitely rude, so I guess this will have to be adapted for public use - but it works too well. See, there's this leeeetle problem that OpenRC tends to not kill processes that well. So if, for example, the apache init script doesn't manage to kill all indians you may have a problem - for example re-starting might fail because there's still the last mohican protecting port 80.Since we know that the processes end up in a specific cgroup we can just take all those, put them against the wall and shoot them dead. This has some potential side-effects, for example if there's multiple init scripts using one cgroup or if there's a service where it's expected that a process survives (although that's funkay). Anyway ...This works well even for uncooperative init scripts, but might not always be what you want. But at least it kills everyone dead :)And there's some funky resource limits possible - I'm still trying to figure out how to make use of them properly, but ...... this nails everything from one init script to a cpuset, so you can hammer apache onto CPUs 1-7 and leave CPU 0 free for "everything else", if you want. It also allows memory limits and a few other advanced gadgets, but I haven't played with that yet.And so in one afternoon we managed to grow a pretty decent bonus feature ..