Linux inter-process communication

I need to implement a test program (quiz), which, in addition to displaying the question and reading the answer, should display the time remaining in each minute. After the exam, ending with questions or ending with time, the program should return from the very beginning, when we enter the name of the candidate before starting. This implementation must be performed using processes. Below is the code that I have written so far. The problem is that I'm not sure that I am making a good connection between the process and subprocesses, especially because I do not use the channel. Some opinions?

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

#define T 180

void firstChildAction(){
    static const char filename[] = "/home/osystems01/laura/text";
    char question[100];
    char answer[100];

    FILE *file = fopen(filename,"r");
    if(file != NULL){
        while(fgets(question,sizeof question,file) != NULL){
            fputs(question, stdout);
            scanf("%s",&answer);
        }
        fclose(file);
    }
    else{
        perror(filename);
    }
}

void secondChildAction(){
    int i;
    for(i = T; i >= 0; i-=60){
        if( i/60 != 0){
            printf("You have %d %s left.\n", i/60,(i/60 >   1)?"minutes":"minute");
            sleep(60);
        }
        else{
            printf("The time is over\n");
            break;
        }
    }
}

int main() {
    pid_t pidA;
    pid_t pidB;
    pid_t wPid;
    char name[20];
    while(1){
        printf("Enter the candidate name or Quit to exit: \n");
        scanf("%s",&name);
        if(strcmp(name,"Quit") == 0 || strcmp(name,"quit") == 0){
            printf("The program is terminating.....\n");
            break;
        }
        else{
            pidA = fork();
            if(pidA == 0){
                firstChildAction();
                exit(0);
            }
            else{
                pidB = fork();
                if(pidB == 0){
                    secondChildAction();
                    exit(0);
                }
            }
            int status;
            while(wPid = wait(&status)) > 0 ){
                if(WIFEXITED(status)){
                    int result = WEXITSTATUS(status);
                    printf("Exit status of %d is %d\n", wPid, result);
                    if(wPid == pidA){
                        kill(pidB,SIGTERM);
                        kill(pidA,SIGTERM);
                    }
                    else if(wPid == pidB){
                        kill(pidA,SIGTERM);
                        kill(pidB,SIGTERM);
                    }
                }
            }
        }
    }
    return 0;
}
+4
source share
1 answer

, , , () , . , , .

() (, ), .

