CS5

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 31

SIGNALS

• Signals are software interrupts.


• Signals provide a way of handling asynchronous events
• When a signal is sent to a process. It can react to signals in one of
three ways:

Accept the default action of the signal, which for most signals will
terminate the process.

 Ignore the signal. The signal will be discarded and it has no affect
whatsoever on the recipient process.

 Invoke a user-defined function. The function is known as a signal


handler routine and the signal is said to be caught when this function is
called.
Examples
Name Description
• SIGABRT abnormal termination (abort)
• SIGALRM timer expired (alarm)
• SIGBUS hardware fault
• SIGCHLD change in status of child
• SIGCONT continue stopped process
• SIGEMT hardware fault
• SIGFPE arithmetic exception
• SIGFREEZE checkpoint freeze
• SIGHUP hangup
• SIGILL illegal instruction
• SIGINT terminal interrupt character
• SIGIO asynchronous I/O
• SIGIOT hardware fault
• SIGKILL termination
SIGPIPE write to pipe with no readers
SIGPWR power fail/restart
SIGSEGV invalid memory reference
SIGSTOP stop process
SIGSYS invalid system call
SIGTERM termination
SIGTRAP hardware fault
SIGNAL
• The function prototype of the signal API is:
#include <signal.h>
void (*signal(int sig_no, void (*handler)(int)))(int);
-- sig_no is a signal identifier like SIGINT or SIGTERM.
-- The handler argument is the function pointer of a user-defined
signal handler function.
Example
#include<iostream.h>
#include<signal.h>
/*signal handler function*/
void catch_sig(int sig_num)
{
signal (sig_num,catch_sig);
cout<<”catch_sig:”<<sig_num<<endl;
}
/*main function*/
int main()
{
signal(SIGTERM,catch_sig);
signal(SIGINT,SIG_IGN);
signal(SIGSEGV,SIG_DFL);
pause( );
/*wait for a signal interruption*/
}
SIGNAL MASK
• A process initially inherits the parent’s signal
mask when it is created, but any pending
signals for the parent process are not passed
on.
• A process may query or set its signal mask via
the sigprocmask API:

#include <signal.h>
int sigprocmask(int cmd, const sigset_t *new_mask, sigset_t *old_mask);
Returns: 0 if OK, -1 on error
• The new_mask argument defines a set of signals
to be set or reset in a calling process signal
mask.

• cmd argument specifies how the new_mask


value is to be used by the API.

• The old_mask argument used to query current


signal mask of the process.
• The possible values of cmd and the corresponding use of
the new_mask value are:

SIG_SETMASK Overrides the calling process signal mask


with the value specified in the new_mask argument.

SIG_BLOCK Adds the signals specified in the new_mask


argument to the calling process signal mask.
SIG_UNBLOCK Removes the signals specified in the
new_mask argument from the calling process signal mask.
• If the actual argument to new_mask argument is
a NULL pointer, the cmd argument will be
ignored, and the current process signal mask will
not be altered and current signal mask is
returned.

• If the actual argument to old_mask is a NULL


pointer, no previous signal mask will be returned.

• The sigset_t contains a collection of bit flags.


The BSD UNIX and POSIX.1 define a set of API
known as sigsetops functions
#include<signal.h>
int sigemptyset (sigset_t* sigmask);
int sigaddset (sigset_t* sigmask, const int sig_num);
int sigdelset (sigset_t* sigmask, const int sig_num);
int sigfillset (sigset_t* sigmask);
int sigismember (const sigset_t* sigmask, const int sig_num);
• The sigemptyset API clears all signal flags in the sigmask
argument.

• The sigaddset API sets the flag corresponding to the signal_num


signal in the sigmask argument.

• The sigdelset API clears the flag corresponding to the signal_num


signal in the sigmask argument.

• The sigfillset API sets all the signal flags in the sigmask argument.
• [ all the above functions return 0 if OK, -1 on error ]

• The sigismember API returns 1 if flag is set, 0 if not set and -1 if


the call fails.
The following example checks whether the SIGINT signal is
present in a process signal mask and adds it to the mask if it is
not there.
#include<stdio.h>
#include<signal.h>
int main()
{
sigset_t sigmask;
sigemptyset(&sigmask); /*initialise set*/ if(sigprocmask(0,0,&sigmask)==-1) /*get current
signal mask*/
{
perror(“sigprocmask”);
exit(1);
}
else
sigaddset(&sigmask,SIGINT); /*set SIGINT flag*/
if(sigprocmask(SIG_SETMASK,&sigmask,0)==-1)
perror(“sigprocmask”);
}
A process can query which signals are
pending for it via the sigpending API:
#include<signal.h>
int sigpending(sigset_t* sigmask);
Returns 0 if OK, -1 if fails.
The sigpending API can be useful to find out
whether one or more signals are pending for a
process and to set up special signal handling
methods for these signals before the process
calls the sigprocmask API to unblock them.
The following example reports to the console whether
the SIGTERM signal is pending for the process:

