Signal Processing in Linux

Source: Internet
Author: User
Tags sigint signal
Linux Signal Processing-general Linux technology-Linux programming and kernel information. The following is a detailed description. In this chapter, we will discuss the signal processing functions in Linux.
Signal processing functions in Linux:
Signal Generation
Signal Processing
Other Signal Functions
One instance
1. Signal Generation
The signals in Linux are similar to those in dos int or Windows. A trusted signal is sent to the corresponding process when a signal occurs. There are several signals in Linux. We can use the kill-l command to obtain the following output results:

1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR

For a detailed explanation of these signals, see the output result of man 7 signal. There are two sources for the occurrence of signal events: one is the cause of hardware (for example, we press the keyboard) and the other is the cause of software (for example, we use system functions or commands to send signals ). The four most commonly used system functions are kill, raise, alarm, and setimer. The setitimer function is used in the timer chapter.
# Include
# Include
# Include

Int kill (pid_t pid, int sig );
Int raise (int sig );
Unisigned int alarm (unsigned int seconds );

The kill system call sends signal sig to the process.
If the pid is positive, the signal sig is sent to the process pid.
If the pid is equal to 0, the signal sig is sent to the process in the same process group as the pid process.
If the pid is equal to-1, the signal is sent to all processes in the progress table, except the process number at the maximum.
If the pid is-1, it is the same as 0, but the sending process group is-pid.
The first case is the most used. Do you still remember the example in the daemon section? At that time, we used this function to kill the creation of the parent process daemon.
The raise system call sends a sig signal to itself. We can use the above function to implement this function.
The alarm function has a relationship with time. This function can send a SIGALRM signal to itself after seconds. What will be the result of this function?

# Include

Main ()
{
Unsigned int I;
Alarm (1 );
For (I = 0; 1; I ++)
Printf ("I = % d", I );
}
The default operation of SIGALRM is to terminate the process, so the program will end in 1 second. You can see how much your last I value is, to compare the differences in system performance (I am using 2232 ).

2. signal operation
Sometimes we want the process to be correctly executed, rather than being affected by the signal. For example, we want the above program to not end after one second. At this time, we need to perform signal operations.
Signal shielding is the most common method for signal operations. The following functions are used for signal shielding.
# Include

Int sigemptyset (sigset_t * set );
Int sigfillset (sigset_t * set );
Int sigaddset (sigset_t * set, int signo );
Int sigdelset (sigset_t * set, int signo );
Int sigismember (sigset_t * set, int signo );
Int sigprocmask (int how, const sigset_t * set, sigset_t * oset );

The sigemptyset function initializes the signal set and sets it to null. Sigfillset also initializes the signal set, but sets the signal set to the set of all signals. The sigaddset adds the signal signo to the signal set, and the sigdelset deletes the signal from the signal set. Sigismember checks whether the signal is in the signal set.
Sigprocmask is the most critical function. Set the signal set before use. This function is used to add the specified signal set to the signal blocking set of the process. If the oset is provided, the current process signal blocking set will be saved in the oset. The parameter how determines the function operation method.
SIG_BLOCK: adds a signal set to the blocking set of the current process.
SIG_UNBLOCK: deletes a signal set from the current blocking set.
SIG_SETMASK: sets the current signal set as a signal blocking set.
Use these functions as an example.

# Include
# Include
# Include
# Include

