Ch20.4 โ€“ Signal Mask & Blocking

 

Ch20.4 โ€“ Signal Mask & Blocking
Linux System Programming ยท EmbeddedPathashala
๐Ÿ“ก Topic 4 of 19
๐ŸŽฏ Intermediate
๐Ÿ’ป 3 Code Examples
โ“ Interview Q&A
๐Ÿ”‘ Key Terms
Signal Mask sigprocmask() SIG_BLOCK SIG_UNBLOCK SIG_SETMASK Critical Section SIGKILL SIGSTOP
What is the Signal Mask?

Every Linux process has a signal mask โ€” a set of signals whose delivery is currently blocked. When a signal is in the mask, the kernel will not deliver it, even if the signal is generated. The signal just waits as pending.

Think of the signal mask like a “do not disturb” list. Signals on the list are held at the door until you remove them from the list.

The signal mask is a per-process (and in multithreaded programs, per-thread) property. You manipulate it with sigprocmask().

๐Ÿ”ง sigprocmask() โ€” Three Operations
how value Effect on Signal Mask
SIG_BLOCK ADD the signals in set to the current mask (union)
SIG_UNBLOCK REMOVE the signals in set from the current mask
SIG_SETMASK REPLACE the entire mask with set
Note: SIGKILL and SIGSTOP can never be added to the signal mask. If you try, sigprocmask() silently ignores those signals with no error.
๐Ÿ’ป Code Example 1 โ€“ Block SIGINT During a Critical Section

The classic use case: block a signal before entering code that must not be interrupted, then restore the old mask after.

/* Block SIGINT during a critical section
   Compile: gcc -o mask_demo mask_demo.c
   Run: ./mask_demo  โ€” try Ctrl+C during the "critical work" */

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

int main(void)
{
    sigset_t block_set, prev_mask;

    /* Build a set containing only SIGINT */
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGINT);

    /* Block SIGINT; save previous mask in prev_mask */
    sigprocmask(SIG_BLOCK, &block_set, &prev_mask);
    printf("Entering critical section (SIGINT blocked)...\n");
    printf("Press Ctrl+C โ€” it will be ignored until we exit.\n");

    /* === CRITICAL SECTION โ€” signal cannot interrupt here === */
    int i;
    for (i = 0; i < 5; i++) {
        printf("Critical work step %d\n", i + 1);
        sleep(1);
    }
    /* === END CRITICAL SECTION === */

    printf("Exiting critical section. Restoring signal mask.\n");

    /* Restore the old mask โ€” if SIGINT was pending it fires NOW */
    sigprocmask(SIG_SETMASK, &prev_mask, NULL);

    printf("Signal mask restored. Normal operation.\n");
    sleep(3);

    return 0;
}
๐Ÿ’ป Code Example 2 โ€“ Block Multiple Signals at Once
/* Block both SIGINT and SIGTERM simultaneously
   Compile: gcc -o multi_block multi_block.c */

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

int main(void)
{
    sigset_t block_set;

    sigemptyset(&block_set);
    sigaddset(&block_set, SIGINT);   /* Ctrl+C */
    sigaddset(&block_set, SIGTERM);  /* kill command default */
    sigaddset(&block_set, SIGHUP);   /* terminal hangup */

    sigprocmask(SIG_BLOCK, &block_set, NULL);

    printf("SIGINT, SIGTERM, SIGHUP are all blocked.\n");
    printf("Try: kill -SIGTERM %d from another terminal.\n", getpid());
    printf("Sleeping 8 seconds...\n");
    sleep(8);

    /* Unblock all three */
    sigprocmask(SIG_UNBLOCK, &block_set, NULL);
    printf("Signals unblocked. Pending ones fire now.\n");
    sleep(2);

    return 0;
}
๐Ÿ’ป Code Example 3 โ€“ Block ALL Signals (except SIGKILL/SIGSTOP)
/* Block every blockable signal using sigfillset()
   SIGKILL and SIGSTOP cannot be blocked โ€” kernel ignores
   attempts to block them silently.
   Compile: gcc -o block_all block_all.c */

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

int main(void)
{
    sigset_t full_set;

    /* sigfillset fills set with ALL signals */
    sigfillset(&full_set);

    /* Attempt to block all โ€” SIGKILL and SIGSTOP are ignored */
    sigprocmask(SIG_BLOCK, &full_set, NULL);

    printf("All blockable signals are now blocked.\n");
    printf("Ctrl+C (SIGINT) won't work. SIGTERM won't work.\n");
    printf("But kill -9 (SIGKILL) WILL still kill this process!\n");
    printf("Try: kill -9 %d\n", getpid());

    sleep(10);

    printf("Done. Unblocking all signals.\n");
    sigprocmask(SIG_UNBLOCK, &full_set, NULL);

    return 0;
}
Key rule: SIGKILL and SIGSTOP can NEVER be blocked, ignored, or caught. They are the “sure kill” and “sure stop” signals โ€” the kernel always handles them directly.
โ“ Interview Questions
Q1. What is the signal mask of a process?
The signal mask is a set of signals whose delivery is currently blocked for a process. When a signal is in the mask, the kernel will not deliver it even if it is generated โ€” the signal becomes pending instead.
Q2. What are the three operations of sigprocmask() and what does each do?
SIG_BLOCK: adds signals to the current mask (union). SIG_UNBLOCK: removes signals from the mask. SIG_SETMASK: replaces the entire mask with the new set.
Q3. Why would you block a signal before a critical section of code?
To prevent the signal handler from interrupting code that must run atomically โ€” for example, code modifying shared data structures. Without blocking, the handler could run in the middle and leave data in an inconsistent state.
Q4. Which two signals can never be blocked? Why?
SIGKILL and SIGSTOP. They cannot be blocked, ignored, or caught. This is by design โ€” they give the system administrator (or kernel) an unconditional way to terminate or stop any process, regardless of what the process is doing.
Q5. What happens when you unblock a signal that has been pending?
The pending signal is delivered immediately. SUSv3 specifies that at least one pending signal from the unblocked set will be delivered before sigprocmask() returns.
Q6. How do you safely block a signal and restore the old mask afterward?
Pass the oldset argument to sigprocmask(SIG_BLOCK, …, &prev_mask) to save the old mask. After the critical section, call sigprocmask(SIG_SETMASK, &prev_mask, NULL) to restore it exactly as it was.
Next Topic โ†’

Signal Dispositions โ€“ What actions can a process take when a signal arrives?

Next: Signal Dispositions โ†’ โ† Previous

Leave a Reply

Your email address will not be published. Required fields are marked *