Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Signal Handling and Message Queue Implementation in C

Tech 2

Signal Handling Mechanisms

Default, Ignore, and Custom Signal Handlers

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void custom_signal_handler(int sig_num) {
    if (sig_num == SIGINT) {
        printf("Received SIGINT signal (Ctrl+C)\n");
    }
}

int main() {
    // Ignore SIGINT signal
    if (signal(SIGINT, SIG_IGN) == SIG_ERR) {
        perror("signal configuration failed");
        return EXIT_FAILURE;
    }

    /*
    // Restore default SIGINT handler
    if (signal(SIGINT, SIG_DFL) == SIG_ERR) {
        perror("signal configuration failed");
        return EXIT_FAILURE;
    }

    // Set custom SIGINT handler
    if (signal(SIGINT, custom_signal_handler) == SIG_ERR) {
        perror("signal configuration failed");
        return EXIT_FAILURE;
    }
    */

    while (1) {
        printf("Running...\n");
        sleep(1);
    }

    return EXIT_SUCCESS;
}

SIGCHLD Signal for Zombie Process Cleanup

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>

void child_signal_handler(int sig_num) {
    if (sig_num == SIGCHLD) {
        while (waitpid(-1, NULL, WNOHANG) > 0) {
            // Child process reaped
        }
    }
}

int main() {
    // Configure SIGCHLD handler
    if (signal(SIGCHLD, child_signal_handler) == SIG_ERR) {
        perror("signal configuration failed");
        return EXIT_FAILURE;
    }

    // Create child processes
    for (int i = 0; i < 5; i++) {
        pid_t child_pid = fork();
        if (child_pid == 0) {
            // Child process
            sleep(1);
            exit(EXIT_SUCCESS);
        }
    }

    // Parent process continues
    while (1) {
        pause();
    }

    return EXIT_SUCCESS;
}

Timer-Based Signal Simulatoin

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void timer_handler(int sig_num) {
    if (sig_num == SIGALRM) {
        printf("System generated a card\n");
        alarm(5);  // Reset timer
    }
}

int main() {
    // Set SIGALRM handler
    if (signal(SIGALRM, timer_handler) == SIG_ERR) {
        perror("signal configuration failed");
        return EXIT_FAILURE;
    }

    alarm(5);  // Start initial timer

    char user_input;
    while (1) {
        printf("Enter your card: ");
        scanf("%c", &user_input);
        getchar();  // Clear newline

        printf("You played: %c\n", user_input);
        alarm(5);  // Reset timer after user action
    }

    return EXIT_SUCCESS;
}

Inter-Process Signal Communication

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

void user_signal_handler(int sig_num) {
    if (sig_num == SIGUSR1) {
        printf("Dynasty has fallen\n");
        raise(SIGKILL);
    }
}

