[Linux] signal set and related functions (sigemptyset, sigfillset, sigprocmask)

Table of Contents

  • 1. Signal set
  • 2. Custom signal set related functions
  • 3. sigprocmask function
      • function analysis
      • code example

Orange

1. Signal set

  • A collection of multiple signals is called a signal set, and its system data type is sigset_t.

  • There are two very important signal sets in the PCB, one is called “blocked signal set” and the other is “pending signal set”. Signals are generated but not processed (pending), and all unprocessed signals are stored in a set (pending signal set) in the kernel. The signal in this pending state needs to be processed. Before processing, it needs to be compared with another signal set (blocking signal set). When processing, it is queried with the flag bit in the blocking signal set to see if the signal is blocked. up.

  • The “pending” of a signal is a state, which refers to the period from the generation of the signal to the time before the signal is processed.

  • The “blocking” of a signal is a switch action, which means preventing the signal from being processed, but not preventing the signal from being generated.

  • Signal blocking is to let the system temporarily reserve the signal for later transmission. Since there are other ways to make the system ignore the signal, the blocking of the signal is generally only temporary, just to prevent the signal from interrupting the sensitive operation.

2. Custom signal set related functions

The following signal set-related functions operate on custom signal sets

/*

    int sigemptyset(sigset_t *set);
        - Function: Clear the data in the signal set, and set all the flag positions in the signal set to 0
        - Parameters: set, outgoing parameters, signal set to be operated
        - Return value: success returns 0, failure returns -1

    int sigfillset(sigset_t *set);
        - Function: Set all flags in the signal set to 1
        - Parameters: set, outgoing parameters, signal set to be operated
        - Return value: success returns 0, failure returns -1

    int sigaddset(sigset_t *set, int signum);
        - Function: Set the flag bit corresponding to a signal in the signal set to 1, indicating that the signal is blocked
        - parameters:
            - set: Outgoing parameters, the set of signals that need to be operated
            - signum: The signal that needs to be blocked
        - Return value: success returns 0, failure returns -1

    int sigdelset(sigset_t *set, int signum);
        - Function: Set the flag bit corresponding to a signal in the signal set to 0, indicating that the signal will not be blocked
        - parameters:
            - set: Outgoing parameters, the set of signals that need to be operated
            - signum: Need to set the signal that does not block
        - Return value: success returns 0, failure returns -1

    int sigismember(const sigset_t *set, int signum);
        - Function: determine whether a signal is blocked
        - parameters:
            - set: the set of signals that need to be operated
            - signum: the signal that needs to be judged
        - return value:
            1: signum is blocked
            0 : signum does not block
            -1 : failed

*/

Code Example

#include <signal.h>
#include <stdio.h>

int main() {<!-- -->

    // Create a signal set, some flags may be 1 at the beginning, so the next step needs to be cleared
    sigset_t set;

    // Clear the content of the signal set
    sigemptyset( & amp;set);

    // Determine whether SIGINT is in the signal set set
    int ret = sigismember( & amp; set, SIGINT);
    if(ret == 0) {<!-- -->
        printf("SIGINT does not block\
");
    } else if(ret == 1) {<!-- -->
        printf("SIGINT blocked\
");
    }

    // Add several signals to the signal set
    sigaddset( & set, SIGINT);
    sigaddset( &set, SIGQUIT);

    // Determine whether SIGINT is in the signal set
    ret = sigismember( & amp; set, SIGINT);
    if(ret == 0) {<!-- -->
        printf("SIGINT does not block\
");
    } else if(ret == 1) {<!-- -->
        printf("SIGINT blocked\
");
    }

    // Determine whether SIGQUIT is in the signal set
    ret = sigismember( & amp; set, SIGQUIT);
    if(ret == 0) {<!-- -->
        printf("SIGQUIT does not block\
");
    } else if(ret == 1) {<!-- -->
        printf("SIGQUIT blocked\
");
    }

    // remove a signal from the signal set
    sigdelset( &set, SIGQUIT);

    // Determine whether SIGQUIT is in the signal set
    ret = sigismember( & amp; set, SIGQUIT);
    if(ret == 0) {<!-- -->
        printf("SIGQUIT does not block\
");
    } else if(ret == 1) {<!-- -->
        printf("SIGQUIT blocked\
");
    }

    return 0;
}

