Open a terminal named "termA", and run the created file
callback.sh
with/bin/bash callback.sh
.cat callback.sh #!/bin/bash myCallback() { echo "callback function called at $(date)" } trap myCallback SIGUSR1 sleep 20
Open a new terminal named "termB" and run:
pkill -USR1 -f callback.sh
Something as below is shown after 20 seconds in termA; it's never shown in termA instantly:
callback function called at Mon Nov 19 08:21:52 HKT 2018
The conclusion verified that when Bash is executing an external command in the foreground, it does not handle any signals received until the foreground process terminates (see signal trap).
Make a little change in callback.sh
:
cat callback.sh
#!/bin/bash
myCallback() {
echo "callback function called at $(date)"
}
trap myCallback SIGUSR1
while true; do
read -p "please input something for foo: " foo
done
Add an infinite while loop and remove sleep 20
.
Open a terminal named "termA" and run the created file
callback.sh
with/bin/bash callback.sh
; the first time, the info pops up instantly.please input something for foo:
Open a new terminal named "termB" and run
pkill -USR1 -f callback.sh
; the first time, the info pops up instantly in termA.callback function called at Mon Nov 19 09:07:14 HKT 2018
Issue 1: callback.sh
contains an infinite while loop. How does that explain the following?
it does not handle any signals received until the foreground process terminates
In this case, the foreground process never terminates.
Go on in termB, run pkill -USR1 -f callback.sh
for the second time.
callback function called at Mon Nov 19 09:07:14 HKT 2018
The info above pops up instantly in termA again.
Issue 2: No please input something for foo:
shown in termA,
go to termB, run pkill -USR1 -f callback.sh
for the third time,
the following info is shown in termA again.
callback function called at Mon Nov 19 09:07:24 HKT 2018
Still no please input something for foo:
is shown in termA.
Why does the info please input something for foo:
freeze up?
Before explaining out your problem, a bit of context on how
read
command works. It reads in input data fromstdin
untilEOF
is encountered. It is safe to say the call toread
command is non-blocking when it comes to reading from on-disk files. But whenstdin
is connected to the terminal, the command will block until the user types something.How signal handlers work?
A simple explanation on how signal handling works. See the below snippet in
C
which just acts onSIGINT
( aka.CTRL+C
)It will register the signal handler and then will enter the infinite loop. When we hit
Ctrl-C
, we can all agree that the signal handlersignal_handler()
should execute and"Hello World!"
prints to the screen, but the program was in an infinite loop. In order to print"Hello World!"
it must have been the case that it broke the loop to execute the signal handler, right? So it should exit the loop as well as the program. Let's see:As the output indicates, every time we issued
Ctrl-C
,"Hello World!"
prints, but the program returns to the infinite loop. It is only after issuing aSIGQUIT
signal withCtrl-\
did the program actually exit. Depending on yourulimit
settings, it would dump a core or print out the signal number received.While the interpretation that the loop would exit is reasonable, it doesn't consider the primary reason for signal handling, that is, asynchronous event handling. That means the signal handler acts out of the standard flow of the control of the program; in fact, the whole program is saved within a context, and a new context is created just for the signal handler to execute in. Once the signal handler has completed its actions, the context is switched back and the normal execution flow starts (i.e. the
while(1)
).To answer your questions,
The key thing to note here is the external command part. In the first case, where
sleep
is an external process but in the second case,read
is a built-in from the shell itself. So the propagation of the signal to these two differs in both these casesYes, this behavior is expected. Because at this time only the function is defined and the trap handler is registered to the function
myCallback
and the signal is not yet received in the script. As the execution sequence goes, the message from theread
prompt is thrown for the first time.Yes, while the
read
command is waiting for string followed by the Enter key pres which signals theEOF
, it receives a signalSIGUSR1
from the other terminal, the current execution context is saved and the control is switched the signal handler which prints the string with the current date.As soon as the handler finishes executing, the context resumes to the
while
loop in which theread
command is still waiting for an input string. Until theread
command is successful, all subsequent signal traps would just print the string inside the signal handler.Same as explained previously, the
read
command is not complete for once in your while loop, only if it is successful reading a string, the next iteration of the loop would start and a new prompt message would be thrown.Image source: The Linux Programming Interface by Michael KerrisK