Search code examples
csignalsposixkill

Posix Reliable Signals between two processes using SIGUSR1


I have to processes running (a server and a client) on two different terminals. The client reads a user input, saves it to a file (hello.txt), signals SIGUSR1 and then sleeps. The server then wakes up, reads the file (hello.txt), prints it, signals the client that it worked and then sleeps. The client then wakes up, prints that it was successful then waits for another user input.

There is more to it later but this is all I am trying to accomplish at the moment. I have had trouble finding examples using sigaction and SIGUSR1 between two separate, unrelated processes. Here is the code I have so far:

server.c

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

volatile sig_atomic_t myFlag = 0;
static void myHandler(int);
struct sigaction newAction, oldAction;


int main(int argc, char* argv[])
{
    //setup signal stuff
    sigset_t zeromask;
    sigemptyset(&newAction.sa_mask);
    sigemptyset (&oldAction.sa_mask);
    sigemptyset(&zeromask);
    newAction.sa_flags = 0;
    newAction.sa_handler = myHandler;
    sigaddset (&newAction.sa_mask, SIGUSR1);
    if ( sigaction(SIGUSR1, &newAction, &oldAction))
            return;

    for ( ; ; ) {
            //Loop
            //This is so I can manually enter the pid into the client 
            printf("%d\n",getpid());
            while(myFlag == 0)
                    sigsuspend (&zeromask);
            myFlag = 0;
            printf("Got signal, process it\n");

    //signal occured process it
    }

    sigprocmask (SIG_SETMASK, &oldAction.sa_mask, NULL);
    exit(0);
    }

static void myHandler(int sigNo) {
    myFlag = 1;

    printf("finally made it");
    sigprocmask (SIG_BLOCK, &newAction.sa_mask, &oldAction.sa_mask);
    return;
}

client.c

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

volatile sig_atomic_t myFlag = 0;
static void myHandler(int);
struct sigaction newAction, oldAction;


int main(int argc, char* argv[])
{
    printf("begin\n");
    //Signal stuff 
    sigset_t zeromask;
    sigemptyset(&newAction.sa_mask);
    newAction.sa_flags = 0;
    newAction.sa_handler = myHandler;
    sigemptyset (&oldAction.sa_mask);
    sigemptyset(&zeromask);
    sigaddset (&newAction.sa_mask, SIGUSR1);
    if ( sigaction(SIGUSR1, &newAction, &oldAction))
            return;
    sigprocmask (SIG_BLOCK, &newAction.sa_mask, &oldAction.sa_mask);

    //loop
    for ( ; ; ) {
            printf("This is where you would get user input\n");
            //Signal Server
            //For now I just manually enter the pid that was printed out when I ran server.c. This does not work and I do not think it is the right thing to do 
            kill(27514,SIGUSR1);
            //loop while waiting for server to respond
            while(myFlag == 0)
                    sigsuspend (&zeromask);

            myFlag = 0;
            printf("this is where you would process return signal\n");
    //signal occured process it
    }

    sigprocmask (SIG_SETMASK, &oldAction.sa_mask, NULL);
    exit(0);
    }

    static void myHandler(int sigNo) {
          myFlag = 1;
          sigprocmask (SIG_BLOCK, &newAction.sa_mask, &oldAction.sa_mask);
          return;
    }

For now all this code is supposed to do is signal the server from the client. From there I will implement the rest. However, this does not work and I cannot seem to figure out.

Is kill the right command to use to implement SIGUSR1? Do I need to know the PID of each the client and server in order for them to communicate? Am I totally just doing the wrong thing?


Solution

  • You haven't indicated what's actually happening, but to answer your questions:

    "Is kill the right command to use to implement SIGUSR1?" Yes.

    "Do I need to know the PID of each the client and server in order for them to communicate?" Yes.

    "Am I totally just doing the wrong thing?" Yes.

    The main issue with using signal is that 1) it arrives at any time in the execution of your program, and 2) you are only ready to handle it at certain times.

    The code you have above will only process the signal correctly if it happens to be in sigsuspend(), waiting. This isn't true at every moment! When you're in the other parts of the loop, i.e. when you send a kill() to the other process, consider what will happen if the other process kill()'s back before you arrive at sigsuspend again... you won't be waiting for the signal and it will come and go. Your implementation isn't reliable.

    A more reliable implementation would be to use a socket connection between the processes; you could communicate the signal or even the data itself through such a connection. In fact there are many ways to do this, see http://en.wikipedia.org/wiki/Inter-process_communication (and you seem to be using POSIX interfaces above).

    The upshot is that signal is asynchronous, interrupts the flow of any program, and specific to your program, you're not always ready for it, and if you miss it, it's gone. With sockets (or pipes or some other thing with an actual file descriptor) the data (your signal) will cause select() or poll() to return, instead of just flying by.