3, sigprocmask function

Function Analysis

/*
    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
        - Function: Set the data in the custom signal set to the kernel (set blocking, unblocking, replacement)
        - parameters:
            - how : How to handle the kernel blocking signal set
                SIG_BLOCK: Add the blocking signal set set by the user to the kernel, and the original data in the kernel remains unchanged
                    Assuming the default blocking signal set in the kernel is mask, mask | set
                SIG_UNBLOCK: According to the data set by the user, unblock the data in the kernel
                    mask & amp;= ~set (that is, first negate set, and then bitwise AND with mask), assuming that the default blocking signal set in the kernel is mask
                SIG_SETMASK: Overwrite the original value in the kernel
            
            - set : User-defined signal set that has been initialized
            - oldset : saves the state of the blocking signal set in the kernel before setting, can be NULL
        - return value:
            Success: 0
            Failed: -1
                Set error numbers: EFAULT, EINVAL

    int sigpending(sigset_t *set);
        - Function: Get the pending signal set in the kernel
        - Parameters: set, the outgoing parameter, saves the information in the pending signal set in the kernel.
*/

Code Example

The code first defines the signal set set and puts the SIGINT and SIGQUIT signals into it. Then the set of blocking signals in the kernel is modified through the sigprocmask function. Then an infinite loop is set, a signal set pendingset is created in the loop, and the data of the current pending signal set is put into the pendingset, and then the first 31 bits of the signal set are traversed.

When you run the program, the first output will be 0, and then press ctrl + c before looping 10 times, and the second digit printed will change from 0 to 1 (in fact, when you press ctrl + c , which means sending a SIGINT signal to the system, but the signal has been set to 1 in the blocking signal set in the kernel through the above operation, so when the system receives the signal, it will also block, so the signal status is unavailable decision, the second bit (representing SIGINT) of the printed pending signal set becomes 1).

After 10 cycles, the blockage is unblocked. Before pressing ctrl + c, there is no way to stop the infinite loop, but after pressing ctrl + c and looping 10 times, the infinite loop will automatically stop, because after the program is set 10 times, the signal blocking we set before is released, and the system is no longer The previously sent SIGINT signal is blocked, so the SIGINT signal does its thing and stops the process.

// Write a program to print the pending status of all regular signals (1-31) to the screen
// Set some signals to be blocked, and generate these signals through the keyboard

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

int main() {<!-- -->

    // Set signal No. 2 and No. 3 to block
    sigset_t set;
    sigemptyset( & amp;set);
    // Add signals No. 2 and No. 3 to the signal set
    sigaddset( & set, SIGINT);
    sigaddset( &set, SIGQUIT);

    // Modify the set of blocking signals in the kernel
    sigprocmask(SIG_BLOCK, & set, NULL);

    int num = 0;

    while(1) {<!-- -->
        num++;
        // Get the data of the current pending signal set
        sigset_t pendingset;
        sigemptyset( &pendingset);
        sigpending( &pendingset);

        // traverse the first 32 bits
        for(int i = 1; i <= 31; i ++ ) {<!-- -->
            if(sigismember( & amp;pendingset, i) == 1) {<!-- -->
                printf("1");
            }else if(sigismember( & amp;pendingset, i) == 0) {<!-- -->
                printf("0");
            } else {<!-- -->
                perror("sigismember");
                exit(0);
            }
        }

        printf("\
");
        sleep(1);
        if(num == 10) {<!-- -->
            // unblock
            sigprocmask(SIG_UNBLOCK, & set, NULL);
        }

    }

    return 0;
}