Ch20.15 – sigpending()

 

Ch20.15 – sigpending()
Linux System Programming Β· EmbeddedPathashala
πŸ“‘ Topic 15 of 19
🎯 Beginner–Intermediate
πŸ’» 3 Code Examples
❓ Interview Q&A
πŸ”‘ Key Terms
sigpending() pending signal sigset_t SigPnd /proc/PID/status SIG_IGN SIG_DFL
What is a Pending Signal?

A signal that has been generated (sent to the process) but not yet delivered (acted upon) is called a pending signal. This happens when the signal is currently in the process’s signal mask (blocked).

sigpending() returns the set of signals that are currently pending for the calling process, allowing you to inspect what is waiting to be delivered before you unblock those signals.

πŸ“‹ Function Prototype
#include <signal.h>

int sigpending(sigset_t *set);
/* Returns 0 on success, or -1 on error */

On success, the sigset_t pointed to by set is filled with the set of signals currently pending for the calling process. Use sigismember() to check for individual signals.

πŸ” Pending Signal Lifecycle
Stage Description sigpending() shows it?
Generated Signal sent via kill(), hardware fault, etc. Only if currently blocked
Pending Signal is in the mask β€” waiting to be delivered βœ… YES
Delivered Mask removed β€” signal is handled/ignored/default ❌ NO (no longer pending)
πŸ’» Code Example 1 – Block SIGUSR1, send it, then inspect pending set
/* Demonstrate sigpending() after blocking and sending a signal
   Compile: gcc -o pending_demo pending_demo.c
   Run: ./pending_demo */

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

int main(void)
{
    sigset_t block_set, old_set, pending;

    /* Block SIGUSR1 */
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGUSR1);
    sigprocmask(SIG_BLOCK, &block_set, &old_set);

    /* Send SIGUSR1 to ourselves β€” it will become pending */
    kill(getpid(), SIGUSR1);

    /* Now check what is pending */
    sigpending(&pending);
    if (sigismember(&pending, SIGUSR1))
        printf("SIGUSR1 is PENDING (blocked, not yet delivered)\n");
    else
        printf("SIGUSR1 is NOT pending\n");

    /* Restore old mask β€” SIGUSR1 will be delivered now */
    printf("Restoring mask β€” SIGUSR1 will be delivered next...\n");
    sigprocmask(SIG_SETMASK, &old_set, NULL);
    /* Default action for SIGUSR1 is termination β€” program ends here */
    printf("This line won't print unless SIGUSR1 is caught.\n");
    return 0;
}
πŸ’» Code Example 2 – Print all pending signals
/* Print names of all currently pending signals
   Compile: gcc -o show_pending show_pending.c
   Run: ./show_pending */

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

void print_pending(void)
{
    sigset_t pending;
    int sig;

    if (sigpending(&pending) == -1) {
        perror("sigpending");
        return;
    }

    printf("Pending signals:\n");
    int found = 0;
    for (sig = 1; sig < NSIG; sig++) {
        if (sigismember(&pending, sig)) {
            printf("  [%2d] %s\n", sig, strsignal(sig));
            found = 1;
        }
    }
    if (!found)
        printf("  (none)\n");
}

int main(void)
{
    sigset_t block_all, old;

    /* Block everything so we can inspect */
    sigfillset(&block_all);
    sigprocmask(SIG_BLOCK, &block_all, &old);

    /* Send several signals to ourselves */
    kill(getpid(), SIGUSR1);
    kill(getpid(), SIGUSR2);
    kill(getpid(), SIGTERM);

    print_pending();

    /* Restore β€” signals delivered, process likely terminated */
    sigprocmask(SIG_SETMASK, &old, NULL);
    return 0;
}
πŸ’» Code Example 3 – Discard a pending signal using SIG_IGN
/* Change disposition of a pending signal to SIG_IGN to discard it
   When a pending signal's disposition is set to SIG_IGN, it is
   removed from the pending set and never delivered. */

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

int main(void)
{
    sigset_t block_set, old_set, pending;

    /* Block SIGTERM */
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGTERM);
    sigprocmask(SIG_BLOCK, &block_set, &old_set);

    /* Send SIGTERM to ourselves */
    kill(getpid(), SIGTERM);

    sigpending(&pending);
    printf("SIGTERM pending: %s\n",
           sigismember(&pending, SIGTERM) ? "YES" : "NO");

    /* Ignore SIGTERM β€” this discards the pending instance */
    signal(SIGTERM, SIG_IGN);

    sigpending(&pending);
    printf("After SIG_IGN, SIGTERM pending: %s\n",
           sigismember(&pending, SIGTERM) ? "YES" : "NO");

    /* Restore mask β€” nothing to deliver now */
    sigprocmask(SIG_SETMASK, &old_set, NULL);
    printf("Unblocked. SIGTERM was discarded.\n");
    return 0;
}
Trick: If you change a pending signal’s disposition to SIG_IGN while it is still blocked, the pending signal is silently discarded β€” it will never be delivered even after unblocking.
πŸ–₯️ Checking Pending Signals via /proc

You can inspect pending signals for any process via the filesystem:

cat /proc/$(pidof myprogram)/status | grep Sig
# SigPnd: 0000000000000200   ← per-thread pending
# ShdPnd: 0000000000000000   ← process-wide pending (Linux 2.6+)
# SigBlk: 0000000000000200
# SigIgn: 0000000000000000
# SigCgt: 0000000000000000

The hex value is a bitmask. Bit 1 = signal 1, bit 2 = signal 2, etc. Value 0x200 = bit 9 = SIGKILL… actually signal 10 (SIGUSR1) in this example.

To decode: python3 -c "mask=0x200; [print(i) for i in range(1,32) if mask & (1<<(i-1))]"
❓ Interview Questions
Q1. What does sigpending() return?
It fills a sigset_t with the set of signals that have been generated for the calling process but not yet delivered (because they are currently blocked by the signal mask). Returns 0 on success, -1 on error.
Q2. How can you tell which signals are pending from the command line?
Read /proc/PID/status and look at the SigPnd (per-thread) and ShdPnd (process-wide) fields. They are hex bitmasks β€” bit N-1 being set means signal N is pending.
Q3. Can you prevent a pending signal from ever being delivered?
Yes. While the signal is still blocked (pending), change its disposition to SIG_IGN. The kernel will then discard the pending signal, and it will not be delivered even after unblocking.
Q4. What is the difference between SigPnd and ShdPnd in /proc/PID/status?
SigPnd shows signals pending for a specific thread, while ShdPnd (added in Linux 2.6) shows signals pending for the entire process (sent via kill() to the process group rather than a specific thread). In a single-threaded process, both typically show the same information.

Leave a Reply

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