当前位置: 首页 > 知识库问答 >
问题:

'ulimit-t'在shell和OSS之间完全不可移植?

费学
2023-03-14

更新:这越来越不是一个问题,而是一个总结。哦,好吧...

不过,还有很多不清楚的地方。我发现其中有些相当出乎意料。特别是,您获得的行为取决于shell和底层操作系统。我创建了一个表,总结了可变性的程度。我还包括了一个脚本的代码,我用来自动获得这些结果。最后一个测试需要root权限,如果注释掉test_shell_sudo$shell,则可以阻止它运行。

|                                              | Darwin/zsh | Darwin/bash | FreeBSD/zsh | FreeBSD/bash | FreeBSD/dash | Linux/zsh  | Linux/bash  | Linux/dash  |
| ulimit -t sets                               | soft limit | both limits | soft limit  | both limits  | both limits  | soft limit | both limits | both limits |
| ulimit -t gets                               | soft limit | soft limit  | soft limit  | soft limit   | soft limit   | soft limit | soft limit  | soft limit  |
| Hard limits can be set below the soft limit  | yes        | no          | yes         | yes          | yes          | yes        | no          | no          |
| Soft limits can be set above the hard limit  | yes        | no          | yes         | no           | no           | yes        | no          | no          |
| Hard limits can be raised without privileges | yes        | no          | yes         | no           | no           | yes        | no          | no          |
| soft signal                                  | SIGXCPU    | SIGXCPU     | SIGXCPU     | SIGXCPU      | SIGXCPU      | SIGXCPU    | SIGXCPU     | SIGXCPU     |
| hard signal                                  | SIGXCPU    | SIGXCPU     | SIGKILL     | SIGKILL      | SIGKILL      | SIGKILL    | SIGKILL     | SIGKILL     |
| Number of SIGXCPUs sent                      | one        | one         | one         | one          | one          | multiple   | multiple    | multiple    |
| Raising soft beyond hard limit raises it     | yes        | impossible* | yes         | no           | no           | yes        | impossible* | impossible* |

* even as root
#!/usr/bin/env bash

get_sigcode() {
    /bin/kill -l |
        tr '\n[a-z]' ' [A-Z]' |
        awk -v name=$1 '
            { for (i=1; i<=NF; ++i) if ($i == name) print i }'
}

create_runner() {
    cat > sig.c <<'EOF'
#include <stdlib.h>
#include <stdio.h>

int
main()
{
  int runs = 0;
  double x = 0.0;
  for (;;runs++) {
    x += (double)rand() / RAND_MAX;
    if (x >= 1e7) {
      printf("Took %d iterations to reach 1000.\n", runs);
      x = 0.0;
      runs = 0;
    }
  }
  return 0;
}
EOF
    cc sig.c -o sig
    rm -f sig.c
    echo Successfully compiled sig.c
}

create_counter() {
    cat > sigcnt.c <<'EOF'
#include <stdatomic.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

sig_atomic_t sig_received;
void handle_signal(int signum) {
  sig_received = signum;
}

int
main()
{
  signal(SIGXCPU, handle_signal);

  int sigxcpu_cnt = 0;
  time_t start, now;
  time(&start);

  int runs = 0;
  double x = 1;
  for (;;) {
    if (sig_received == SIGXCPU) {
      sigxcpu_cnt++;
      sig_received = 0;
    }
    time(&now);
    if (now - start > 5) {
      switch (sigxcpu_cnt) {
      case 0:
        fprintf(stderr, "none\n");
        exit(0);
      case 1:
        fprintf(stderr, "one\n");
        exit(0);
      default:
        fprintf(stderr, "multiple\n");
        exit(0);
      }
    }

    // Do something random that eats CPU (sleeping is not an option)
    x += (double)rand() / RAND_MAX;
    if (x >= 1e7) {
      printf("Took %d iterations to reach 1000.\n", runs);
      x = 0.0;
      runs = 0;
    }
  }
}
EOF
    cc sigcnt.c -o sigcnt
    rm -f sigcnt.c
    echo Successfully compiled sigcnt.c
}