Int main (int argc, char ** argv)
{
Double y;
Sigset_t intmask;
Int I, repeat_factor;

If (argc! = 2)
{
Fprintf (stderr, "Usage: % s repeat_factor \ n \ a", argv [0]);
Exit (1 );
}

If (repeat_factor = atoi (argv [1]) <1) repeat_factor = 10;
Sigemptyset (& intmask);/* set the signal set to null */
Sigaddset (& intmask, SIGINT);/* Add the Ctrl + C signal to interrupt */
While (1)
{
/* Blocking signal. We do not want to save the original set. Therefore, the parameter is NULL */
Sigprocmask (SIG_BLOCK, & intmask, NULL );
Fprintf (stderr, "SIGINT signal blocked \ n ");
For (I = 0; I
Fprintf (stderr, "Blocked calculation is finished \ n ");
/* Cancel blocking */
Sigprocmask (SIG_UNBLOCK, & intmask, NULL );
Fprintf (stderr, "SIGINT signal unblocked \ n ");
For (I = 0; I
Fprintf (stderr, "Unblocked calculation is finished \ n ");
}
Exit (0 );
}

When the program is running, we need to use Ctrl + C to end. If we send a SIGINT signal during the first calculation, the program does not reflect it because the signal has been blocked. The program ends only when the signal is blocked. Note that we only need to send a SIGINT signal once, because the signal shielding only adds the signal to the signal blocking set and does not discard the signal. Once the signal shielding is canceled, this signal will take effect.
Sometimes we want to reflect the signal in a timely manner. For example, when we press Ctrl + C, we don't want to do anything. We want to tell the user that this operation is not good, do not try again. In this case, we need to use the sigaction function.
# Include

Int sigaction (int signo, const struct sigaction * act,
Struct sigaction * oact );

Struct sigaction {
Void (* sa_handler) (int signo );
Void (* sa_sigaction) (int siginfo_t * info, void * act );
Sigset_t sa_mask;
Int sa_flags;
Void (* sa_restore) (void );
}

Is this function and structure a little scary. Don't be scared. In fact, this function is quite simple to use. Let's first explain the meaning of each parameter. Signo is simply the signal we want to process. It can be any legitimate signal. Two signals are unavailable (SIGKILL and SIGSTOP ). Act contains information about how to process this signal. Oact is simpler than the previous processing information for this function. It is mainly used to save information. It is okay to use NULL.
The signal structure is a bit complicated. It doesn't matter if we study it slowly.
Sa_handler is a function pointer pointing to a function, which has a parameter. This function is the function for signal operations. Sa_sigaction, sa_restore and sa_handler are similar, but the parameters are different. These two elements are rarely used.
Sa_flags is used to set various signal operations. It is generally set to 0. We have learned sa_mask.
We can use sa_handler to point to one of our signal operation functions. Sa_handler has two special values: SIG_DEL and SIG_IGN. SIG_DEL is the default signal operation function, while SIG_IGN is the operation function that ignores the signal.
This function is complex. We use an instance to describe it. The following function captures the user's CTRL + C signal. And output a prompt statement.

# Include
# Include
# Include
# Include
# Include

# Define PROMPT "do you want to terminate the program? "

Char * prompt = PROMPT;

Void ctrl_c_op (int signo)
{
Write (STDERR_FILENO, prompt, strlen (prompt ));
}

Int main ()
{
Struct sigaction act;

Act. sa_handler = ctrl_c_op;
Sigemptyset (& act. sa_mask );
Act. sa_flags = 0;
If (sigaction (SIGINT, & act, NULL) <0)
{
Fprintf (stderr, "Install Signal Action Error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
While (1 );
}

In the signal operation function of the above program, we use the write function instead of the fprintf function. This is because we need to consider the following situation. If another signal occurs during signal operations, how should the program run? To process the signal when the signal processing function is running, we need to set the sa_mask member. We add the signals we want to shield to the sa_mask structure so that these functions will be blocked during signal processing.
3. Other Signal Functions
As signal operations and processing are complex, we will introduce several signal operation functions.
# Include
# Include

Int pause (void );
Int sigsuspend (const sigset_t * sigmask );

The pause function is simple, that is, to suspend the process until a signal occurs. While sigsuspend is also a pending process, it only replaces the current signal blocking set with sigmask during the call.
# Include

Int sigsetjmp (sigjmp_buf env, int val );
Void siglongjmp (sigjmp_buf env, int val );

Do you still remember the goto functions, setjmp and longjmp functions. These two signal jump functions can also implement program jump so that we can jump from the function to what we need.
Since the above functions are rarely met, we just explained them. For details, please refer to the online help.
4. One instance
Do you still remember which program we created in the daemon process? Here we will strengthen the daemon program. The following program can also check users' emails. However, a switch is provided. If you do not want the program to prompt for a new email, you can send a SIGUSR2 signal to the program. If you want the program to provide a prompt, you can send a SIGUSR1 signal.

# Include
# Include
# Include
# Include
# Include
# Include
# Include

# Include
# Include

/* The personal email address of Linux users is/var/spool/mail /*/

# Define MAIL_DIR "/var/spool/mail /"

/* Sleep for 10 seconds */

# Define SLEEP_TIME 10
# Define MAX_FILENAME 255

Unsigned char policyflag = 1;

Long get_file_size (const char * filename)
{
Struct stat buf;

If (stat (filename, &; buf) =-1)
{
If (errno = ENOENT) return 0;
Else return-1;
}
Return (long) buf. st_size;
}

Void send_mail_notify (void)
{
Fprintf (stderr, "New mail has arrived \ 007 \ n ");
}

Void turn_on_notify (int signo)
{
Notifyflag = 1;
}

Void turn_off_notify (int signo)
{
Notifyflag = 0;
}

Int check_mail (const char * filename)
{
Long old_mail_size, new_mail_size;
Sigset_t blockset, emptyset;

Sigemptyset (&; blockset );
Sigemptyset (&; emptyset );
Sigaddset (&; blockset, SIGUSR1 );
Sigaddset (&; blockset, SIGUSR2 );

Old_mail_size = get_file_size (filename );
If (old_mail_size <0) return 1;
If (old_mail_size> 0) send_mail_y y ();
Sleep (SLEEP_TIME );

While (1)
{
If (sigprocmask (SIG_BLOCK, &; blockset, NULL) <0) return 1;
While (policyflag = 0) sigsuspend (&; emptyset );
If (sigprocmask (SIG_SETMASK, &; emptyset, NULL) <0) return 1;
New_mail_size = get_file_size (filename );
If (new_mail_size> old_mail_size) send_mail_notify;
Old_mail_size = new_mail_size;
Sleep (SLEEP_TIME );
}
}

Int main (void)
{
Char mailfile [MAX_FILENAME];
Struct sigaction newact;
Struct passwd * pw;

If (pw = getpwuid (getuid () = NULL)
{
Fprintf (stderr, "Get Login Name Error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
Strcpy (mailfile, MAIL_DIR );
Strcat (mailfile, pw-> pw_name );
Newact. sa_handler = turn_on_policy;
Newact. sa_flags = 0;
Sigemptyset (&; newact. sa_mask );
Sigaddset (&; newact. sa_mask, SIGUSR1 );
Sigaddset (&; newact. sa_mask, SIGUSR2 );
If (sigaction (SIGUSR1, &; newact, NULL) <0)
Fprintf (stderr, "Turn On Error: % s \ n \ a", strerror (errno ));
Newact. sa_handler = turn_off_policy;
If (sigaction (SIGUSR1, &; newact, NULL) <0)
Fprintf (stderr, "Turn Off Error: % s \ n \ a", strerror (errno ));
Check_mail (mailfile );
Exit (0 );
}

Signal operation is a very complicated task, and it is more complicated than we think. If you want to thoroughly understand the problems of signal operation, in addition to a large number of exercises, you need to read more online manuals. However, if we just use it in general, it would be similar to the above functions. We will introduce it here.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.