2

Ran into some difficulties with a program I'm writing up over the last few days. I simply want a program to run with signals. When a user hits control c, I create two pipes and 1 parent that has two children.

When the user hits control Z from a child process, I want the children to talk to one another. At the time being, I just want it to print out some line to terminal. Now after doing some tests on the problem, I concluded on some factors.

  1. If the signal for control Z is placed in the parent process (commented out line in the code), the program runs fine...
  2. If the signal is then moved to the child process....it terminates the program for some reason. I assumed it was the child dying, however using commands such as sleep and wait proved to be ineffective.

Can someone see where I am going wrong...its really starting to bug me :/

  #include <stdio.h>
    #include <signal.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <time.h>
    #include <string.h>

    pid_t forkA, forkB;

    void handleSignal();
    void controlC();
    void controlZ();

    int main ()
    {
        signal(SIGINT, handleSignal);
        while(1);
    }    

    void handleSignal (int signal)
    {
      if (signal == SIGINT)
        {
          write(1, "ContrlC \n", 11);
        controlC();
        }
      else if (signal == SIGTSTP)
        {
          write(1, "CONTROLZ \n", 11);
          controlZ();
        }
      else
      {
        write(2, "error \n", 8);
      }
    }

    void controlC()
    {   
        int firstPipe[2];
        int secondPipe[2];

        if (pipe(firstPipe) < 0)
        {
                write(1,"Error \n", 7);
        }   
        else if (pipe(secondPipe) < 0)
        {
                write(1,"Error creating pipe 2 \n", 23);
        }
        else
        {
            write(1, "Pipe creations: DONE \n", 22);
        }

        //make child
        forkA = fork();
        if (forkA < 0)
        {
            write(2, "FORK ERROR. \n", 13);
        }
        else if (forkA == 0)
        {
                write(1, "CHILD 1 \n", 9);
                close(firstPipe[0]);    //close reading end of pipe 1
                close(secondPipe[1]);//close writing end of pipe 2
            sleep(5);
        }
        else
        {
            forkB = fork();
                if (forkB < 0)
                {
                write(2, "FORK ERROR. \n", 12);
                }
            else if (forkB == 0)
            {
            signal(SIGTSTP, handleSignal);
                write(1, "CHild 2 \n", 9);
                close(firstPipe[1]); //close write end of pipe 1
                    close(secondPipe[0]); //close read end of pipe 2
            sleep(5);
            }
            else
            {
            //signal(SIGTSTP, handleSignal);
signal(SIGCHLD, SIG_IGN);
            write(1,"parent of both \n", 16);
            wait();
            }
        }               
    }

    void controlZ()
    {
        write(1, "woo z \n", 7);
    }
doron
  • 27,972
  • 12
  • 65
  • 103
lecardo
  • 1,208
  • 4
  • 15
  • 37
  • Have you tried using a debugger? – user1231232141214124 Dec 22 '14 at 01:27
  • what debugger would you recommend? I've just been carrying out trial and errors to determine the root problem – lecardo Dec 22 '14 at 01:28
  • 1
    `gdb` is the standard debugger on (GNU/)Linux. – John Zwinck Dec 22 '14 at 01:28
  • 1
    `GDB`... to be fair, you should already know how to debug simple programs before moving on to advanced concepts. – user1231232141214124 Dec 22 '14 at 01:29
  • When a child process receives a signal, the parent process is notified with a signal of `SIGCHLD`. You have to make sure the parent can handle this signal. – alvits Dec 22 '14 at 01:59
  • @alvits I looked into SIGCHLD, In the parent I placed the code to ignore it(updated in code above with this addition), Still receiving the same isuse – lecardo Dec 22 '14 at 12:12
  • 1
    This is not an [MVCE](http://stackoverflow.com/help/mcve): the call to `wait()`, at least, is wrong, and the `pipe()`s are superfluous for demonstration. It's slippery, too: some `write()s` are wrong as @chux noted. Then there's the complex signal handlers and the `main` busy loop (to which both children _return_ from their birth in a handler, by the way). Discard this attempt, try again just to reproduce the problem you think you're having, and then show us in code _and its output_ what is going wrong. – pilcrow Dec 22 '14 at 13:27

3 Answers3

1

From signal(7):

The signal disposition is a per-process attribute

So this means that you have to define the signal behavior in all of your forked processes. Otherwise the ctrl+c will kill the process or the ctrl+z will stop the process. You don't have to explicitly SIG_IGN SIGCHLD because that is the default behavior for SIGCHLD.

On an unrelated note: please do not use write(2) for outputting text to the terminal. Use fprintf(3). Use stdout as the first argument if you want to output to stdout and stderr for outputting error messages. This way you don't have to worry at all about counting the amount of characters to write.

Your wait call is also wrong, it needs an int* argument or at least a NULL argument.

SamC
  • 71
  • 3
  • `fprintf()` is not safe to call from a signal handler, is the reason for using `write()`, although having a signal handler do so much work isn't a fantastic idea to begin with. – Crowman Dec 22 '14 at 14:27
  • @PaulGriffiths You are correct of course. I don't tend to use many signal handlers. – SamC Dec 29 '14 at 09:34
0

write(1, "ContrlC \n", 11); and write(1, "CONTROLZ \n", 11); are certainly the wrong lengths.

Suggest a different approach to avoid counting errors like

#define CONTORLC "ContrlC \n"
write(1, CONTORLC, sizeof(CONTORLC) - 1);

or

void write_string(int handle, const char *s) {
  write(handle, s, strlen(s));
}

Although this takes care of UB generated by avoiding accessing memory outside array bounds, additional issue may remain.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    Cheers for that, wasn't really a concern for me as I just needed to see if my code was getting to that stage...those are likely to be removed when I figure out this issue – lecardo Dec 22 '14 at 01:50
0

Signal handlers should remain as quick as possible. Moreover you should have a look on this question which deals with the difference between signal(2) and sigaction(2).

Did you simply tried using USR1 and USR2 in order not to break the semantic of sigint / sigcont?

Community
  • 1
  • 1
Aif
  • 11,015
  • 1
  • 30
  • 44
  • Hi, I understand the differences between the two signal methods however I have been told to use just signal(2). No user defined signals are being used. – lecardo Dec 22 '14 at 12:09