Signals and Graceful Shutdown
When you run a daemon on Linux, it is essential that your process can respond to events such as shutdown requests or configuration reloads. This is achieved through Unix signals. Signals are a form of inter-process communication used by the operating system to notify a process that a particular event has occurred. For daemons, the most relevant signals are:
- SIGTERM: sent to request termination. This is the standard way to ask a daemon to shut down;
- SIGINT: sent when you press Ctrl+C in a terminal (less common for daemons, but possible during development or debugging);
- SIGHUP: sent to indicate that the terminal has been closed or, for daemons, often used as a signal to reload configuration without stopping the process.
Handling these signals correctly allows your daemon to shut down gracefully. This means cleaning up resources, saving necessary state, closing files or network connections, and removing any temporary files or locks. Without proper signal handling, a daemon might leave resources in an inconsistent state or become difficult to restart.
1234567891011121314151617181920212223242526272829303132333435363738394041#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> volatile sig_atomic_t running = 1; void cleanup() { // Perform cleanup tasks here printf("Cleaning up resources...\n"); // Example: close files, release locks, free memory } void handle_signal(int sig) { if (sig == SIGTERM || sig == SIGINT || sig == SIGHUP) { printf("Received signal %d, shutting down gracefully.\n", sig); running = 0; } } int main() { struct sigaction sa; sa.sa_handler = handle_signal; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGHUP, &sa, NULL); printf("Daemon running. PID: %d\n", getpid()); while (running) { // Daemon main loop sleep(1); } cleanup(); printf("Daemon exited.\n"); return 0; }
After the loop, the cleanup() function is called. This is where you should release resources, close files, or perform any actions needed to leave the system in a clean state. By handling signals this way, your daemon can respond predictably to shutdown requests or configuration reloads, rather than being killed abruptly. This approach prevents issues such as data corruption, resource leaks, or leaving stale lock files that could prevent the daemon from restarting.
Graceful shutdown is a key aspect of robust daemon design. It ensures that your service can be stopped, restarted, or reconfigured without negative side effects or manual intervention.
¡Gracias por tus comentarios!
Pregunte a AI
Pregunte a AI
Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla
Can you explain how the signal handling works in this code?
What would happen if the daemon received a signal that isn't handled here?
How can I modify the code to reload configuration on SIGHUP?
Genial!
Completion tasa mejorada a 8.33
Signals and Graceful Shutdown
Desliza para mostrar el menú
When you run a daemon on Linux, it is essential that your process can respond to events such as shutdown requests or configuration reloads. This is achieved through Unix signals. Signals are a form of inter-process communication used by the operating system to notify a process that a particular event has occurred. For daemons, the most relevant signals are:
- SIGTERM: sent to request termination. This is the standard way to ask a daemon to shut down;
- SIGINT: sent when you press Ctrl+C in a terminal (less common for daemons, but possible during development or debugging);
- SIGHUP: sent to indicate that the terminal has been closed or, for daemons, often used as a signal to reload configuration without stopping the process.
Handling these signals correctly allows your daemon to shut down gracefully. This means cleaning up resources, saving necessary state, closing files or network connections, and removing any temporary files or locks. Without proper signal handling, a daemon might leave resources in an inconsistent state or become difficult to restart.
1234567891011121314151617181920212223242526272829303132333435363738394041#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> volatile sig_atomic_t running = 1; void cleanup() { // Perform cleanup tasks here printf("Cleaning up resources...\n"); // Example: close files, release locks, free memory } void handle_signal(int sig) { if (sig == SIGTERM || sig == SIGINT || sig == SIGHUP) { printf("Received signal %d, shutting down gracefully.\n", sig); running = 0; } } int main() { struct sigaction sa; sa.sa_handler = handle_signal; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGHUP, &sa, NULL); printf("Daemon running. PID: %d\n", getpid()); while (running) { // Daemon main loop sleep(1); } cleanup(); printf("Daemon exited.\n"); return 0; }
After the loop, the cleanup() function is called. This is where you should release resources, close files, or perform any actions needed to leave the system in a clean state. By handling signals this way, your daemon can respond predictably to shutdown requests or configuration reloads, rather than being killed abruptly. This approach prevents issues such as data corruption, resource leaks, or leaving stale lock files that could prevent the daemon from restarting.
Graceful shutdown is a key aspect of robust daemon design. It ensures that your service can be stopped, restarted, or reconfigured without negative side effects or manual intervention.
¡Gracias por tus comentarios!