#include<iostream.h>
#include<stdio.h>
#include<signal.h>
int main()
{
sigset_t sigmask;
sigemptyset(&sigmask);
if(sigpending(&sigmask)==-1)
perror(“sigpending”)
else
cout << “SIGTERM signal is:” << (sigismember(&sigmask,SIGTERM) ? “Set” :
“No Set”) << endl;
};
SIGACTION
• Improved form of signal () where you can
specify additional signals to be blocked when
the API is handling a signal.
• The sigaction API prototype is:
#include<signal.h>
int sigaction(int signal_num, struct sigaction* action, struct
sigaction* old_action);
Returns: 0 if OK, -1 on error
• The struct sigaction data type is defined in the
<signal.h> header as:
struct sigaction
{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flag;
}
The following program illustrates the uses
of sigaction:
#include<iostream.h>
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void callme(int sig_num)
{
cout<<”catch signal:”<<sig_num<<endl;
}
int main(int argc, char* argv[])
{
sigset_t sigmask;
struct sigaction action,old_action;
sigemptyset(&sigmask);
if(sigaddset(&sigmask,SIGTERM)==-1 || sigprocmask(SIG_SETMASK,&sigmask,0)==-1)
perror(“set signal mask”);
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask,SIGSEGV);
action.sa_handler=callme;
action.sa_flags=0;
if(sigaction(SIGINT,&action,&old_action)==-1)
perror(“sigaction”);
pause(); cout<<argv[0]<<”exists\n”;
return 0;
}
KILL
• A process can send a signal to a related
process via the kill API.
• This is a simple means of inter-process
communication or control.
• The function prototype of the API is:
#include<signal.h>
int kill(pid_t pid, int signal_num);
Returns: 0 on success, -1 on failure.
• The signal_num argument is the integer value of a signal to be
sent to one or more processes designated by pid.

• The possible values of pid and its use by the kill API are:

 pid > 1 : The signal is sent to the process whose process ID is


pid.
 pid == 0 : The signal is sent to all processes whose process
group ID equals the process group ID of the sender and for which
the sender has permission to send the signal.
 pid < 0 : The signal is sent to all processes whose process group
ID equals the absolute value of pid and for which the sender has
permission to send the signal.
 pid == 1 : The signal is sent to all processes on the system
for which the sender has permission to send the signal.
The following program illustrates the implementation of the UNIX kill
command using the kill API:
#include<iostream.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
int main(int argc,char** argv)
{
int pid, sig = SIGTERM;
if(argc==3)
{
if(sscanf(argv[1],”%d”,&sig)!=1)
{
cerr<<”invalid number:” << argv[1] << endl;
return -1;
}
argv++,argc--;
}
while(--argc>0)
if(sscanf(*++argv, “%d”, &pid)==1)
{
if(kill(pid,sig)==-1)
perror(“kill”);
}
else
cerr<<”invalid pid:” << argv[0] <<endl;
return 0;
}
The UNIX kill command invocation syntax is:
Kill [ -<signal_num> ] <pid>......
Where signal_num can be an integer number or the symbolic
name of a signal. <pid> is process ID.
ALARM
• The alarm API can be called by a process to
request the kernel to send the SIGALRM signal
after a certain number of real clock seconds.
• The function prototype of the API is:
#include<signal.h>
Unsigned int alarm(unsigned int time_interval);
Returns: 0 or number of seconds until previously set alarm
The alarm API can be used to implement the sleep API:
#include<signal.h>
#include<stdio.h>
#include<unistd.h>
void wakeup( )
{ printf(“Alarm Done WakeUp}
unsigned int sleep (unsigned int timer )
{
struct sigaction action;
action.sa_handler=wakeup;
action.sa_flags=0;
sigemptyset(&action.sa_mask);
if(sigaction(SIGALARM,&action,0)==-1)
{
perror(“sigaction”);
return -1;
}
(void) alarm (timer);
(void) pause( );
return 0;
}
INTERVAL TIMERS
The interval timer can be used to schedule a
process to do some tasks at a fixed time interval,
to time the execution of some operations, or to
limit the time allowed for the execution of some
tasks.
The following program illustrates how to set up a real-time clock interval timer using the
alarm API:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#define INTERVAL 5
void callme(int sig_no)
{
alarm(INTERVAL); /*do scheduled tasks*/
}
int main()
{
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_handler=(void(*)( )) callme;
action.sa_flags=SA_RESTART;
if(sigaction(SIGALARM,&action,0)==-1)
{
perror(“sigaction”);
return 1;
}
if(alarm(INTERVAL)==-1)
perror(“alarm”);
else
while(1)
{
/*do normal operation*/
}
return 0;
}
PROCESS ACCOUNTING

• Most UNIX systems provide an option to do process accounting. When enabled,


the kernel writes an accounting record each time a process terminates.

• These accounting records are typically a small amount of binary data with the
name of the command, the amount of CPU time used, the user ID and group ID,
the starting time, and so on.

• A superuser executes accton with a pathname argument to enable accounting.

• The accounting records are written to the specified file, which is usually
/var/account/acct. Accounting is turned off by executing accton without any
arguments.
• The data required for the accounting record, such as CPU times
and number of characters transferred, is kept by the kernel in the
process table and initialized whenever a new process is created, as
in the child after a fork.

• Each accounting record is written when the process terminates.

• This means that the order of the records in the accounting file
corresponds to the termination order of the processes, not the
order in which they were started.

• The accounting records correspond to processes, not programs.

• A new record is initialized by the kernel for the child after a fork,
not when a new program is executed.
The structure of the accounting records is defined in the
header <sys/acct.h> and looks something like
Values for ac_flag from accounting record

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy