Skip to content

Instantly share code, notes, and snippets.

@epipping
Last active July 15, 2016 10:18
Show Gist options
  • Save epipping/393f1c5d5fe388a4c7903b53e4e416ff to your computer and use it in GitHub Desktop.
Save epipping/393f1c5d5fe388a4c7903b53e4e416ff to your computer and use it in GitHub Desktop.
Test how ulimit behaves on your OS (with different shells)
#!/usr/bin/env bash
get_sigcode() {
/bin/kill -l |
awk -v name=$1 '
BEGIN { nf = 0 }
{
for (i=1; i<=NF; ++i)
if (toupper($i) == name)
print i+nf;
nf += NF
}'
}
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
@epipping
Copy link
Author

  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*

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment