Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I think your problem is that you wait for the child to die before giving it the signal to go and read the file.</p> <p>You have:</p> <pre><code> /* Reap the child */ wait(&amp;child_status); kill(pid, SIGUSR1); </code></pre> <p>You probably need:</p> <pre><code> kill(pid, SIGUSR1); /* Reap the child */ wait(&amp;child_status); </code></pre> <p>The other part of your problem could be that the child gets to the second <code>pause()</code> before exiting, but no process sends it a signal at that point. And since the parent is still waiting for the child to die, but the child can't exit until someone sends it a signal to break the <code>pause()</code>, nothing much happens except everyone waiting around for someone else to do something.</p> <hr> <p>And, after a bit more experimentation (and a good deal more diagnostic output), I got the file (it was the source code) printed by the parent, followed by the information:</p> <pre><code>Parent sending signal to child Parent waiting for child Child (56243) about to pause() </code></pre> <p>On the face of it, then, the signal was sent to the child before the child was paused, so the signal may as well never have been sent. Since the code was flushing religiously, I'm not quite sure why I wasn't seeing the trace from the signal handler in the child.</p> <hr> <p>Nothing like a nice simple problem for blowing up in one's face...</p> <p>Here's some revised code that does what is expected, though you may be a bit surprised:</p> <pre><code>#define _XOPEN_SOURCE 600 #include &lt;limits.h&gt; /* For LONG_MAX */ #include &lt;fcntl.h&gt; /*For open()*/ #include &lt;unistd.h&gt; /*For close(), read(), write(), nice()*/ #include &lt;stdlib.h&gt; /*For exit()*/ #include &lt;stdio.h&gt; /*For fprintf(),perror()*/ #include &lt;signal.h&gt; /*For signal()*/ #include &lt;sys/types.h&gt; /* For pid_t */ #include &lt;sys/wait.h&gt; /* For wait() */ static volatile sig_atomic_t sigusr1 = 0; void my_handler(int); void displayUsage(FILE *, const char *); int main(int argc, char **argv) { char c[BUFSIZ]; /* To hold the string that has been read from the file */ int fd; /* file descriptor */ int n; long int nBytes; /* To hold the number of bytes to read */ pid_t pid; int child_status; /* Display usage if user use this process wrong */ if(argc != 3){ displayUsage(stderr, argv[0]); exit(1); } /* Convert argv[1] to long - number of bytes to read */ nBytes = strtol(argv[1], NULL, 10); if((nBytes &lt;= 0) || (nBytes &gt; INT_MAX)){ fprintf(stderr, "Bufferize %s is not a positive integer\n", argv[1]); exit(2); } /* Open a file */ if((fd = open(argv[2],O_RDONLY,0)) &lt; 0){ perror(argv[2]); exit(3); } /* Attempt to register a signal handler */ if(signal(SIGUSR1, my_handler) == SIG_ERR){ perror("Could not set a handler for SIGUSR1"); exit(4); } /* lowering the process priority */ if(nice(40) &lt; 0){ perror("Cannot lower the priority"); exit(5); } /* Create a new process */ pid = fork(); if(pid &lt; 0){ perror("fork"); exit(6); } /* Allocating memory space for string/data to be read from the file if(!(c = malloc(nBytes))){ perror("ERROR"); exit(4); }*/ if(pid == 0){ printf("Child (pid = %d) about to signal self (sigusr1 = %d)\n", (int)getpid(), (int)sigusr1); fflush(0); kill(pid, SIGUSR1); printf("Child (%d) about to pause() (sigusr1 = %d)\n", (int)getpid(), (int)sigusr1); fflush(0); pause(); /* I'm the child */ printf("Child's turn %d!\n", (int)getpid()); /* Read The File */ while((n = read(fd, c, nBytes)) != 0){ /* Write content of 'c' to the stdout */ if(write(STDOUT_FILENO, c, n) &lt; 0){ perror("Write Error!\n"); exit(7); } } printf("Child signalling parent\n"); kill(pid,SIGUSR1); printf("Child exiting (status = 37)\n"); exit(37); } else{ /* I'm the parent */ printf("Parent's turn! (pid = %d, kid = %d)\n", (int)getpid(), (int)pid); /* Read The File */ while((n = read(fd, c, nBytes)) != 0){ /* Write content of 'c' to the stdout */ if(write(STDOUT_FILENO, c, n) &lt; 0){ perror("Write Error!\n"); exit(7); } } printf("Parent sleeping\n"); sleep(1); printf("Parent sending signal to child\n"); fflush(0); kill(pid, SIGUSR1); printf("Parent waiting for child\n"); fflush(0); /* Reap the child */ int corpse = wait(&amp;child_status); printf("waiting over: pid = %d, status = 0x%.4X\n", corpse, child_status); } printf("%d skipping final pause\n", (int)getpid()); /*pause();*/ /* Close the file */ if(close(fd) &lt; 0){ perror(argv[2]); exit(8); } printf("%d exiting\n", (int)getpid()); return(0); } void displayUsage(FILE *fp, const char *arg) { fprintf(fp, "Usage: %s n filename\n", arg); fprintf(fp, "where\n"); fprintf(fp, "\tn\tNumber of bytes to read and write in each \"block\".\n"); fprintf(fp,"\tfilename\tName of file to be catted.\n"); } void my_handler(int sig) { /* Re-registering the handler */ if(signal(sig, my_handler) == SIG_ERR){ perror("Could not set a handler for SIGUSR1"); exit(4); } sigusr1 = 1; printf("In signal handler (pid %d)\n", (int)getpid()); fflush(0); } </code></pre> <p>Example output:</p> <pre><code>$ ./doze 20 file.1 Parent's turn! (pid = 56459, kid = 56460) 0.0 Parent sleeping Child (pid = 56460) about to signal self (sigusr1 = 0) In signal handler (pid 56460) Child (56460) about to pause() (sigusr1 = 1) In signal handler (pid 56459) Parent sending signal to child Parent waiting for child In signal handler (pid 56460) Child's turn 56460! Child signalling parent In signal handler (pid 56460) Child exiting (status = 37) In signal handler (pid 56459) waiting over: pid = 56460, status = 0x2500 56459 skipping final pause 56459 exiting $ </code></pre> <p>The data file, <code>file.1</code>, contains a single line containing <code>0.0</code> (very unexciting). As you can see, the parent copies the file fine. Now, thanks to the <code>sleep(1)</code>, the child gets a chance to do things, and wake up from the signal handler. It copies the rest of the file to standard output...</p> <p>What's that—you can't see what the child copied? Ah, well...</p> <p>The two processes share an open file description, and the current position in the file is controlled by the position in the open file description. So, when the parent's finished reading the file, the file is at EOF, so the first <code>read()</code> by the child is of zero bytes. You'd need to do an <code>lseek(fd, 0L, SEEK_SET);</code> to get it to read the file again.</p> <p>So, the child copies the data, then signals the parent, exits with status 37. You can see the parent responding, and so on, up to the exit. So, as edited, it works. You had too many pauses. I'm not sure the <code>sleep()</code> is necessary, but I suspect it is.</p> <hr> <p>Point of detail: the message <code>Child signalling parent</code> is inaccurate information; that is the child signalling itself. I don't think that is necessary. In fact, here's the 'same' code with 40 fewer lines in it:</p> <pre><code>#define _XOPEN_SOURCE 600 #include &lt;fcntl.h&gt; #include &lt;unistd.h&gt; #include &lt;stdlib.h&gt; #include &lt;stdio.h&gt; #include &lt;signal.h&gt; #include &lt;sys/wait.h&gt; void my_handler(int); void displayUsage(FILE *, const char *); int main(int argc, char **argv) { char c[BUFSIZ]; int fd; int n; long int nBytes; pid_t pid; int child_status; if(argc != 3){ displayUsage(stderr, argv[0]); exit(1); } nBytes = strtol(argv[1], NULL, 10); if((nBytes &lt;= 0) || (nBytes &gt; BUFSIZ)){ fprintf(stderr, "Buffer size %s is not a positive integer between 1 and %d\n", argv[1], BUFSIZ); exit(2); } if((fd = open(argv[2], O_RDONLY, 0)) &lt; 0){ perror(argv[2]); exit(3); } if(signal(SIGUSR1, my_handler) == SIG_ERR){ perror("Could not set a handler for SIGUSR1"); exit(4); } pid = fork(); if(pid &lt; 0){ perror("fork"); exit(6); } if(pid == 0){ printf("Child (%d) about to pause()\n", (int)getpid()); pause(); printf("Child's turn %d!\n", (int)getpid()); lseek(fd, 0L, SEEK_SET); while((n = read(fd, c, nBytes)) != 0){ if(write(STDOUT_FILENO, c, n) &lt; 0){ perror("Write Error!\n"); exit(7); } } int rc = 37; printf("Child exiting (status = %d (0x%.2X))\n", rc, rc); exit(rc); } else{ printf("Parent's turn! (pid = %d, kid = %d)\n", (int)getpid(), (int)pid); while((n = read(fd, c, nBytes)) != 0){ if(write(STDOUT_FILENO, c, n) &lt; 0){ perror("Write Error!\n"); exit(7); } } printf("Parent sleeping\n"); sleep(1); printf("Parent sending signal to child\n"); kill(pid, SIGUSR1); printf("Parent waiting for child\n"); int corpse = wait(&amp;child_status); printf("waiting over: pid = %d, status = 0x%.4X\n", corpse, child_status); } if(close(fd) &lt; 0){ perror(argv[2]); exit(8); } printf("%d exiting\n", (int)getpid()); return(0); } void displayUsage(FILE *fp, const char *arg) { fprintf(fp, "Usage: %s n filename\n", arg); fprintf(fp, "where\n"); fprintf(fp, "\tn\tNumber of bytes to read and write in each \"block\".\n"); fprintf(fp, "\tfilename\tName of file to be catted.\n"); } void my_handler(int sig) { if(signal(sig, my_handler) == SIG_ERR){ perror("Could not set a handler for SIGUSR1"); exit(4); } printf("In signal handler (pid %d)\n", (int)getpid()); } </code></pre> <p>Example output:</p> <pre><code>$ ./doze 20 file.1 Parent's turn! (pid = 56651, kid = 56652) 0.0 Parent sleeping Child (56652) about to pause() Parent sending signal to child Parent waiting for child In signal handler (pid 56652) Child's turn 56652! 0.0 Child exiting (status = 37 (0x25)) waiting over: pid = 56652, status = 0x2500 56651 exiting $ </code></pre> <p>When I removed the <code>sleep()</code>, the program hung once more; the parent sent the signal to the child before the child was in the <code>pause()</code>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload