Skip to content

Commit

Permalink
[test] Preparing for job control and signal changes
Browse files Browse the repository at this point in the history
- demo: How to handle SIGINT in Python
- test/stateful: Repro of issue #1005
  - But I want to fix the issue where Ctrl-Z is ignored first ...
- Rename devtools/sigparse.sh -> test/signal-state.sh
- Start test/group-session.sh
  • Loading branch information
Andy C committed Feb 5, 2022
1 parent 281c220 commit b7ed2ce
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 18 deletions.
5 changes: 5 additions & 0 deletions core/pyos.py
Expand Up @@ -271,6 +271,11 @@ def __call__(self, sig_num, unused_frame):
def SignalState_AfterForkingChild():
# type: () -> None
"""Not a member of SignalState since we didn't do dependency injection."""

# Note: this happens in BOTH interactive and non-interactive shells.
# We technically don't need to do most of it in non-interactive, since we
# did not change state in InitInteractiveShell().

# Python sets SIGPIPE handler to SIG_IGN by default. Child processes
# shouldn't have this.
# https://docs.python.org/2/library/signal.html
Expand Down
39 changes: 39 additions & 0 deletions demo/py_signals.py
@@ -0,0 +1,39 @@
#!/usr/bin/env python2
"""
py_signals.py
"""
from __future__ import print_function

import signal
import sys
import time



g_sigint = False

def SigInt(x, y):
print('SIGINT')
global g_sigint
g_sigint = True


def main(argv):

# This suppresses KeyboardInterrupt. You can still do Ctrl-\ or check a flag
# and throw your own exception.
signal.signal(signal.SIGINT, SigInt)

while True:
print('----')
time.sleep(0.5)
if g_sigint:
raise Exception('interrupted')


if __name__ == '__main__':
try:
main(sys.argv)
except RuntimeError as e:
print('FATAL: %s' % e, file=sys.stderr)
sys.exit(1)
17 changes: 2 additions & 15 deletions spec/stateful/job_control.py
Expand Up @@ -148,26 +148,13 @@ def bug_1005(sh):

expect_prompt(sh)

return

sh.sendline('sleep 10')

# This is NOT right. The Ctrl-Z goes to the TERMINAL, and the TERMINAL sends
# it to both the shell process and the sleep process. The shell process
# should ignore it.

# Section 19.6 of APUE: SIGTSTP can't be delivered to a process!!
# Section 19.7: Signal generation with ioctl TIOCSIG!

#sh.kill(signal.SIGTSTP)
time.sleep(0.1)

# This distribute Ctrl-Z to the whole process group? Why doesn't it work?
sh.sendcontrol('z')
ctrl_z(sh)
sh.expect(r'.*Stopped.*')

#sh.expect(r'\^Z')

return
sh.sendline('wait')
sh.sendline('echo status=$?')
sh.expect(r"status=0")
Expand Down
17 changes: 17 additions & 0 deletions test/group-session.sh
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
#
# Test kernel state: the process group and session leader.
#
# Usage:
# ./group-session.sh <function name>

set -o nounset
set -o pipefail
set -o errexit

show() {
# by deafult, it shows processes that use the same terminal
ps -o pid,ppid,pgid,sid,tname,comm
}

"$@"
28 changes: 25 additions & 3 deletions devtools/sigparse.sh → test/signal-state.sh
@@ -1,20 +1,23 @@
#!/usr/bin/env bash
#
# Parse signal format in /proc.
# Test kernel state: which signals caught, ignored, etc.
#
# Copied from:
# https://unix.stackexchange.com/questions/85364/how-can-i-check-what-signals-a-process-is-listening-to
#
# Usage:
# devtools/sigparse.sh <function name>
# test/signal-state.sh <function name>

sigparse() {
# Parse signal format in /proc.
local hex_mask=$1

local i=0

# bits="$(printf "16i 2o %X p" "0x$1" | dc)" # variant for busybox

# hex to binary. Could also do this with Python.
bits="$(printf "ibase=16; obase=2; %X\n" "0x$1" | bc)"
bits="$(printf 'ibase=16; obase=2; %X\n' "0x$hex_mask" | bc)"
while test -n "$bits"; do
i=$((i + 1))
case "$bits" in
Expand All @@ -33,7 +36,18 @@ report() {
done
}

do-child() {
echo
echo 'BACKGROUND CHILD'
$sh -c 'script=$1; sleep 0.5 & { sleep 0.2; $script report $!; }' -- $0

# TODO: I think we need a foreground child too. It can just be a C program that
# prints its own PID, and then waits for a byte on stdin before it exits?
}

compare-shells() {
local do_child=${1:-}

local -a shells=(bash dash mksh zsh bin/osh)

# Hm non-interactive shells have consistency.
Expand All @@ -46,6 +60,10 @@ compare-shells() {
echo

$sh -c 'script=$1; $script report $$' -- $0

if test -n "$do_child"; then
do-child $sh
fi
done

echo
Expand All @@ -68,6 +86,10 @@ compare-shells() {
esac

$sh $more_flags -i -c 'script=$1; $script report $$' -- $0

if test -n "$do_child"; then
do-child $sh
fi
done
}

Expand Down
5 changes: 5 additions & 0 deletions test/stateful.sh
Expand Up @@ -26,6 +26,11 @@ export PYTHONPATH=.

readonly BASE_DIR=_tmp/stateful

run() {
### for PYTHONPATH
"$@"
}

signals-quick() {
spec/stateful/signals.py \
$OSH bash "$@"
Expand Down

0 comments on commit b7ed2ce

Please sign in to comment.