" " , ( , ). , , , . Linux, - ( , , ). - (https://unix.stackexchange.com/questions/53641/how-to-make-bidirectional-pipe-between-two-programs). . , .

, : fooobar.com/questions/61935/...

. pipe.h pipe.c ( NamedPipeReader NamedPipeWriter ). , () .


pipe.h
#ifndef PIPE_H_
#define PIPE_H_

//C headers
#include <errno.h>
#include <assert.h>

//Linux headers
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#ifdef __cplusplus
extern "C"
{
#endif

int open_named_pipe(const char* const name, const int permissions, const int mode, int* pipe_created);

#ifdef __cplusplus
}
#endif

#endif /* PIPE_H_ */


pipe.c
#include "pipe.h"

#include <stdio.h>

int open_named_pipe(const char* const name, const int permissions, const int mode, int* pipe_created)
{
    int fd;

    assert(name);
    assert(permissions);
    assert(pipe_created);

    //Create or use an existing pipe special file
    if (0 == mkfifo(name, permissions))
    {
        *pipe_created = 1;
        printf("Successfully created named pipe '%s'\n", name);
    }
    else
    {
        switch (errno)
        {
        case EEXIST:
            //this is OK, as the other process might already has created the special file
            printf("Opened existing named pipe '%s'\n", name);
            break;
        default:
            fprintf(stderr, "Failed to create or access named pipe '%s'\n", name);
            perror("    ");
            return -1;
        };
    }

    fd = open(name, mode);
    if (fd < 0)
    {
        perror("Could not open pipe for writing");
        if (*pipe_created)
        {
            if (0 == unlink(name))
            {
                *pipe_created = 0;
            }
            else
            {
                perror("Failed to unlink named pipe");
            }
        }
    }

    return fd;
}

NamedPipeReader.c

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

#include "pipe.h"

//Globals
const char* const pipe_name = "/tmp/myfifo";
const int pipe_permissions = 0600;
const size_t read_buffer_size = 1024; //[bytes]
const size_t read_retry_delay = 25000; //[us]

int fd = -1;
int pipe_created = 0;
char* read_buffer = NULL;

//Handles EPIPE signal
void signal_handler(int signal)
{
    fprintf(stderr, "cought signal %d\n", signal);
}

//Handles cleanup on exit
void exit_handler(void)
{
    if (read_buffer)
        free(read_buffer);

    if (fd >= 0)
        close(fd);

    //if this process created the FIFO, we unlink it
    if (pipe_created == 0)
        unlink(pipe_name);
}

int main()
{
    //Locals
    int run = 1;
    int received = 0;

    //Install the exit handler
    atexit(&exit_handler);
    signal(EPIPE, signal_handler);
    signal(EACCES, signal_handler);

    //Allocate the buffer
    read_buffer = (char*) malloc(read_buffer_size);
    if (!read_buffer)
    {
        perror("Failed to allocate buffer");
        return EXIT_FAILURE;
    }

    restart: ;

    //Close if already open
    if(fd >= 0)
        close(fd);
    //Create or use an existing pipe special file
    fd = open_named_pipe(pipe_name, pipe_permissions, O_RDONLY, &pipe_created);
    if (fd < 0)
    {
        return EXIT_FAILURE;
    }

    while (run)
    {
        assert(fd >= 0);
        assert(read_buffer_size > 1);

        received = read(fd, read_buffer, read_buffer_size - 1);

        if (received > 0)
        {
            //add a NUL char for string termination
            read_buffer[received] = '0';
            printf("local process %llu received: %s\n", (unsigned long long) getpid(), read_buffer);
        }
        else if (received == 0)
        {
            //EOF reached, this happens in case the writer has closed its handle.
            //Perform a delayed restart and recreate the named pipe
            usleep(read_retry_delay);
            printf("Restarting...\n");
            goto restart;
        }
        else
        {
            switch (errno)
            {
            case EAGAIN:
                //Wait, if the pipe is empty,
                //happens when opened with the O_NONBLOCK flag
                usleep(read_retry_delay);
                break;
            case EPIPE:
            case EBADF:
            case EBADFD:
                perror("Pipe error");
                printf("Restarting...\n");
                goto restart;
            default:
                perror("Pipe error");
                return EXIT_FAILURE;
            };
        }
    }

    return EXIT_SUCCESS;
}

NamedPipeWriter.c

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

#include "pipe.h"

//Globals
const char* const pipe_name = "/tmp/myfifo";
const int pipe_permissions = 0600;
const size_t write_buffer_size = 1024; //[bytes]
const size_t write_retry_delay = 25000; //[us]
const size_t write_interval = 1000000;

int fd = -1;
int pipe_created = 0;
char* write_buffer = NULL;

//Handles EPIPE signal
void signal_handler(int signal)
{
    fprintf(stderr, "cought signal %d\n", signal);
}

//Handles cleanup on exit
void exit_handler(void)
{
    if (write_buffer)
        free(write_buffer);

    if (fd >= 0)
        close(fd);

    //if this process created the FIFO, we unlink it
    if (pipe_created == 0)
        unlink(pipe_name);
}

//Main Function
int main()
{
    //Locals
    int run = 1;
    int sent = 0;
    int msg_len = 0;

    //Install the exit handler
    atexit(&exit_handler);
    signal(EPIPE, signal_handler);
    signal(EACCES, signal_handler);

    //Allocate the buffer
    write_buffer = (char*) malloc(write_buffer_size);
    if (!write_buffer)
    {
        perror("Failed to allocate buffer");
        return EXIT_FAILURE;
    }

    restart: ;

    //Close if already open
    if(fd >= 0)
        close(fd);
    //Create or use an existing pipe special file
    fd = open_named_pipe(pipe_name, pipe_permissions, O_WRONLY, &pipe_created);
    if (fd < 0)
    {
        return EXIT_FAILURE;
    }

    while (run)
    {
        //Print message into the buffer
        msg_len = snprintf(write_buffer, write_buffer_size, "Greetings from process %llu\n", (unsigned long long) getpid());

        {
            char* msg_ptr = write_buffer;
            char* msg_end = write_buffer + msg_len;
            while (msg_ptr != msg_end)
            {
                assert(fd >= 0);
                assert(msg_ptr < msg_end);
                sent = write(fd, msg_ptr, msg_end - msg_ptr);
                if (sent > 0)
                {
                    msg_ptr += sent;
                }
                else if (sent == 0)
                {
                    //retry delay for nonblocking writes
                    usleep(write_retry_delay);
                }
                else
                {
                    switch (errno)
                    {
                    case EAGAIN:
                        //Wait, if the pipe is full,
                        //happens when opened with the O_NONBLOCK flag
                        usleep(write_retry_delay);
                        break;
                    case EPIPE:
                    case EBADF:
                    case EBADFD:
                        perror("Pipe error");
                        printf("Restarting...\n");
                        goto restart;
                    default:
                        perror("Pipe error");
                        return EXIT_FAILURE;
                    };
                }
            }

            printf("Written: %s\n", write_buffer);
            usleep(write_interval);
        }
    }

    return EXIT_SUCCESS;
}
+1

All Articles