The following scenario:
process_1.bin starts doSomeThing.sh
doSomeThing.sh should kill process_1.bin first but keep running itself and do some other things
I have tried fork, exec, screen, p_threads, daemon, and some without success.
Every time the doSomeThing.sh starts and kills the process_1.bin, it kills itself because the parent process is killed.
doSomeThing.sh tells me: "leaving program after kill signal!"
Unfortunately, this does not work either:
pid_t pid;
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0) // Success: Let the parent terminate
exit(EXIT_SUCCESS);
if (setsid() < 0)
exit(EXIT_FAILURE);
pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
if (pid > 0)
exit(EXIT_SUCCESS);
// umask(0);
// chdir("/");
switch(pid)
{
case -1: // Fork() has failed
perror ("fork");
break;
case 0: // This is processed by the child
// deamon(0,0);
system("/root/doSomeThing.sh");
// system("screen -dmS doSomeThing /root/doSomething.sh")
// char *name[] = {
// "/bin/bash",
// "-c",
// "/root/doSomeThing.sh",
// NULL
// };
// if(execvp(name[0], name) < 0)
// perror("execvp");
exit(0);
break;
default: // This is processed by the parrent
break;
}
How can I direct the doSomeThing.sh to kill the process_1.bin but still stay alive itself?
Apart from ignoring SIGTERM as suggested by Jonathan Leffler, you could make the child process a daemon so that its life will become independant of the life of its parent. Linux has a command to start a process as a daemon daemonize or a library function for a program willing to detach from its parent and its controlling terminal daemon.
Your child process should not be dying. Here's a pair of shell scripts simulating what you describe.
process1.bin
#!/bin/sh
echo "$0: at work"
trap 'echo "$0: Death threat received"; exit 1' 1 2 3 13 15
sh doSomething.sh &
echo "$0: so far, so good"
wait
echo "$0: it's sad when all your children die"
ps -f
echo "$0: exiting normally"
exit 0
doSomething.sh
#!/bin/sh
#
# Commit parenticide and continue, preferably without dying.
#PPID=$(ps -fp$$ | colnum -c 3)
echo "Before"
ps -f
(
set -x
kill $PPID
)
sleep 1
echo ""
echo "After"
ps -f
sleep 5
echo "$0: Goodbye, Cruel World!"
One time when I ran it, I got the output:
$ ./process1.bin
./process1.bin: at work
./process1.bin: so far, so good
Before
UID PID PPID C STIME TTY TIME CMD
501 649 641 0 9:58AM ttys000 0:00.14 -bash
501 29760 649 0 8:47AM ttys000 0:00.01 sh
501 29793 29760 0 8:47AM ttys000 0:00.01 /bin/sh ./process1.bin
501 29794 29793 0 8:47AM ttys000 0:00.01 sh doSomething.sh
501 661 657 0 9:58AM ttys001 0:00.05 -bash
501 693 688 0 9:58AM ttys002 0:00.05 -bash
501 738 731 0 9:58AM ttys007 0:00.31 -bash
501 769 766 0 9:58AM ttys008 0:00.05 -bash
501 848 847 0 9:58AM ttys009 0:00.05 -bash
501 884 881 0 9:58AM ttys010 0:00.12 -bash
501 946 920 0 9:58AM ttys011 0:00.15 -bash
+ kill 29793
./process1.bin: Death threat received
$
After
UID PID PPID C STIME TTY TIME CMD
501 649 641 0 9:58AM ttys000 0:00.14 -bash
501 29760 649 0 8:47AM ttys000 0:00.01 sh
501 29794 1 0 8:47AM ttys000 0:00.01 sh doSomething.sh
501 661 657 0 9:58AM ttys001 0:00.05 -bash
501 693 688 0 9:58AM ttys002 0:00.05 -bash
501 738 731 0 9:58AM ttys007 0:00.31 -bash
501 769 766 0 9:58AM ttys008 0:00.05 -bash
501 848 847 0 9:58AM ttys009 0:00.05 -bash
501 884 881 0 9:58AM ttys010 0:00.12 -bash
501 946 920 0 9:58AM ttys011 0:00.15 -bash
doSomething.sh: Goodbye, Cruel World!
$
Note that my $ prompt appears after 'Death threat received'. The following output is from doSomething; I hit return after 'Goodbye, Cruel World!' to get the final $ prompt.
Testing with Bash on a MacBook Pro running macOS Catalina 10.15.7.
In a comment, oemer_1907 says:
The shell script kills all processes to play the update (including the C update process). Once the C update process is killed by the shell update process, it sends a SIGTERM to all its children. Hence, the shell script is also killed. If instead it just calculates without killing its parent, then it just keeps running until the end.
Well, if the parent process sends SIGTERM to all its children, your child script, doSomething.sh, must ignore the SIGTERM signal using either of these:
trap "" 15
trap "" TERM
before it sends a signal to its parent. Or the parent process could arrange not to send the signal to this child. Or it could arrange for the child to ignore SIGTERM before it is executed:
signal(SIGTERM, SIG_IGN);
…exec child…
Or …
Related
I want to create 5 processes just like the picture shown i have tried a lil bit by printing out their pid's but its hard for me to visualize the fork() creating them and get exactly what I want [The image shows 5 processes connected by pipes]
P
/ \
M M
| |
C C
When you use fork() the kernel will create one new process and will return to the child (the new process) 0 and the PID to the parent. So, knowing this this is the following code to create the tree
if ((pid = fork()) == 0) {
//I am process M1
if (pid = form()) == 0) {
//I am process C1
}
} else {
// I am still in P, so go on the next branch
if ((pid = fork()) == 0) {
//I am process M2
if (pid = form()) == 0) {
//I am process C2
}
}
}
Use ps --forest to visualize the process tree as in following example
~# ps --forest
PID TTY TIME CMD
1295 pts/0 00:00:00 sudo
1296 pts/0 00:00:00 \_ su
1297 pts/0 00:00:01 \_ bash
3541 pts/0 00:00:00 \_ ps
So you will see something like:
~# ps --forest
PID TTY TIME CMD
1295 pts/0 00:00:00 a.out
1296 pts/0 00:00:00 \_ a.out
1297 pts/0 00:00:00 \_ a.out
1298 pts/0 00:00:00 \_ a.out
1299 pts/0 00:00:00 \_ a.out
Which will tell you if you have successfully made the tree.
When I run the following code and then run ps to see the processes running, I only get 4 ./a.out running processes even though there are 5 forks. Why is that? How am I able to see the other fork? Also, if multiple people are using my computer, running the same process a.out, how can I terminate only my processes, using only linux commands? Please help.
PID TTY TIME CMD
32941 ttys000 0:00.10 -bash
34098 ttys000 0:00.08 less
33651 ttys000 0:00.00 ./a.out
33652 ttys000 0:00.00 ./a.out
33654 ttys000 0:00.00 ./a.out
33655 ttys000 0:00.00 ./a.out
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#define N 5 /* How many children to make. */
#define D 1200 /* Sleep 1200 seconds = 20 minutes */
int main(void)
{
int i;
pid_t p;
for (i = 0; i < N; i++) {
p = fork();
if (p == 0) {
close(0);
close(1);
close(2);
if (i == 2) {
setsid();
}
sleep(D);
return 0;
}
}
return 0;
}
All five processes are running, but you're using the ps command that only shows processes associated with your session, but the setsid() called for i=2 sets a different session, so the default ps options won't show you.
$ ps
PID TTY TIME CMD
3048 pts/0 00:00:00 bash
8288 pts/0 00:00:00 a.out
8289 pts/0 00:00:00 a.out
8291 pts/0 00:00:00 a.out
8292 pts/0 00:00:00 a.out
8301 pts/0 00:00:00 ps
$ ps -fe | grep a.out
steve 8288 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8289 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8290 1 0 13:39 ? 00:00:00 ./a.out <-- missing one
steve 8291 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8292 1 0 13:39 pts/0 00:00:00 ./a.out
steve 8303 3048 0 13:40 pts/0 00:00:00 grep --color=auto a.out
$
By default, ps only displays processes with the same session id as itself and associated with a terminal. When you changed the session id of one of the processes, you disqualified it from being listed. ps x will include all of your processes.
By default, ps only lists the processes belong to you. You can be sure of this by using ps ux to include the owners of the processes in the output.
You can use the kill utility to kill these processes. Unless you are root, you can't kill other processes owned by others even if you tried.
I want to fork multiple processes and assign each child process it's own terminal window so that IPC can be demonstrated easily.
Forking goes on fine, and if I run the child processes on the same terminal it runs fine.
However to make each child process have its own terminal window, I do
execl("/usr/bin/xterm", "xterm", "-e", "yourprogram", NULL);
The program runs in a new window, but its PID is different from that shown by the parent which forks the process. What am I doing wrong?
Thanks
edit1 - this is my main function (the parent process). I fork 4 child processes. I want each child process to have its own terminal window. However the child process just exits, and a new process with a different PID continues to run in the new terminal.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
pid_t pid[4];
int i = 0;
int status;
//Fork four new processes
for(i=0; i<4; i++)
{
pid[i] = fork();
if(pid[i] == 0 && i == 0)
{
execl("/usr/bin/xterm", "xterm", "./child1", NULL);
exit(1);
}
else if(pid[i] == 0 && i == 1)
{
execl("/usr/bin/xterm", "xterm", "./child2", NULL);
exit(1);
}
else if(pid[i] == 0 && i == 2)
{
execl("/usr/bin/xterm", "xterm", "./child3", NULL);
exit(1);
}
else if(pid[i] == 0 && i == 3)
{
execl("/usr/bin/xterm", "xterm", "./child4", NULL);
exit(1);
}
else
{
//Parent process
printf("The main function has forked a process with pid: %d\n", pid[i]);
}
}
for(i=0;i<4;i++)
{
status = waitpid(pid[i], NULL, 0);
if(status == pid[i])
printf("%d: Process Terminated Successfully\n", pid[i]);
else
{
perror("waitpid");
exit(1);
}
}
return 1;
}
edit2 - added ps -u output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
dell-pc 3024 0.1 0.0 26872 5480 pts/0 Ss 16:54 0:00 bash
dell-pc 3038 0.0 0.0 4200 632 pts/0 S+ 16:54 0:00 ./main
dell-pc 3039 22.5 0.1 109240 11116 pts/0 S+ 16:54 0:01 xterm ./child1
dell-pc 3040 26.1 0.1 109240 11268 pts/0 R+ 16:54 0:02 xterm ./child2
dell-pc 3041 28.7 0.1 109240 11180 pts/0 S+ 16:54 0:02 xterm ./child3
dell-pc 3042 27.0 0.1 109240 11288 pts/0 S+ 16:54 0:02 xterm ./child4
dell-pc 3044 4.1 0.0 4200 648 pts/24 Ss+ 16:55 0:00 child3
dell-pc 3046 3.7 0.0 4200 680 pts/26 Ss+ 16:55 0:00 child4
dell-pc 3048 3.8 0.0 4200 792 pts/25 Ss+ 16:55 0:00 child2
dell-pc 3050 3.3 0.0 4200 660 pts/14 Ss+ 16:55 0:00 child1
dell-pc 3060 2.0 0.0 26816 5412 pts/27 Ss 16:55 0:00 bash
dell-pc 3072 0.0 0.0 22648 2688 pts/27 R+ 16:55 0:00 ps -u
edit3: added output of main:
The main function has forked a process with pid: 3491
The main function has forked a process with pid: 3492
The main function has forked a process with pid: 3493
The main function has forked a process with pid: 3494
3491: Process Terminated Successfully
3492: Process Terminated Successfully
3493: Process Terminated Successfully
3494: Process Terminated Successfully
I did a program like yours (naming it stackoverflow), executing vi in an xterm, and while it is running I open a third xterm to run ps -u. Output is:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
osboxes 1713 0.0 0.2 6588 4756 pts/0 Ss 18:56 0:00 bash
osboxes 1780 0.0 0.2 6508 4484 pts/1 Ss 19:12 0:00 bash
osboxes 1836 88.4 0.0 2020 532 pts/0 R+ 19:21 0:29 ./stackoverflow
osboxes 1837 0.1 0.4 12844 8952 pts/0 S+ 19:21 0:00 /usr/bin/xterm -e vi stackoverflow.txt
osboxes 1839 0.0 0.1 6072 3536 pts/2 Ss+ 19:21 0:00 vi stackoverflow.txt
osboxes 1840 0.0 0.1 4772 2452 pts/1 R+ 19:22 0:00 ps -u
Output of program is:
PID=1836
child PID=1837
So the child is still running xtermcommand. It created another child running vi (pid 1839).
IPC Demo and sample using terminal windows, under bash
Because it's easy under bash:
This will require simple terminal tools, like xterm. This was successfully tested with lxterm, mate-terminal, konsole and gnome-terminal. Of course, tmux and screen must be able too...
Ok, let's go. We assume you're already in some terminal window, we will name this initial console.
1. First opening a display window:
So, from the initial console, open log window:
exec 5> >(xterm -T 'Log window...' -e sh -c "cat /proc/$$/fd/5")
or
exec 5> >(xterm -e sh -c "printf '\\e];Log window...\\a';cat /proc/$$/fd/5")
exec 5> >(konsole --nofork -e sh -c "cat /proc/$$/fd/5")
exec 5> >(lxterm -T "Log window..." -e sh -c "cat /proc/$$/fd/5")
exec 5> >(mate-terminal -t 'Log window...' -x sh -c "cat /proc/$$/fd/5")
exec 5> >(gnome-terminal --window -x sh -c "printf '\\e];Log window...\\a';cat /proc/$$/fd/5")
Variant usefull for debugging
exec 5> >(xterm -e sh -c "printf '\\e];Log window...\\a';
tee </proc/$$/fd/5 /dev/tty | sed -u s/.*/now/|date -f -")
Will print date and time on each line output.
exec 5> >(xterm -e sh -c "printf '\\e];Log window...\\a';
tee </proc/$$/fd/5 /dev/tty | sed -u s/.*/now/|date -f - ; read foo")
Same, but will keep window open after closing from parent, waiting for terminal input (Return) before closing (or close by window manager).
2. Testing, then using this:
Always in initial console, hit:
echo >&5 This is a test string.
This must prompt in Log window.
Ok, now:
xterm -T 'Input window' -e bash --rcfile <(echo "exec 1>/proc/$$/fd/5") &
Note: There, double-quotes will ensure $$ will expand from initial window's shell level.
So now, you could enter command in Input window and read results on Log window.
3. Closing window
Window will close when file descriptor is closed:
exec 5>&-
Full script using 3 window
You may found full script there:
ipc_win-demo.sh.txt
ipc_win-demo.sh
For gnome terminal I used:
execl("/usr/bin/gnome-terminal", "gnome-terminal", "-q", "-e", "./my_binary", (char*)0);
In my project, I need a sub-task to play in parallel with a parent task. I use fork() to create a parallel process which is aplay xyz.wav. Now when I want to kill the child process from the parent process e.g system("kill -9 aplay ") the aplay is killed, but I see two instances of the parent task. I think one of them is a copy made by the call to fork() and the other one is the original. And with each fork() call, the number of copies increases. I am conscious about memory overflow. I just want to keep the original process. I have tried to kill that parent copy but failed!copies of the parent process appear as 'defunct'.
the 'defucnt' process continue to increase as i call parallel process, whether i kill aplay or not. I also tried to kill defunt by its PID, it also didn't work.
static int
test(Core *pc, char *args)
{
pid1=fork();
if (pid1 ==0)
{
system ("ps " );
system("aplay /opt/Line_Tone_14s.wav");
_exit(0);
}
else if(pid1<0)
{
out("fork() ERROR (-1) returned\n");
}
else if(pid1>0)
{
out("I AM IN PARENT PROCESS() NOW\n");
}
return 1;
}
static int
test1(Core *pc, char *args)
{
system ("ps " );
system ("killall -9 aplay ");
return 1;
}
Initially
> PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5738 pts/0 00:00:00 sh
5739 pts/0 00:00:00 ps
>test
> PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent
5740 pts/0 00:00:00 sh
5741 pts/0 00:00:00 aplay
5743 pts/0 00:00:00 sh
5744 pts/0 00:00:00 ps
>test1
>killed
after kill
>PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent <defunct>
5753 pts/0 00:00:00 sh
5754 pts/0 00:00:00 ps
>test
> PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent <defunct>
5759 pts/0 00:00:00 parent
5762 pts/0 00:00:00 sh
5763 pts/0 00:00:00 aplay
5765 pts/0 00:00:00 sh
5766 pts/0 00:00:00 ps
>test1
>killed
after kill
>PID TTY TIME CMD
1580 pts/0 00:00:00 sudo
1581 pts/0 00:00:00 su
1589 pts/0 00:00:00 bash
5732 pts/0 00:00:00 parent
5737 pts/0 00:00:00 parent <defunct>
5759 pts/0 00:00:00 parent <defunct>
5773 pts/0 00:00:00 sh
5774 pts/0 00:00:00 ps
i also tried with this in test() command
else if(pid1>0)
{
out("I AM IN PARENT PROCESS() NOW\n");
wait(&status);
}
by doing this only one parent process remain after aplay finishes to play sound, no matter how many times i call the "test" command. but the issue with this is that, I can not type any other command during sound play, until it finishes. so could not kill it in between playing the sound.
I want to play sound in parallel, and want to kill any time i want.
Don't kill it that way! You have the child PID in pid1, just use the kill() function to kill it.
Spawning an separate process to run killall is unnecessary, expensive and (as you've found out), not that reliable. What if there are five copies of that executable running?
You can use something like:
#include <sys/types.h>
#include <signal.h>
:
int rc = kill (pid1, 9); // or SIGKILL for portability, rather than 9.
// Check rc and errno.
in your parent.
I would also seriously look into removing the system calls in the child process as well since they start up separate processes. You can do better by using the exec family of calls the replace the program in the child's process space.
Is there a programmatic method to set CPU affinity for a process in c/c++ for the Linux operating system?
You need to use sched_setaffinity(2).
For example, to run on CPUs 0 and 2 only:
#define _GNU_SOURCE
#include <sched.h>
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
CPU_SET(2, &mask);
int result = sched_setaffinity(0, sizeof(mask), &mask);
(0 for the first parameter means the current process, supply a PID if it's some other process you want to control).
See also sched_getcpu(3).
Use sched_setaffinity at the process level, or pthread_attr_setaffinity_np for individual threads.
I have done many effort to realize what is happening so I add this answer for helping people like me(I use gcc compiler in linux mint)
#include <sched.h>
cpu_set_t mask;
inline void assignToThisCore(int core_id)
{
CPU_ZERO(&mask);
CPU_SET(core_id, &mask);
sched_setaffinity(0, sizeof(mask), &mask);
}
int main(){
//cal this:
assignToThisCore(2);//assign to core 0,1,2,...
return 0;
}
But don't forget to add this options to the compiler command : -D _GNU_SOURCE
Because operating system might assign a process to the particular core, you can add this GRUB_CMDLINE_LINUX_DEFAULT="quiet splash isolcpus=2,3" to the grub file located in /etc/default and the run sudo update-grub in terminal to reserve the cores you want
UPDATE:
If you want to assign more cores you can follow this piece of code:
inline void assignToThisCores(int core_id1, int core_id2)
{
CPU_ZERO(&mask1);
CPU_SET(core_id1, &mask1);
CPU_SET(core_id2, &mask1);
sched_setaffinity(0, sizeof(mask1), &mask1);
//__asm__ __volatile__ ( "vzeroupper" : : : ); // It is hear because of that bug which dirtied the AVX registers, so, if you rely on AVX uncomment it.
}
sched_setaffinity + sched_getaffinity minimal C runnable example
This example was extracted from my answer at: How to use sched_getaffinity and sched_setaffinity in Linux from C? I believe the questions are not duplicates since that one is a subset of this one, as it asks about sched_getaffinity only, and does not mention C++.
In this example, we get the affinity, modify it, and check if it has taken effect with sched_getcpu().
main.c
#define _GNU_SOURCE
#include <assert.h>
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void print_affinity() {
cpu_set_t mask;
long nproc, i;
if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_getaffinity");
assert(false);
}
nproc = sysconf(_SC_NPROCESSORS_ONLN);
printf("sched_getaffinity = ");
for (i = 0; i < nproc; i++) {
printf("%d ", CPU_ISSET(i, &mask));
}
printf("\n");
}
int main(void) {
cpu_set_t mask;
print_affinity();
printf("sched_getcpu = %d\n", sched_getcpu());
CPU_ZERO(&mask);
CPU_SET(0, &mask);
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
perror("sched_setaffinity");
assert(false);
}
print_affinity();
/* TODO is it guaranteed to have taken effect already? Always worked on my tests. */
printf("sched_getcpu = %d\n", sched_getcpu());
return EXIT_SUCCESS;
}
GitHub upstream.
Compile and run:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Sample output:
sched_getaffinity = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
sched_getcpu = 9
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 0
Which means that:
initially, all of my 16 cores were enabled, and the process was randomly running on core 9 (the 10th one)
after we set the affinity to only the first core, the process was moved necessarily to core 0 (the first one)
It is also fun to run this program through taskset:
taskset -c 1,3 ./a.out
Which gives output of form:
sched_getaffinity = 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 2
sched_getaffinity = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
sched_getcpu = 0
and so we see that it limited the affinity from the start.
This works because the affinity is inherited by child processes, which taskset is forking: How to prevent inheriting CPU affinity by child forked process?
Python: os.sched_getaffinity and os.sched_setaffinity
See: How to find out the number of CPUs using python
Tested in Ubuntu 16.04.
In short
unsigned long mask = 7; /* processors 0, 1, and 2 */
unsigned int len = sizeof(mask);
if (sched_setaffinity(0, len, &mask) < 0) {
perror("sched_setaffinity");
}
Look in CPU Affinity for more details
It is also possible to make it through the shell without any modification in the programs with the cgroups and the cpuset sub-system. Cgroups (v1 at least) are typically mounted on /sys/fs/cgroup under which the cpuset sub-system resides. For example:
$ ls -l /sys/fs/cgroup/
total 0
drwxr-xr-x 15 root root 380 nov. 22 20:00 ./
drwxr-xr-x 8 root root 0 nov. 22 20:00 ../
dr-xr-xr-x 2 root root 0 nov. 22 20:00 blkio/
[...]
lrwxrwxrwx 1 root root 11 nov. 22 20:00 cpuacct -> cpu,cpuacct/
dr-xr-xr-x 2 root root 0 nov. 22 20:00 cpuset/
dr-xr-xr-x 5 root root 0 nov. 22 20:00 devices/
dr-xr-xr-x 3 root root 0 nov. 22 20:00 freezer/
[...]
Under cpuset, the cpuset.cpus defines the range of CPUs on which the processes belonging to this cgroup are allowed to run. Here, at the top level, all the CPUs are configured for all the processes of the system. Here, the system has 8 CPUs:
$ cd /sys/fs/cgroup/cpuset
$ cat cpuset.cpus
0-7
The list of processes belonging to this cgroup is listed in the cgroup.procs file:
$ cat cgroup.procs
1
2
3
[...]
12364
12423
12424
12425
[...]
It is possible to create a child cgroup into which a subset of CPUs are allowed. For example, let's define a sub-cgroup with CPU cores 1 and 3:
$ pwd
/sys/fs/cgroup/cpuset
$ sudo mkdir subset1
$ cd subset1
$ pwd
/sys/fs/cgroup/cpuset/subset1
$ ls -l
total 0
-rw-r--r-- 1 root root 0 nov. 22 23:28 cgroup.clone_children
-rw-r--r-- 1 root root 0 nov. 22 23:28 cgroup.procs
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.cpu_exclusive
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.cpus
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.effective_cpus
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.effective_mems
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mem_exclusive
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mem_hardwall
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_migrate
-r--r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_pressure
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_spread_page
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.memory_spread_slab
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.mems
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.sched_load_balance
-rw-r--r-- 1 root root 0 nov. 22 23:28 cpuset.sched_relax_domain_level
-rw-r--r-- 1 root root 0 nov. 22 23:28 notify_on_release
-rw-r--r-- 1 root root 0 nov. 22 23:28 tasks
$ cat cpuset.cpus
$ sudo sh -c "echo 1,3 > cpuset.cpus"
$ cat cpuset.cpus
1,3
The cpuset.mems files must be filled before moving any process into this cgroup. Here we move the current shell into this new cgroup (we merely write the pid of the process to move into the cgroup.procs file):
$ cat cgroup.procs
$ echo $$
4753
$ sudo sh -c "echo 4753 > cgroup.procs"
sh: 1: echo: echo: I/O error
$ cat cpuset.mems
$ sudo sh -c "echo 0 > cpuset.mems"
$ cat cpuset.mems
0
$ sudo sh -c "echo 4753 > cgroup.procs"
$ cat cgroup.procs
4753
12569
The latter shows that the current shell (pid#4753) is now located in the newly created cgroup (the second pid 12569 is the cat's command one as being the child of the current shell, it inherits its cgroups). With a formatted ps command, it is possible to verify on which CPU the processes are running (PSR column):
$ ps -o pid,ppid,psr,command
PID PPID PSR COMMAND
4753 2372 3 bash
12672 4753 1 ps -o pid,ppid,psr,command
We can see that the current shell is running on CPU#3 and its child (ps command) which inherits the its cgroups is running on CPU#1.
As a conclusion, instead of using sched_setaffinity() or any pthread service, it is possible to create a cpuset hierarchy in the cgroups tree and move the processes into them by writing their pids in the corresponding cgroup.procs files.