Ch20.10 โ Null Signal & Process Existence Check
Linux System Programming ยท EmbeddedPathashala
๐ก Topic 10 of 19
๐ฏ Intermediate
๐ป 2 Code Examples
โ Interview Q&A
๐ Key Terms
Null Signal (sig=0) Process Existence ESRCH EPERM Zombie Process PID Recycling /proc/PID
The Null Signal Trick
When you call kill(pid, 0), the kernel does NOT send any signal. Instead it only performs the permission check. This is called the null signal technique.
The result tells you whether the process exists and whether you have permission to signal it โ without disturbing the target process at all.
๐ Interpreting kill(pid, 0) Results
| Return value & errno | Meaning |
|---|---|
| Returns 0 | Process exists AND caller has permission to signal it |
| Returns -1, errno = EPERM | Process exists BUT caller lacks permission |
| Returns -1, errno = ESRCH | Process does NOT exist |
Limitation: Even if kill(pid, 0) returns 0, the process might be a zombie (it has “died” but the parent hasn’t called wait() yet). Also, PID recycling means the same PID might refer to a completely different process by the time you act on the result.
๐ป Code Example 1 โ Check if a Process Exists
/* Use kill(pid, 0) null signal to check process existence
Compile: gcc -o check_pid check_pid.c
Usage: ./check_pid <PID> */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
return 1;
}
pid_t pid = (pid_t)atoi(argv[1]);
/* Send null signal โ no signal is actually sent */
if (kill(pid, 0) == 0) {
printf("PID %d exists and we can signal it.\n", (int)pid);
} else {
if (errno == EPERM)
printf("PID %d exists but we lack permission.\n", (int)pid);
else if (errno == ESRCH)
printf("PID %d does NOT exist.\n", (int)pid);
else
perror("kill");
}
return 0;
}
Try:
./check_pid 1 (init โ exists, EPERM), ./check_pid $$ (your shell โ exists), ./check_pid 999999 (likely ESRCH).๐ป Code Example 2 โ Poll a Process Until It Exits
/* Wait for a process to exit by polling with null signal
Compile: gcc -o wait_exit wait_exit.c
Usage: ./wait_exit <PID> */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
return 1;
}
pid_t pid = (pid_t)atoi(argv[1]);
int checks = 0;
printf("Monitoring PID %d...\n", (int)pid);
while (1) {
if (kill(pid, 0) == -1) {
if (errno == ESRCH) {
printf("PID %d has exited after %d checks.\n",
(int)pid, checks);
break;
} else if (errno == EPERM) {
printf("PID %d exists (no permission). Still alive.\n",
(int)pid);
} else {
perror("kill");
break;
}
} else {
printf("Check %d: PID %d still running.\n",
++checks, (int)pid);
}
sleep(1);
if (checks > 30) {
printf("Gave up after 30 seconds.\n");
break;
}
}
return 0;
}
Warning about zombies: A zombie process still has its PID entry in the kernel table. kill(pid, 0) will return ESRCH for zombies on some systems but succeed on others. The /proc/PID directory is a more reliable check.
๐ Other Techniques to Check Process Existence
| Technique | Works For | Notes |
|---|---|---|
| kill(pid, 0) null signal | Any process | Subject to PID recycling |
| wait() system calls | Child processes only | Most reliable for own children |
| Semaphore / file lock | Cooperating processes | Requires pre-arrangement |
| Pipe (watching write-end close) | Any related process | Elegant for monitoring |
| stat(“/proc/PID”) | Any process | Not affected by PID recycling ambiguity if done carefully |
โ Interview Questions
Q1. What is the null signal and what is it used for?
The null signal is kill(pid, 0) where sig=0. It sends no actual signal but performs the permission check. It is used to test whether a process with a given PID exists and whether the caller has permission to signal it.
Q2. Why is kill(pid, 0) returning 0 not a guarantee that the program you care about is still running?
Two reasons: 1) PID recycling โ the kernel reuses PIDs after a process exits, so the same PID may now belong to a different process. 2) The process might be a zombie โ it has technically exited but still holds its PID entry.
Q3. What is a zombie process?
A zombie is a process that has exited but whose exit status has not yet been collected by the parent via wait(). The process entry remains in the kernel table until the parent reaps it. Its PID is not yet available for recycling.
Q4. How would you check process existence without being affected by PID recycling?
Use a pipe โ the monitored process holds the write end open; the monitor holds the read end. When the write end closes (process exits), read() returns EOF. This is immune to PID recycling because it is tied to the file descriptor, not the PID.
Next Topic โ
raise() and killpg() โ Sending signals to yourself and process groups
