diff --git a/exercises/README.md b/exercises/README.md index 8f48182..8e24526 100644 --- a/exercises/README.md +++ b/exercises/README.md @@ -75,6 +75,21 @@ This is an organized list of all exercises completed so far, including a brief d --- +## 🚦 signal_handler + +**Description**: A C program demonstrating robust signal handling for `SIGINT` and `SIGUSR1` using `sigaction` with `SA_SIGINFO`. + +- 📄 [README](signal_handler/README.md) +- 📂 Directory: `signal_handler/` +- ✅ Features: + - Handles `SIGINT` up to three times before exiting + - Handles `SIGUSR1` with a simple message + - Masks signals during handler execution to avoid reentrancy issues + - Includes comments and clear separation of handler logic + - Makefile included with standard targets + +--- + ## 🔧 Tooling & Automation **Shared tools and scripts used across projects**: diff --git a/exercises/signal_handler/Makefile b/exercises/signal_handler/Makefile new file mode 100644 index 0000000..9a1a7e3 --- /dev/null +++ b/exercises/signal_handler/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CFLAGS = -Wall -Wextra -O2 +TARGET = signal_handler +SRC = main.c + +all: $(TARGET) + +$(TARGET): $(SRC) + $(CC) $(CFLAGS) -o $(TARGET) $(SRC) + +clean: + rm -f $(TARGET) diff --git a/exercises/signal_handler/README.md b/exercises/signal_handler/README.md new file mode 100644 index 0000000..1b8a978 --- /dev/null +++ b/exercises/signal_handler/README.md @@ -0,0 +1,55 @@ +# Signal Handler + +## Overview + +This project demonstrates how to handle UNIX signals in C using `sigaction`. +It specifically intercepts **SIGINT** and **SIGUSR1** and prints messages when these signals are received. + +--- + +## Features + +- Intercepts **SIGINT** (usually generated with `Ctrl + C`) and **SIGUSR1**`. +- Prints a custom message for each signal. +- Tracks the number of `SIGINT` signals received and terminates after a defined count. +- Demonstrates proper use of: + - `sigaction()` instead of `signal()` for consistent behavior. + - `volatile sig_atomic_t` for safe signal state handling. + +--- + +## Build + +```bash +make +``` + +--- + +## Run + +```bash +./signal_handler +``` + +--- + +## Test + +- Open another terminal and run: + +```bash +kill -USR1 +``` + +where `` is the process ID of `signal_handler`. + +- Press `Ctrl + C` in the terminal running the program to send `SIGINT`. + +--- + +## Clean + +```bash +make clean +``` diff --git a/exercises/signal_handler/main.c b/exercises/signal_handler/main.c new file mode 100644 index 0000000..166c59c --- /dev/null +++ b/exercises/signal_handler/main.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +volatile sig_atomic_t sigint_caught = 0; + +void signal_handler(int signo, siginfo_t *si, void *ucontext) +{ + (void)si; + (void)ucontext; + + if (signo == SIGINT) { + sigint_caught += 1; + if (write(STDOUT_FILENO, "Caught SIGINT signal\n", 22) == -1) { + _exit(EXIT_FAILURE); + } + if (sigint_caught >= 3) { + if (write(STDOUT_FILENO, "Reach SIGINT limit\n", 20) == + -1) { + _exit(EXIT_FAILURE); + } + _exit(EXIT_FAILURE); + } + } else if (signo == SIGUSR1) { + if (write(STDOUT_FILENO, "Caught SIGUSR1 signal\n", 23) == -1) { + _exit(EXIT_FAILURE); + } + } else { + if (write(STDOUT_FILENO, "Unknown signal\n", 16) == -1) { + _exit(EXIT_FAILURE); + } + } +} + +int main(void) +{ + struct sigaction action; + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGINT); + sigaddset(&action.sa_mask, SIGUSR1); + action.sa_sigaction = signal_handler; + action.sa_flags = SA_SIGINFO; + + if (sigaction(SIGINT, &action, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + if (sigaction(SIGUSR1, &action, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } + + printf("Hi, I'm process with PID %d\n", getpid()); + for (;;) + pause(); + return EXIT_SUCCESS; +}