【问题标题】:Cgroup unexpectedly propagates SIGSTOP to the parentCgroup 意外将 SIGSTOP 传播到父级
【发布时间】:2020-11-05 19:02:06
【问题描述】:

我有一个小脚本可以在限制 CPU 时间的 cgroup 中运行命令:

$ cat cgrun.sh
#!/bin/bash

if [[ $# -lt 1 ]]; then
    echo "Usage: $0 <bin>"
    exit 1
fi

sudo cgcreate -g cpu:/cpulimit
sudo cgset -r cpu.cfs_period_us=1000000 cpulimit
sudo cgset -r cpu.cfs_quota_us=100000 cpulimit
sudo cgexec -g cpu:cpulimit sudo -u $USER "$@"
sudo cgdelete cpu:/cpulimit

我让命令运行:./cgrun.sh /bin/sleep 10

然后我从另一个终端向睡眠命令发送 SIGSTOP。不知何故,此时父命令sudocgexec 也收到了这个信号。然后,我将 SIGCONT 发送到 sleep 命令,它允许 sleep 继续。

但是此时sudocgexec 都被停止了,永远不会收获休眠进程的僵尸。我不明白这怎么会发生?我该如何预防呢?此外,我无法将 SIGCONT 发送到 sudocgexec,因为我正在从用户发送信号,而这些命令以 root 身份运行。

这是它在 htop 中的样子(省略了一些列):

    PID USER S CPU% MEM%   TIME+  Command
1222869 user S  0.0  0.0  0:00.00 │     │  └─ /bin/bash ./cgrun.sh /bin/sleep 10
1222882 root T  0.0  0.0  0:00.00 │     │     └─ sudo cgexec -g cpu:cpulimit sudo -u user /bin/sleep 10
1222884 root T  0.0  0.0  0:00.00 │     │        └─ sudo -u desertfox /bin/sleep 10
1222887 user Z  0.0  0.0  0:00.00 │     │           └─ /bin/sleep 10

如何以不将 SIGSTOP 退回到父进程的方式创建 cgroup?

更新

如果我使用 systemd-run 启动进程,我不会观察到相同的行为:

sudo systemd-run --uid=$USER -t -p CPUQuota=10% sleep 10

【问题讨论】:

    标签: linux bash signals sudo cgroups


    【解决方案1】:

    我不会使用“cg工具”,而是使用shell命令创建cpulimit cgroup(它是mkdir),设置cfs参数(在相应的 cpu.cfs_* 文件中使用echo 命令),使用(...) 表示法创建一个子shell,将其移动到cgroup(其pid 的echo 命令进入tasks cgroup 的文件)并在此子 shell 中执行请求的命令。

    因此,cgrun.sh 看起来像这样:

    #!/bin/bash
    
    if [[ $# -lt 1 ]]; then
        echo "Usage: $0 <bin>" >&2
        exit 1
    fi
    
    CGTREE=/sys/fs/cgroup/cpu
    
    sudo -s <<EOF
    [ ! -d ${CGTREE}/cpulimit ] && mkdir ${CGTREE}/cpulimit
    echo 1000000 > ${CGTREE}/cpulimit/cpu.cfs_period_us
    echo 100000 > ${CGTREE}/cpulimit/cpu.cfs_quota_us
    EOF
    
    # Sub-shell in background
    (
      # Pid of the current sub-shell
      # ($$ would return the pid of the father process)
      MY_PID=$BASHPID
    
      # Move current process into the cgroup
      sudo sh -c "echo ${MY_PID} > ${CGTREE}/cpulimit/tasks"
    
      # Run the command with calling user id (it inherits the cgroup)
      exec "$@"
    
    ) &
    
    # Wait for the sub-shell
    wait $!
    
    # Exit code of the sub-shell
    rc=$?
    
    # Delete the cgroup
    sudo rmdir ${CGTREE}/cpulimit
    
    # Exit with the return code of the sub-shell
    exit $rc
    

    运行它(在我们获取当前 shell 的 pid 以在另一个终端中显示进程层次结构之前):

    $ echo $$
    112588
    $ ./cgrun.sh /bin/sleep 50
    

    这将创建以下流程层次结构:

    $ pstree -p 112588
    bash(112588)-+-cgrun.sh(113079)---sleep(113086)
    

    停止sleep 进程:

    $ kill -STOP 113086
    

    查看 cgroup 以验证 sleep 命令正在其中运行(它的 pid 在 tasks 文件中)并且 CFS 参数设置正确:

    $ ls -l /sys/fs/cgroup/cpu/cpulimit/
    total 0
    -rw-r--r-- 1 root root 0 nov.    5 22:38 cgroup.clone_children
    -rw-r--r-- 1 root root 0 nov.    5 22:38 cgroup.procs
    -rw-r--r-- 1 root root 0 nov.    5 22:36 cpu.cfs_period_us
    -rw-r--r-- 1 root root 0 nov.    5 22:36 cpu.cfs_quota_us
    -rw-r--r-- 1 root root 0 nov.    5 22:38 cpu.shares
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpu.stat
    -rw-r--r-- 1 root root 0 nov.    5 22:38 cpu.uclamp.max
    -rw-r--r-- 1 root root 0 nov.    5 22:38 cpu.uclamp.min
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.stat
    -rw-r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage_all
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage_percpu
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage_percpu_sys
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage_percpu_user
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage_sys
    -r--r--r-- 1 root root 0 nov.    5 22:38 cpuacct.usage_user
    -rw-r--r-- 1 root root 0 nov.    5 22:38 notify_on_release
    -rw-r--r-- 1 root root 0 nov.    5 22:36 tasks
    $ cat /sys/fs/cgroup/cpu/cpulimit/tasks 
    113086  # This is the pid of sleep
    $ cat /sys/fs/cgroup/cpu/cpulimit/cpu.cfs_*
    1000000
    100000
    

    sleep进程发送SIGCONT信号:

    $ kill -CONT 113086
    

    进程结束,cgroup被销毁:

    $ ls -l /sys/fs/cgroup/cpu/cpulimit
    ls: cannot access '/sys/fs/cgroup/cpu/cpulimit': No such file or directory
    

    获取脚本执行完毕后的退出码(即启动命令的退出码):

    $ echo $?
    0
    

    【讨论】:

    • 谢谢。你的例子似乎工作正常。这是否表明 cg 工具存在某种形式的错误?
    • cg 工具工作正常,但在这个用例中不够灵活:两个涉及很多的过程......
    • @mcsim:我增强了脚本使其返回子shell的退出代码
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2020-11-07
    • 2020-04-09
    • 1970-01-01
    • 2017-06-08
    • 2013-01-07
    相关资源
    最近更新 更多