Handling Standard Signals
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void signal_handler(int sig_num) {
if (sig_num == SIGINT) {
printf("Ctrl+C signal received\n");
}
}
int main(void) {
// Set SIGINT to be ignored
if (signal(SIGINT, SIG_IGN) == SIG_ERR) {
perror("Failed to set SIG_IGN");
exit(EXIT_FAILURE);
}
// Restore default behavior for SIGINT
if (signal(SIGINT, SIG_DFL) == SIG_ERR) {
perror("Failed to set SIG_DFL");
exit(EXIT_FAILURE);
}
// Assign custom handler to SIGINT
if (signal(SIGINT, signal_handler) == SIG_ERR) {
perror("Failed to set custom handler");
exit(EXIT_FAILURE);
}
while (1) {
printf("Program is running...\n");
sleep(2);
}
return 0;
}
Attempting to Modify SIGKILL Behavior
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void custom_handler(int sig_num) {
if (sig_num == SIGINT) {
printf("Interrupt signal caught\n");
}
if (sig_num == SIGKILL) {
printf("SIGKILL signal intercepted\n");
}
}
int main(void) {
// These calls will fail as SIGKILL cannot be caught or ignored
if (signal(SIGKILL, SIG_IGN) == SIG_ERR) {
perror("Cannot ignore SIGKILL");
}
if (signal(SIGKILL, custom_handler) == SIG_ERR) {
perror("Cannot handle SIGKILL");
}
if (signal(SIGKILL, SIG_DFL) == SIG_ERR) {
perror("Cannot set SIGKILL default");
}
while (1) {
printf("Process active\n");
sleep(3);
}
return 0;
}
Reaping Zombie Processes Using SIGCHLD
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
void child_handler(int sig_num) {
if (sig_num == SIGCHLD) {
// Reap all terminated child processes
while (waitpid(-1, NULL, WNOHANG) > 0) {
// Continue until no more children to reap
}
}
}
int main(void) {
if (signal(SIGCHLD, child_handler) == SIG_ERR) {
perror("Failed to set SIGCHLD handler");
exit(EXIT_FAILURE);
}
// Create multiple child processes
for (int i = 0; i < 8; i++) {
pid_t child_pid = fork();
if (child_pid == 0) {
// Child process
sleep(2);
exit(0);
}
}
// Parent process continues
while (1) {
pause(); // Wait for signals
}
return 0;
}
Simulating a Card Game with Alarm Signals
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void alarm_handler(int sig_num) {
if (sig_num == SIGALRM) {
printf("System played a random card\n");
alarm(5); // Reset alarm
}
}
int main(void) {
if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
perror("Failed to set alarm handler");
exit(EXIT_FAILURE);
}
alarm(5); // Initial alarm
char user_card;
while (1) {
printf("Enter your card: ");
scanf("%c", &user_card);
getchar(); // Consume newline
printf("You played: %c\n", user_card);
alarm(5); // Reset timer after user input
}
return 0;
}
Testing Signal Tranmsission Functions
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void user_signal_handler(int sig_num) {
if (sig_num == SIGUSR1) {
printf("Received SIGUSR1\n");
raise(SIGKILL); // Self-terminate
}
}
int main(void) {
if (signal(SIGUSR1, user_signal_handler) == SIG_ERR) {
perror("Failed to set SIGUSR1 handler");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid > 0) {
// Parent process
while (1) {
printf("Parent process alive\n");
sleep(2);
}
} else if (pid == 0) {
// Child process
sleep(5);
printf("Child process declaring independence\n");
kill(getpid(), SIGUSR1); // Send signal to self
// This code won't execute due to SIGKILL
while (1) {
printf("Child continues\n");
sleep(2);
}
}
return 0;
}
Implementing Message Queues
Message Sender
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
struct message_buffer {
long msg_type;
char msg_content[1024];
};
#define MSG_DATA_SIZE (sizeof(struct message_buffer) - sizeof(long))
int main(void) {
key_t queue_key;
if ((queue_key = ftok("/tmp", 'A')) == -1) {
perror("ftok failed");
exit(EXIT_FAILURE);
}
printf("Generated key: 0x%x\n", queue_key);
int queue_id;
if ((queue_id = msgget(queue_key, IPC_CREAT | 0666)) == -1) {
perror("msgget failed");
exit(EXIT_FAILURE);
}
printf("Queue ID: %d\n", queue_id);
struct message_buffer send_buf;
while (1) {
memset(send_buf.msg_content, 0, sizeof(send_buf.msg_content));
printf("Enter message type: ");
scanf("%ld", &send_buf.msg_type);
getchar();
printf("Enter message: ");
fgets(send_buf.msg_content, sizeof(send_buf.msg_content), stdin);
send_buf.msg_content[strlen(send_buf.msg_content) - 1] = '\0';
if (msgsnd(queue_id, &send_buf, MSG_DATA_SIZE, 0) == -1) {
perror("msgsnd failed");
exit(EXIT_FAILURE);
}
printf("Message sent\n");
if (strcmp(send_buf.msg_content, "exit") == 0) {
break;
}
}
return 0;
}
Message Receiver
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
struct message_buffer {
long msg_type;
char msg_content[1024];
};
#define MSG_DATA_SIZE (sizeof(struct message_buffer) - sizeof(long))
int main(void) {
key_t queue_key;
if ((queue_key = ftok("/tmp", 'A')) == -1) {
perror("ftok failed");
exit(EXIT_FAILURE);
}
printf("Generated key: 0x%x\n", queue_key);
int queue_id;
if ((queue_id = msgget(queue_key, IPC_CREAT | 0666)) == -1) {
perror("msgget failed");
exit(EXIT_FAILURE);
}
printf("Queue ID: %d\n", queue_id);
struct message_buffer recv_buf;
while (1) {
memset(recv_buf.msg_content, 0, sizeof(recv_buf.msg_content));
if (msgrcv(queue_id, &recv_buf, MSG_DATA_SIZE, 1, 0) == -1) {
perror("msgrcv failed");
exit(EXIT_FAILURE);
}
printf("Received: %s\n", recv_buf.msg_content);
if (strcmp(recv_buf.msg_content, "exit") == 0) {
break;
}
}
return 0;
}