echo_underscored() {
    out1=$1
    out2=''
    for ((i=0; i < ${#out1}; ++i)); do
        out2+='='
    done
    echo $out1
    echo $out2
}


test_shell() {
    shell=$1
    echo_underscored "Testing shell: $shell"

    f() {
        $shell -c 'ulimit -St 3; ulimit -t 2; ulimit -Ht; ulimit -St' | tr -d '\n'
    }
    case `f` in
        22)
            t_sets='both limits';;
        unlimited2)
            t_sets='soft limit';;
        *)
            echo UNEXPECTED;;
    esac
    echo "ulimit -t sets: ${t_sets}"

    f() {
        $shell -c 'ulimit -St 3; ulimit -Ht 4; ulimit -St 3; ulimit -t'
    }
    case `f` in
        3)
            t_gets='soft limit';;
        *)
            echo UNEXPECTED;;
    esac
    echo "ulimit -t gets: ${t_gets}"

    f() {
        $shell -c 'ulimit -St 2; ulimit -Ht 1' >/dev/null 2>&1 &&
            echo yes || echo no
    }
    ht_can_set_below_soft=`f`
    echo "Hard limits can be set below the soft limit: ${ht_can_set_below_soft}"

    f() {
        $shell -c 'ulimit -St 1; ulimit -Ht 2; ulimit -St 3' >/dev/null 2>&1 &&
            echo yes || echo no
    }
    st_can_set_above_hard=`f`
    echo "Soft limits can be set above the hard limit: ${st_can_set_above_hard}"

    f() {
        $shell -c 'ulimit -St 1; ulimit -Ht 2; ulimit -Ht 3' >/dev/null 2>&1 &&
            echo yes || echo no
    }
    hard_can_be_raised=`f`
    echo "Hard limits can be raised without privileges: ${hard_can_be_raised}"

    f() {
        $shell -c 'ulimit -St 1; ./sig' >/dev/null 2>&1
        echo $?
    }
    case $((`f` - 128)) in
        ${sigxcpu})
            soft_signal=SIGXCPU;;
        ${sigkill})
            soft_signal=SIGKILL;;
        *)
            echo UNEXPECTED;
    esac
    echo "soft signal: ${soft_signal}"

    f() {
        $shell -c 'ulimit -St 1; ulimit -Ht 1; ./sig' >/dev/null 2>&1
        echo $?
    }
    case $((`f` - 128)) in
        ${sigxcpu})
            hard_signal=SIGXCPU;;
        ${sigkill})
            hard_signal=SIGKILL;;
        *)
            echo UNEXPECTED;;
    esac
    echo "hard signal: ${hard_signal}"

    f() {
        $shell -c 'ulimit -St 1; ./sigcnt 2>&1 >/dev/null'
    }
    sigxcpus_sent=`f`
    echo "Number of SIGXCPUs sent: ${sigxcpus_sent}"
}

test_shell_sudo() {
    shell=$1
    echo_underscored "Testing shell with sudo: $shell"

    f() {
        sudo $shell -c 'ulimit -St 1; ulimit -Ht 1; ulimit -St 2 && ulimit -Ht' \
            2>/dev/null;
    }
    out=`f`; ret=$?;
    if [[ $ret == 0 ]]; then
        case $out in
            1)
                raising_soft_beyond_hard='no';;
            2)
                raising_soft_beyond_hard='yes';;
            *)
                echo UNEXPECTED;;
        esac
    else
        raising_soft_beyond_hard='impossible'
    fi
    echo "Raising soft beyond hard limit raises it: ${raising_soft_beyond_hard}"
}

main() {
    echo "Testing on platform: $(uname)"

    sigxcpu=$(get_sigcode XCPU)
    sigkill=$(get_sigcode KILL)
    echo Number of signal SIGXCPU: ${sigxcpu}
    echo Number of signal SIGKILL: ${sigkill}

    create_runner
    create_counter
    echo

    for shell in zsh bash dash; do
        which $shell >/dev/null || continue;
        test_shell $shell
        echo
    done

    for shell in zsh bash dash; do
        which $shell >/dev/null || continue;
        test_shell_sudo $shell
        echo
    done
}

