Unit4 Signals Session 2
Unit4 Signals Session 2
Another problem with these earlier systems was that the process was unable to turn a signal off when it didn’t want the
signal to occur
• Another problem with these earlier int sig_int(); /* my signal handling function */
systems was that the process was int sig_int_flag; /* set nonzero when signal occurs */
unable to turn a signal off when it
didn’t want the signal to occur. main()
{
• All the process could do was ignore signal(SIGINT, sig_int); /* establish handler */
the signal. ...
while (sig_int_flag == 0)
• There are times when we would like pause(); /* go to sleep, waiting for signal */
to tell the system "prevent the ...
following signals from interrupting }
• Reads that can block the caller forever if data isn’t present with certain file types (pipes,
terminal devices, and network devices)
• Writes that can block the caller forever if the data can’t be accepted immediately by these
same file types
• Opens on certain file types that block the caller until some condition occurs (such as a
terminal device open waiting until an attached modem answers the phone)
• The pause function (which by definition puts the calling process to sleep until a signal is
caught) and the wait function
• Certain ioctl operations
• Some of the interprocess communication functions
• notable exception to these slow system calls is anything related to disk I/O.
again:
if ((n = read(fd, buf, BUFFSIZE)) < 0) {
if (errno == EINTR)
goto again; /* just an interrupted system call */
/* handle other errors */
}
Automatic restarting
• Automatic restarting of certain interrupted system calls were introducted since 4.2BSD
to prevent applications from having to handle interrupted system calls.
• The system calls that were automatically restarted are:
Functions that are interrupted by a signal only if they are operating on a slow device:
• ioctl
• read
• readv
• write
• writev
Functions that are always interrupted when a signal is caught.
• wait
• waitpid
• Some applications didn’t want the operation restarted if it was interrupted; 4.3BSD
allowed the process to disable this feature on a per-signal basis.
Reentrant Functions
• When a signal that is being caught is handled by a process, the normal
sequence of instructions being executed by the process is temporarily
interrupted by the signal handler.
• The process then continues executing, but the instructions in the signal
handler are now executed.
• If the signal handler returns (instead of calling exit or longjmp), then the
normal sequence of instructions that the process was executing when
the signal was caught continues executing.
• This is similar to what happens when a hardware interrupt occurs.
Reentrant Functions
• However, in the signal handler, we can’t tell where the process was
executing when the signal was caught:
• What if the process was in the middle of allocating additional memory
on its heap using malloc, and we call malloc from the signal handler?
• Havoc can result for the process, since malloc usually maintains a linked
list of all its allocated areas, and it may have been in the middle of
changing this list.
• What if the process was in the middle of a call to a function, such as
getpwnam ,that stores its result in a static location, and we call the same
function from the signal handler?
• The information returned to the normal caller can get overwritten with
the information returned to the signal handler.
#include "apue.h" int main(void)
#include <pwd.h> {
struct passwd *ptr;
static void
signal(SIGALRM, my_alarm);
my_alarm(int signo)
alarm(1);
{
for ( ; ; ) {
struct passwd *rootptr;
if ((ptr = getpwnam("sar")) == NULL)
err_sys("getpwnam error");
printf("in signal handler\n"); if (strcmp(ptr->pw_name, "sar") != 0)
if ((rootptr = getpwnam("root")) == NULL) printf("return value corrupted!, pw_name = %s\n",
err_sys("getpwnam(root) error"); ptr->pw_name);
alarm(1); }
} }
SIGCLD Semantics
• The kill function sends a signal to a int kill(pid_t pid, int signo);
process or a group of processes. int raise(int signo);
• The raise function allows a process to
send a signal to itself.
• The raise function was originally defined /* Both return: 0 if OK, −1 on error */
by ISO C. POSIX.1 includes it to align The call:
itself with the ISO C standard, but
POSIX.1 extends the specification of
raise to deal with threads. raise(signo);
• Since ISO C does not deal with multiple is equivalent to the call:
processes, it could not define a function,
such as kill, that requires a process ID
argument. kill(getpid(), signo);
• There are four different conditions for the pid • A process needs permission to send a
argument to kill: signal to another process:
• pid > 0. The signal is sent to the process whose
process ID is pid. • The superuser can send a signal to any
• pid == 0 The signal is sent to all processes whose process.
process group ID equals the process group ID of the
sender and for which the sender has permission to • For other users, the real or effective user
send the signal. ID of the sender has to equal the real or
• pid < 0. The signal is sent to all processes whose effective user ID of the receiver. If the
process group ID equals the absolute value of pid implementation supports
and for which the sender has permission to send the _POSIX_SAVED_IDS, the saved set-user-ID
signal.
of the receiver is checked instead of its
• pid == −1. The signal is sent to all processes on the
system for which the sender has permission to send
effective user ID.
the signal. • One special case for the permission
• Note that the term all processes in the four testing also exists: if the signal being sent
conditions above excludes an implementation- is SIGCONT,aprocess can send it to any
defined set of system processes, including kernel
processes and init (pid 1).
other process in the same session.
alarm and pause Functions
• The alarm function sets a timer that will expire at a specified time in the
future.
• When the timer expires, the SIGALRM signal is generated.
• If we ignore or don’t catch this signal, its default action is to terminate
the process.
• #include <unistd.h>
• unsigned int alarm(unsigned int seconds);
• /* Returns: 0 or number of seconds until previously set alarm */
• The seconds value is the number of clock seconds in the future when the signal
should be generated. When that time occurs, the signal is generated by the kernel,
although additional time could elapse before the process gets control to handle
the signal, because of processor scheduling delays.
• There is only one of these alarm clocks per process. If alarm is called with a
previously registered alarm clock not yet expired, then:
• The number of seconds left for previous alarm clock is returned as the value of this
function.
• The previous alarm clock is replaced by the new value.
• If a previously registered alarm clock for the process has not yet expired and if the
seconds value is 0, the previous alarm clock is canceled. The number of seconds
left for that previous alarm clock is still returned as the value of the function.
• The pause function suspends the calling process until a signal is
caught.
• #include <unistd.h>
• int pause(void);