Note first that the kill()
syscall is somewhat misnamed, as it is a general-purpose function for sending a signal to a process. Killing the target process is only one of several possible results.
More generally, however, signal handling is is an interrupt mechanism. A great many library functions, including wait()
can be interrupted by receipt of a signal. Control passes to the registered handler for that signal, if any, or else the default action is performed. Afterward, the function that was interrupted returns, indicating an error via its return code and / or by setting errno
.
Edited to add: Additionally, your own code may be interrupted by receipt of a signal. Provided that the effect is not to terminate the process, execution will resume at the point where it left off if the signal handler exits normally, or at some other point if the handler exits by calling longjmp()
.
Also, signal delivery is an asynchronous mechanism handled by the kernel. A process can be blocked or otherwise occupied and still receive signals; indeed, that's a big part of the point of them. Each process has a queue of pending signals awaiting handling; for most processes, this queue is empty almost all the time, but unless you explicitly block signals, it is never safe for a process to assume that it will not receive any (and certain signals cannot be blocked anyway).
In your particular code, the main process starts by setting function1()
to be its handler for signal USR1
. It then forks, and the child process sets function function2()
as its handler for signal USR1
(not thereby affecting the parent), sends signal USR1
to the parent, and goes into an infinite loop.
Meanwhile, the parent initiates a wait()
for its child process. This will be interrupted by receipt of the signal. The wait will end after the signal is received and the registered handler runs, with wait()
returning -1 and setting errno
to EINTR
. One of the actions the handler performs is to send a SIGUSR1
to the child.
Upon receiving the signal, the child's normal flow of execution is interrupted to run its handler, function2()
. This updates the child's copy of variable counter
, prints its value, and exit()
s.
End result:
The main process prints
counter = 1
then exits. The child process prints
counter = 3
then exits.