#Make the following files:
Note: depending on your system you may need to modify the following variables SYSTEMD_LIB_DIR
and GROUP_DIR
bad-cgroup-demo.service
[Unit]
Description=Systemd bad cgroup demo
[Service]
Type=forking
ExecStart=/tmp/systemd-demo-unit
StandardOutput=journal
Delegate=false
[Install]
WantedBy=multi-user.target
Alias=bad-cgroup-demo.service
good-cgroup-demo.service
[Unit]
Description=Systemd good cgroup demo
[Service]
Type=forking
ExecStart=/tmp/systemd-demo-unit
StandardOutput=journal
Delegate=true
[Install]
WantedBy=multi-user.target
Alias=good-cgroup-demo.service
systemd-demo-unit.cc
#include <fstream>
#include <unordered_set>
#include <sys/stat.h>
#include <unistd.h>
using std::string;
using std::ofstream;
using std::ifstream;
using std::unordered_set;
const std::string GROUP_DIR = "/sys/fs/cgroup/";
const std::string SUBSYSTEM = "memory";
const std::string PROC_NAME = "systemd-demo-unit";
const std::string PROC_PATH = GROUP_DIR + SUBSYSTEM + "/" + PROC_NAME;
const std::string TASKS_PATH = PROC_PATH + "/tasks";
void force_proc_dir()
{
struct stat st;
if (stat(PROC_PATH.c_str(), &st) == 0) {
if(!(st.st_mode & S_IFDIR)) { exit(EXIT_FAILURE); }
// If we get here the directory already exists.
} else {
if (mkdir(PROC_PATH.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) { exit(EXIT_FAILURE); }
}
}
void add_task(pid_t pid)
{
ofstream out(TASKS_PATH.c_str());
if (!out.is_open()) { exit(EXIT_FAILURE); }
out << pid;
if (out.fail()) { exit(EXIT_FAILURE); }
out.close();
}
unordered_set<pid_t> get_tasks()
{
unordered_set<pid_t> result;
ifstream in(TASKS_PATH.c_str());
while (in.is_open() && !in.bad() && !in.eof() && !in.fail()) {
pid_t pid;
in >> pid;
result.emplace(pid);
}
in.close();
return result;
}
int main()
{
pid_t pid = fork();
if (pid < 0) {
// Bail on failed fork.
exit(EXIT_FAILURE);
}
if (pid == 0) {
// Child.
sleep(3);
auto tasks = get_tasks();
for (const pid_t pid : tasks) {
printf("Child task view = [%d]\n", pid);
}
printf("Reloading daemon\n");
system("systemctl daemon-reload");
printf("Restarting syslog\n");
system("systemctl restart rsyslog.service");
sleep(3);
tasks = get_tasks();
for (const pid_t pid : tasks) {
printf("Child task view = [%d]\n", pid);
}
return 0;
} else {
// Parent.
// Make sure the cgroup dir exists.
force_proc_dir();
sleep(1);
// Write the child pid to the cgroup tasks.
printf("Adding child task [%d] to tasks\n", pid);
add_task(pid);
auto tasks = get_tasks();
for (const pid_t pid : tasks) {
printf("Parent task view = [%d]\n", pid);
}
printf("Parent exiting\n");
}
return 0;
}
cgroup-demo.sh
#!/usr/bin/env bash
SYSTEMD_LIB_DIR=/lib/systemd/system/
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
cp good-cgroup-demo.service $SYSTEMD_LIB_DIR
cp bad-cgroup-demo.service $SYSTEMD_LIB_DIR
systemctl daemon-reload
echo "Running Bad Cgroup Demo:"
systemctl start bad-cgroup-demo.service
sleep 10
journalctl -u bad-cgroup-demo.service -n9
echo "Running Good Cgroup Demo:";
systemctl start good-cgroup-demo.service
sleep 10
journalctl -u good-cgroup-demo.service -n9
echo "Cleaning up..."
rm "$SYSTEMD_LIB_DIR""good-cgroup-demo.service"
rm "$SYSTEMD_LIB_DIR""bad-cgroup-demo.service"
echo "Finished"
#Run the following commands:
// Allow the script to be executed.
chmod +x cgroup-demo.sh
// Compile the demo binary.
clang++-3.6 -std=c++11 systemd-demo-unit.cc -o systemd-demo-unit
// Copy the binary to /tmp
cp systemd-demo-unit /tmp/
// Run the script as ROOT
./cgroup-demo.sh
###You should see output similar to this:
Running Bad Cgroup Demo:
-- Logs begin at ***, end at ***. --
DDD 12:51:53 XXX systemd[1]: Starting Systemd bad cgroup demo...
DDD 12:51:54 XXX systemd-demo-unit[13824]: Adding child task [13825] to tasks
DDD 12:51:54 XXX systemd-demo-unit[13824]: Parent task view = [13825]
DDD 12:51:54 XXX systemd-demo-unit[13824]: Parent exiting
DDD 12:51:54 XXX systemd[1]: Started Systemd bad cgroup demo.
DDD 12:51:59 XXX systemd-demo-unit[13824]: Child task view = [13825]
DDD 12:51:59 XXX systemd-demo-unit[13824]: Reloading daemon
DDD 12:51:59 XXX systemd-demo-unit[13824]: Restarting syslog
DDD 12:51:59 XXX systemd-demo-unit[13824]: Child task view = [0]
Running Good Cgroup Demo:
-- Logs begin at *** , end at ***. --
DDD 12:52:04 XXX systemd[1]: Starting Systemd good cgroup demo...
DDD 12:52:05 XXX systemd-demo-unit[13858]: Adding child task [13859] to tasks
DDD 12:52:05 XXX systemd-demo-unit[13858]: Parent task view = [13859]
DDD 12:52:05 XXX systemd-demo-unit[13858]: Parent exiting
DDD 12:52:05 XXX systemd[1]: Started Systemd good cgroup demo.
DDD 12:52:10 XXX systemd-demo-unit[13858]: Child task view = [13859]
DDD 12:52:10 XXX systemd-demo-unit[13858]: Reloading daemon
DDD 12:52:10 XXX systemd-demo-unit[13858]: Restarting syslog
DDD 12:52:10 XXX systemd-demo-unit[13858]: Child task view = [13859]
Cleaning up...
Finished
Notice that when the Delegate
is set to false
, the child task gets removed from the cgroup.