ebash

enhanced bash

Home Table of Contents GitHub

Module cgroup

Cgroups are a capability of the linux kernel designed for categorizing processes. They’re most typically used in ways that not only categorize processes, but also control them in some fasion. A popular reason is to limit the amount of resources a particular process can use.

Within each of many different subsystems that are set up by code in the kernel, a process may exist at one point in a hierarchy. That is, within the CPU subsystem, a process may only be owned by a single cgroup. And in the memory subsystem, it may be owned by a different cgroup. For the purposes of THIS ebash code, though, we duplicate a similar tree of groups within all of the subsystems that we interact with.

CGROUP_SUBSYSTEMS defines which subsystems those are. So when you use these functions, the hierarchy that you create is created in parallel under all of the subsystems defined by CGROUP_SUBSYSTEMS

Positions within the cgroup hierarchy created here are identified by names that look like relative directories. This is no accident – cgroups are represented to the kernel by a directory structure created within a filesystem of type cgroups.

Hopefully these functions make accessing the cgroups filesystem a little bit easier, and also help you to keep parallel hierarchies identical across the various cgroups subsystems.

NOTE: On Docker, The cgroups functions work when run within docker containers, operating on a cgroup inside the one that docker set up for them. This requires said containers to be started with –privileged or suitable other capabilities (which I have not investigated – it could be done, though)

func cgroup_create

Prior to using a cgroup, you must create it. It is safe to attempt to “create” a cgroup that already exists.

func cgroup_current

Display the name of the cgroup that the specified process is in. Defaults to the current process (i.e. ${BASHPID}).

ARGUMENTS

   pid
         Process whose cgroup should be listed. Default is the current process.

func cgroup_destroy

If you want to get rid of a cgroup, you can do so by calling cgroup_destroy.

NOTE:: It is an error to try to destroy a cgroup that contains any processes or any child cgroups. You can use cgroup_kill_and_wait to ensure that they are if you like.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --recursive, -r
         Destroy cgroup's children recursively

func cgroup_empty

cgroup_empty is a simple wrapper around cgroup_pids. It simply checks if all the provided cgroups are empty or not. Which means that there are no pids running in the provided cgroups.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --exclude, -x <value>
         Space separated list of pids not to return. By default returns all.

   --recursive, -r
         Additionally return pids for processes of this cgroup's children.


ARGUMENTS

   cgroups
         Cgroups whose processes should be listed.

func cgroup_exists

Returns true if all specified cgroups exist. In other words, they have been created via cgroup_create but have not yet been removed with cgroup_destroy)

func cgroup_find_setting_file

Find the full path to a cgroup setting file.

ARGUMENTS

   cgroup
        cgroup

   setting
        setting

func cgroup_get

Read the existing value of a subsystem-specific cgroups setting for the specified cgroup. See cgroup_set for more info

ARGUMENTS

   cgroup
         Name of the cgroup (e.g distbox/dtest or usa/colorado)

   setting
         Name of the subsystem-specific setting e.g. memory.kmem.limit_in.bytes)

func cgroup_kill

Recursively KILL (or send a signal to) all of the pids that live underneath all of the specified cgroups (and their children!). Accepts any number of cgroups.

NOTE: $$ and $BASHPID are always added to this list so as to not kill the calling process

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --exclude, -x <value>
         Space separated list of processes not to kill. Note: current process and ancestors are
         always excluded.

   --signal, -s <value>
         The signal to send to processs in the specified cgroup


ARGUMENTS

   cgroups
         Cgroups whose processes should be signalled.

func cgroup_kill_and_wait

Ensure that no processes are running all of the specified cgroups by killing all of them and waiting until the group is empty.

NOTE: This probably won’t work well if your script is already in that cgroup.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --exclude, -x <value>
         Space-separated list of processes not to kill. Current process and ancestors are always
         excluded.

   --signal, -s <value>
         Signal to send to processes in the cgroup

   --timeout, --max, -t <value>
         Maximum number of seconds to wait for all processes to die. If some still exist at
         that point, an error code will be returned. WARNING: The default of 0 will cause this
         function to wait forever.


ARGUMENTS

   cgroups
         Cgroups whose processes should be signalled and waited upon

func cgroup_move

Move one or more processes to a specific cgroup. Once added, all (future) children of that process will also automatically go into that cgroup.

It’s worth noting that all pids live in exactly one place in each cgroup subsystem. By default, processes are started in the cgroup of their parent (which by default is the root of the cgroup hierarchy). If you’d like to remove a process from your cgroup, you should simply move it up to that root (i.e. cgroup_move “/” $pid)

ARGUMENTS

   cgroup
         Name of a cgroup which should already have been created.

   pids
         IDs of processes to move. Empty strings are allowed and ignored.

func cgroup_pids

Recursively find all of the pids that live underneath a set of sections in the cgorups hierarchy. You may specify as many different cgroups as you like, and the processes in those cgroups AND THEIR CHILDREN will be echoed to stdout.

Cgroup_pids will return success as long as all of the specified cgroups exist, and failure if they do not (but it will still echo pids for any cgroups that do exist). On failure, it returns the number of specified cgroups that did not exist.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --exclude, -x <value>
         Space separated list of pids not to return. By default returns all.

   --recursive, -r
         Additionally return pids for processes of this cgroup's children.


ARGUMENTS

   cgroups
         Cgroups whose processes should be listed.

func cgroup_ps

Run ps on all of the processes in a cgroup.

OPTIONS
(*) Denotes required options
(&) Denotes options which can be given multiple times

   --exclude, -x <value>
         Space separated list of pids not to display.

   --recursive, -r
         List processes for specified cgroup and all children.


ARGUMENTS

   cgroup
         Name of cgroup to examine.

func cgroup_pstree

Display a graphical representation of all cgroups descended from those specified as arguments.

func cgroup_set

Change the value of a cgroups subsystem setting for the specified cgroup. For instance, by using the memory subsystem, you could limit the amount of memory used by all pids underneath the distbox hierarchy like this:

cgroup_set distbox memory.kmem.limit_in.bytes $((4*1024*1024*1024))
ARGUMENTS

   cgroup
         Name of the cgroup (e.g. distbox/distcc or fruit/apple or fruit)

   setting
         Name of the subsystem-specific setting

   value
         Value that should be assined to that subsystem-specific setting

func cgroup_supported

Detect whether the machine currently running this code is built with kernel support for all of the cgroups subsystems that ebash depends on.

func cgroup_tree

Return all items in the cgroup hierarchy. By default this will echo to stdout all directories in the cgroup hierarchy. You may optionally specify one or more cgroups and then only those cgroups descended from them it will be returned.

For example, if you’ve run this cgroup_create command:

cgroup_create a/{1,2,3} b/{10,20} c

cgroup_tree will produce output as follows:

$ cgroup_tree
a/1 a/2 a/3 b/10 b/20 c

$ cgroup_tree a
a/1 a/2 a/3

$ cgroup_tree b c
b/10 b/20 c
ARGUMENTS

   cgroups
        @cgroups