int main() {
    // Configure SIGUSR1 handler
    if (signal(SIGUSR1, user_signal_handler) == SIG_ERR) {
        perror("signal configuration failed");
        return EXIT_FAILURE;
    }

    pid_t process_id = fork();

    if (process_id > 0) {
        // Parent process
        while (1) {
            printf("This is my kingdom\n");
            sleep(1);
        }
    } else if (process_id == 0) {
        // Child process
        sleep(3);
        printf("I am the true emperor\n");
        kill(getppid(), SIGUSR1);
        while (1) {
            printf("Now it's my turn\n");
            sleep(1);
        }
    } else {
        perror("fork failed");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Message Queue Implementation

Message Sender Program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>

struct message_structure {
    long message_type;
    char message_content[1024];
};

#define MESSAGE_CONTENT_SIZE (sizeof(struct message_structure) - sizeof(long))

int main() {
    // Generate key
    key_t queue_key;
    if ((queue_key = ftok("/", 'm')) == -1) {
        perror("ftok failed");
        return EXIT_FAILURE;
    }
    printf("Generated key: 0x%x\n", queue_key);

    // Create message queue
    int queue_id;
    if ((queue_id = msgget(queue_key, IPC_CREAT | 0664)) == -1) {
        perror("msgget failed");
        return EXIT_FAILURE;
    }
    printf("Queue ID: 0x%x\n", queue_id);

    struct message_structure outgoing_message;

    while (1) {
        memset(outgoing_message.message_content, 0, sizeof(outgoing_message.message_content));

        printf("Enter message type: ");
        scanf("%ld", &outgoing_message.message_type);
        getchar();

        printf("Enter message content: ");
        fgets(outgoing_message.message_content, sizeof(outgoing_message.message_content), stdin);
        outgoing_message.message_content[strlen(outgoing_message.message_content) - 1] = '\0';

        // Send message
        if (msgsnd(queue_id, &outgoing_message, MESSAGE_CONTENT_SIZE, 0) == -1) {
            perror("msgsnd failed");
            return EXIT_FAILURE;
        }
        printf("Message sent successfully\n");

        if (strcmp(outgoing_message.message_content, "quit") == 0) {
            break;
        }
    }

    return EXIT_SUCCESS;
}

Message Receiver Program

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>

struct message_structure {
    long message_type;
    char message_content[1024];
};

#define MESSAGE_CONTENT_SIZE (sizeof(struct message_structure) - sizeof(long))

int main() {
    // Generate key
    key_t queue_key;
    if ((queue_key = ftok("/", 'm')) == -1) {
        perror("ftok failed");
        return EXIT_FAILURE;
    }
    printf("Generated key: 0x%x\n", queue_key);

    // Access message queue
    int queue_id;
    if ((queue_id = msgget(queue_key, IPC_CREAT | 0664)) == -1) {
        perror("msgget failed");
        return EXIT_FAILURE;
    }
    printf("Queue ID: 0x%x\n", queue_id);

    struct message_structure incoming_message;

    while (1) {
        memset(incoming_message.message_content, 0, sizeof(incoming_message.message_content));

        // Receive message
        if (msgrcv(queue_id, &incoming_message, MESSAGE_CONTENT_SIZE, 0, 0) == -1) {
            perror("msgrcv failed");
            return EXIT_FAILURE;
        }

        printf("Received message: %s\n", incoming_message.message_content);

        if (strcmp(incoming_message.message_content, "quit") == 0) {
            break;
        }
    }

    // Remove message queue
    if (msgctl(queue_id, IPC_RMID, NULL) == -1) {
        perror("msgctl failed");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Bidirectional Process Communication Using Message Queues

Process A: Type 1 Messages

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>

struct message_structure {
    long message_type;
    char message_content[1024];
};

#define MESSAGE_CONTENT_SIZE (sizeof(struct message_structure) - sizeof(long))

int main() {
    key_t queue_key = ftok("/", 'b');
    if (queue_key == -1) {
        perror("ftok failed");
        return EXIT_FAILURE;
    }

    int queue_id = msgget(queue_key, IPC_CREAT | 0664);
    if (queue_id == -1) {
        perror("msgget failed");
        return EXIT_FAILURE;
    }

    pid_t child_pid = fork();

    if (child_pid > 0) {
        // Parent sends type 1 messages
        struct message_structure outgoing_msg;
        outgoing_msg.message_type = 1;

        while (1) {
            memset(outgoing_msg.message_content, 0, sizeof(outgoing_msg.message_content));
            printf("Send message: ");
            fgets(outgoing_msg.message_content, sizeof(outgoing_msg.message_content), stdin);
            outgoing_msg.message_content[strlen(outgoing_msg.message_content) - 1] = '\0';

            msgsnd(queue_id, &outgoing_msg, MESSAGE_CONTENT_SIZE, 0);
            printf("Message sent\n");

            if (strcmp(outgoing_msg.message_content, "quit") == 0) {
                break;
            }
        }
        wait(NULL);
    } else if (child_pid == 0) {
        // Child receives type 2 messages
        struct message_structure incoming_msg;

        while (1) {
            memset(incoming_msg.message_content, 0, sizeof(incoming_msg.message_content));
            msgrcv(queue_id, &incoming_msg, MESSAGE_CONTENT_SIZE, 2, 0);
            printf("Received: %s\n", incoming_msg.message_content);

            if (strcmp(incoming_msg.message_content, "quit") == 0) {
                break;
            }
        }
        exit(EXIT_SUCCESS);
    } else {
        perror("fork failed");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Process B: Type 2 Messages

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>

struct message_structure {
    long message_type;
    char message_content[1024];
};

#define MESSAGE_CONTENT_SIZE (sizeof(struct message_structure) - sizeof(long))

int main() {
    key_t queue_key = ftok("/", 'b');
    if (queue_key == -1) {
        perror("ftok failed");
        return EXIT_FAILURE;
    }

    int queue_id = msgget(queue_key, IPC_CREAT | 0664);
    if (queue_id == -1) {
        perror("msgget failed");
        return EXIT_FAILURE;
    }

    pid_t child_pid = fork();

    if (child_pid > 0) {
        // Parent receives type 1 messages
        struct message_structure incoming_msg;

        while (1) {
            memset(incoming_msg.message_content, 0, sizeof(incoming_msg.message_content));
            msgrcv(queue_id, &incoming_msg, MESSAGE_CONTENT_SIZE, 1, 0);
            printf("Received: %s\n", incoming_msg.message_content);

            if (strcmp(incoming_msg.message_content, "quit") == 0) {
                break;
            }
        }
        wait(NULL);
    } else if (child_pid == 0) {
        // Child sends type 2 messages
        struct message_structure outgoing_msg;
        outgoing_msg.message_type = 2;

        while (1) {
            memset(outgoing_msg.message_content, 0, sizeof(outgoing_msg.message_content));
            printf("Send message: ");
            fgets(outgoing_msg.message_content, sizeof(outgoing_msg.message_content), stdin);
            outgoing_msg.message_content[strlen(outgoing_msg.message_content) - 1] = '\0';

            msgsnd(queue_id, &outgoing_msg, MESSAGE_CONTENT_SIZE, 0);
            printf("Message sent\n");

            if (strcmp(outgoing_msg.message_content, "quit") == 0) {
                break;
            }
        }
        exit(EXIT_SUCCESS);
    } else {
        perror("fork failed");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.