main

相应的要点还附带了一个更好的表格。

共有1个答案

丁晋
2023-03-14

首先,这里有ulimits的绝对规则,包括shell在内的所有进程都必须遵守:

  • 任何人都可以降低自己的硬限制。
  • 它需要特殊权限才能提高硬限制。
  • 软限制可以上下提升,只要它小于硬限制。

考虑到这一点:

  1. 是否可以再次提高先前对ulimit的调用设置的限制?

软极限,是的。硬性限制,没有。

bash似乎认为不,而zsh认为是。

$ strace -e setrlimit zsh -c 'ulimit -t 1'
setrlimit(RLIMIT_CPU, {rlim_cur=1, rlim_max=RLIM64_INFINITY}) = 0

$ strace -e setrlimit bash -c 'ulimit -t 1'
setrlimit(RLIMIT_CPU, {rlim_cur=1, rlim_max=1}) = 0
zsh% ulimit -H -t 1
zsh% ( while true; do true; done )   # is a child, soon killed
zsh% while true; do true; done       # not a child, never dies

如果同时设置这两个限制,它们将应用于当前shell,如bash中所示:

zsh% ulimit -SH -t 1
zsh% while true; do true; done       # will now die, just like bash

我不知道这背后的理由是什么。

 类似资料:
  • 问题内容: package main 该代码可以很好地工作。但是,如果按如下所示更改方法,则会导致死循环。区别在于将替换为。为什么? 问题答案: 因为程序包检查要打印的值是否具有方法(或换句话说:是否实现接口),如果是,则将调用它以获取值的表示形式。 软件包doc中对此进行了说明: […]如果操作数实现String()字符串方法,则将调用该方法将对象转换为字符串,然后根据动词的要求对其进行格式化(

  • 问题内容: 从理论上讲,如果我将所有cookie从selenium的对象复制到对象,那么请求是否能够继续进行,就好像会话没有中断一样? 具体来说,我对编写自动化感兴趣,我可以通过Selenium到达网页上的特定位置,然后将特定的下载链接传递到,该链接将下载并验证文件中特定字节的内容,有时甚至是完整文件。(下载的文件的值将根据我在selenium中的相互作用而变化) 问题答案: 是的,肯定可以。以下

  • 我一直在学习如何使用java编程,但我还没有明确解释的和方法的区别。第二个只是将LinkedList对象中的所有元素作为数组返回,对吗?但是,第一个呢? 编辑: 我的意思是,我从甲骨文中阅读了文档,它说: 返回一个数组,其中包含此列表中所有元素的正确顺序(从第一个元素到最后一个元素);返回数组的运行时类型是指定数组的运行时类型。如果列表适合指定的数组,则返回该数组。否则,将使用指定数组的运行时类型

  • 本文向大家介绍完全虚拟化和准虚拟化之间的区别,包括了完全虚拟化和准虚拟化之间的区别的使用技巧和注意事项,需要的朋友参考一下 在本文中,我们将了解完全虚拟化和半虚拟化之间的区别 全面虚拟化 此过程由IBM于1966年引入。它被认为是第一个用于服务器虚拟化的软件解决方案。它使用二进制翻译和直接方法。 在这种情况下,使用虚拟机将来宾操作系统与虚拟化层和硬件完全隔离。 完全虚拟化的示例包括Microsof

  • 问题内容: 我一直认为,子shell程序不是子进程,而是同一进程中的另一个shell程序环境。 我使用一组基本的内置函数: 在另一个终端上: 因此,kornShell(ksh)中没有子进程。 输入bash,使用相同的命令,其行为似乎有所不同: 因此,bash中的一个子进程。 通过阅读bash手册页,很明显,为子shell创建了另一个进程,但是它伪造了$$,这很时髦。 是bash和ksh之间的区别是

  • 我正在测试上面的代码。两者给我的结果是一样的。我正试图理解第1、2和6行之间的区别。我可以通过这两种方法获得相同的结果。