117 lines
3.5 KiB
C
117 lines
3.5 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <sys/wait.h>
|
|
|
|
// Global variable with data, needed to communicate with another process.
|
|
struct ping_pong_data_t {
|
|
char const *name;
|
|
pid_t pid_to_print;
|
|
pid_t pid_to_send;
|
|
double delay_seconds;
|
|
} ping_pong_data;
|
|
|
|
// Signal handler for printing PID and sending signal back to another process.
|
|
void do_ping_pong(int signo) {
|
|
if (signo != SIGUSR1) // Protecting from unexpected signals
|
|
return;
|
|
|
|
// Printing some useful info
|
|
printf("[%s] Got signal\n", ping_pong_data.name);
|
|
printf("[%s] Another side PID=%d\n", ping_pong_data.name, ping_pong_data.pid_to_print);
|
|
|
|
|
|
// Sleeping to avoid unreadable spam
|
|
printf("[%s] Sleeping %lf seconds before sending signal\n", ping_pong_data.name, ping_pong_data.delay_seconds);
|
|
usleep((useconds_t) (1000 * 1000 * ping_pong_data.delay_seconds));
|
|
|
|
// Sending signal back
|
|
printf("[%s] Sending signal\n", ping_pong_data.name);
|
|
kill(ping_pong_data.pid_to_send, SIGUSR1);
|
|
}
|
|
|
|
// Global flag to stop infinite loop on interrupt (Ctrl+C)
|
|
volatile int is_running = 1;
|
|
|
|
|
|
// Interrupt (Ctrl+C) handler
|
|
void interrupt(int signo) {
|
|
if (signo != SIGINT) // Protecting from unexpected signals
|
|
return;
|
|
kill(ping_pong_data.pid_to_send, SIGINT);
|
|
is_running = 0;
|
|
}
|
|
|
|
// Entry point
|
|
int main(void) {
|
|
// Obtaining PID of parent (main) process
|
|
pid_t parent_pid = getpid();
|
|
// Obtaining PID of child (forked) process
|
|
pid_t child_pid = fork();
|
|
|
|
|
|
switch (child_pid) {
|
|
case -1:
|
|
perror("Failed to fork\n");
|
|
return EXIT_FAILURE;
|
|
case 0:
|
|
// Obtaining PID of child (forked) process because fork() didn't return it
|
|
child_pid = getpid();
|
|
|
|
// Initializing settings
|
|
ping_pong_data.name = "\033[36mchild\033[0m";
|
|
ping_pong_data.delay_seconds = 1.5;
|
|
ping_pong_data.pid_to_print = parent_pid;
|
|
ping_pong_data.pid_to_send = parent_pid;
|
|
|
|
// Debug info printing
|
|
printf("[%s] My PID=%d\n", ping_pong_data.name, getpid());
|
|
|
|
// Initializing interruption (Ctrl+C) handler
|
|
signal(SIGINT, interrupt);
|
|
|
|
// Initializing communication handler
|
|
signal(SIGUSR1, do_ping_pong);
|
|
|
|
// Eventloop
|
|
while (is_running)
|
|
pause();
|
|
|
|
// Notification about execution finishing
|
|
printf("[%s] Interrupted\n", ping_pong_data.name);
|
|
|
|
return EXIT_SUCCESS;
|
|
default:
|
|
// Initializing settings
|
|
ping_pong_data.name = "\033[31mparent\033[0m";
|
|
ping_pong_data.delay_seconds = 1.5;
|
|
ping_pong_data.pid_to_print = child_pid;
|
|
ping_pong_data.pid_to_send = child_pid;
|
|
|
|
// Debug info printing
|
|
printf("[%s] My PID=%d\n", ping_pong_data.name, getpid());
|
|
|
|
// Initializing interruption (Ctrl+C) handler
|
|
signal(SIGINT, interrupt);
|
|
|
|
// Initializing communication handler
|
|
signal(SIGUSR1, do_ping_pong);
|
|
|
|
// Sending initial signal to start communication chain
|
|
kill(parent_pid, SIGUSR1);
|
|
|
|
|
|
// Eventloop
|
|
while (is_running)
|
|
pause();
|
|
|
|
// Notification about execution finishing
|
|
printf("[%s] Interrupted\n", ping_pong_data.name);
|
|
|
|
// Releasing zombie-process
|
|
waitpid(child_pid, NULL, 0);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
} |