CorellianAle
CorellianAle

Reputation: 685

memory and pipe/socket management in a program with pipe(), fork() and signal handling

Working with fork, pipe and signal.h signal handling. STDIN is used to quickly simulate socket connection with a network server. Pseudocode:

struct message_t {
    uint32_t length;
    uint8_t *data;
};

int is_shutdown = 0;

void signal_handler(int) {
    //set is_shutdown if SIGINT
}

int main() {
    //initialize
    pipe();
    fork();

    if (parent) {
        while(!is_shutdown) {
            //0. initialize variables, buffer, message_t
            //1. read string of unknown length from STDIN (or socket) to a buffer
            //2. malloc() message_t and fill it's fields
            //3. write() message_t to pipe
            //4. free() message_t
        }
    }

    if (child) {
        while(!is_shutdown) {
            //0. initialize variables, message_t
            //1. read() message_t: read length, malloc() buffer, read data
            //2. execute command
            //4. free() message_t
        }   
    }

    //close pipe
}

Several thing that confuse me:

  1. Should I close() the pipe in the signal handler?
  2. I don't fully understand what happens to the message (it's memory) after I send it (parent). Should I free() the buffer after the write()?
  3. How do I handle resources deallocation from signal handler. Should I implement buffers and fd's as global variable to have access to them from signal handler
  4. is_shutdown flag and interprocess communication. Am I understanding it right that parent and child do not share is_shutdown as the same variable (they are copies) and change to the one would not change the other?
  5. What about concurrent access to is_shutdown for both signal handler and main? Any hidden details like in concurrency via multithreading?
  6. When one process gets shut down, the other would still be working. I would not be able to notify the other one if something happens with a pipe. Should I hope for a SIGPIPE?
  7. I suspect that calling malloc() on each iteration of the parent's while loop would not be wise from a performance standpoint. But defining buffer that is "big enough" feels like a hack (what if someday it would not be big enough). Am I wrong?

I am quite new to C and it's memory and resource management: switching from C++14 development for powerful Intel based server/desktops to C development for ~180MHz ARM embedded systems so I may be worried to much and forget some obvious things.

Upvotes: 0

Views: 134

Answers (1)

zwol
zwol

Reputation: 140788

  1. No, you should not. The only thing you should do in the signal handler is set is_shutdown.
  2. write makes a copy. After write returns, it is safe to reuse or deallocate the buffer. (Make sure to handle short writes, though.)
  3. You don't. Again, the only thing you should do in the signal handler is set is_shutdown. Clean up in the parent and child blocks after the while loops terminate.
  4. Yes, each process has an independent copy. You should also know that with this design, if you run the program from the terminal and then type ^C at it, the kernel will fire a SIGINT at both of the processes, because they are both in the same process group.
  5. is_shutdown needs to be declared with type volatile sig_atomic_t, and, for a simple program like this, it should not be written to by anything other than the signal handler. Also, the signal handler should not read its value, it should only set it. And depending on details of the code you haven't shown us, it may be appropriate to install the signal handler without using SA_RESTART, so that it interrupts blocking system calls.
  6. The only thing you need to do about this is make sure that each side of the communications channel gracefully handles the other end disconnecting abruptly.
    • If this is a mockup of what will eventually become a network server and client, you should change from using pipe to using socketpair before you start testing abrupt disconnects, because socketpair fds behave much more like real network sockets.
  7. I/O overhead is probably much bigger than malloc overhead. Worrying about malloc overhead at this stage is premature optimization.

Upvotes: 1

Related Questions