Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Various comments as I look at the code:</p> <ol> <li><p>End messages with newlines; you're on Linux now, not Windows. Windows systems seem to encourage people to leave messages without newlines, but it won't work well on Unix in general and Linux in particular.</p></li> <li><p>Don't use <code>_exit()</code> if you want your error messages to appear, especially ones that don't end in a newline.</p></li> <li><p>Don't report error messages on standard output; report them on standard error (that's what it is for!).</p></li> <li><p>Writing <code>else if (argc == 2) { }</code> (with nothing in the braces) is a little odd if there is an <code>else</code> clause after it, but it is pointless when there is no <code>else</code> clause. You should arguably test for <code>argc != 2</code> since that is the correct number of arguments (or, perhaps more accurately, any arguments beyond <code>argc == 2</code> are ignored).</p></li> <li><p>If you want to sleep for a time involving sub-second timing (e.g. 1.3 seconds), use one of the appropriate sub-second sleep commands. In this case, <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html" rel="nofollow"><code>nanosleep()</code></a> is probably the function to use.</p></li> <li><p>Don't use SIGKILL except in dire emergency. The process signalled with SIGKILL has no chance to clean up or anything; it is killed immediately (assuming your process is allowed to send a signal to the other at all, of course).</p></li> <li><p><code>case -1: printf("syserr");</code> with no <code>break;</code> after it means that on error, the flow of control goes into the following <code>case 0:</code> code, which is not what's required. Either <code>break;</code> or <code>exit(1);</code> is probably appropriate. (Bullet 3 applies too.)</p></li> <li><p>Don't close standard error. The code:</p> <pre><code>close(1); close(2); dup(pipe_fds[1]); close(pipe_fds[0]); close(pipe_fds[1]); execvp(*command, command); perror("execv"); _exit(EXIT_FAILURE); </code></pre> <p>is never going to report an error; you closed standard error. Remember that programs are entitled to have a standard error channel. The C standard guarantees it, but you have to cooperate and make sure you've not closed standard error.</p></li> <li><p>Some of the casts in:</p> <pre><code>diff = ((double)((uintmax_t)(clock_t)done) - (double)((uintmax_t)(clock_t)launch)) / (double)CLOCKS_PER_SEC; </code></pre> <p>are unnecessary. Since both <code>done</code> and <code>launch</code> are of the type <code>clock_t</code>, the casts to <code>clock_t</code> are unnecessary. The intermediate cast to <code>uintmax_t</code> also isn't really necessary. You could simply write:</p> <pre><code>diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC; </code></pre> <p>and even then, two of the three casts are theoretically redundant (any two of the three could be removed).</p></li> <li><p>The code in <code>read_from_pipe()</code> is curious and error prone. Since you've got a file stream, simply read an integer from it using <code>fscanf()</code>, rather than the curious construct using double arithmetic and fractional values that are then multiplied at the end. This is especially appropriate since the <code>write_to_pipe()</code> code uses <code>printf("%d", ...);</code> to write the data. Since <code>c</code> is already an <code>int</code>, the cast in <code>return (int)c;</code> is superfluous.</p></li> <li><p>Theoretically, it would be a good idea to check the streams returned by <code>fdopen()</code> to ensure that the operation did not fail.</p></li> <li><p>If the <code>pipe()</code> function fails, you report the error on standard output and then continue as nothing had gone wrong.</p></li> <li><p>It is not clear what the <code>racket</code> command actually does. It doesn't exist on my machine.</p></li> <li><p><code>argv</code> in <code>spawnfp()</code> is unused.</p></li> <li><p><code>pid = fork(); if (pidDos &lt; (pid_t) 0)</code> generates a warning (accurately) that <code>pidDos</code> might be used uninitialized. The condition should presumably be using <code>pid</code>, not <code>pidDos</code>. You then send a SIGKILL signal to the PID identified at random by <code>pidDos</code>, which is unlikely to lead to happiness.</p></li> </ol> <p>When I copy <code>cat</code> to <code>racket</code> and invoke the following code (as a program <code>mk</code> built from <code>mk.c</code>) as <code>mk /etc/passwd</code>, I get to see the password file double-spaced (and the message from the shell about <code>Killed: 9</code>.</p> <pre><code>#include &lt;math.h&gt; #include &lt;signal.h&gt; #include &lt;stdint.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;time.h&gt; #include &lt;unistd.h&gt; static int read_from_pipe(int file) { int c; FILE *stream = fdopen(file, "r"); if (fscanf(stream, "%d", &amp;c) != 1) { fprintf(stderr, "Failed to read integer from pipe\n"); exit(1); } fclose(stream); return c; } static void write_to_pipe(int file, int pidRacket) { FILE *stream = fdopen(file, "w"); fprintf(stream, "%d", pidRacket); fclose(stream); } static int spawnpipe(char *fileName, int *fd) { int pid; int pipe_fds[2]; char *command[] = {"racket", fileName, NULL}; if (pipe(pipe_fds) &lt; 0) { fprintf(stderr, "FE: pipe\n"); exit(1); } switch ((pid = fork())) { case -1: printf("syserr"); exit(1); case 0: close(1); close(2); dup(pipe_fds[1]); close(pipe_fds[0]); close(pipe_fds[1]); execvp(*command, command); perror("execv"); exit(EXIT_FAILURE); default: *fd = pipe_fds[0]; close(pipe_fds[1]); return pid; } } static int spawnfp(char *fileName, FILE **fpp) { int fd, pid; pid = spawnpipe(fileName, &amp;fd); *fpp = fdopen(fd, "r"); return pid; } int main(int argc, char *argv[]) { pid_t pid; int mypipe[2]; if (pipe(mypipe)) { fprintf(stderr, "Pipe failed.\n"); return EXIT_FAILURE; } pid = fork(); if (pid &lt; (pid_t) 0) { fprintf(stderr, "Fork failed.\n"); return EXIT_FAILURE; } else if (pid != (pid_t) 0) { double diff = 0; clock_t launch = clock(); close(mypipe[1]); int pidRacket = read_from_pipe(mypipe[0]); while (diff &lt; 1.3) { clock_t done = clock(); diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC; } kill(pidRacket, SIGKILL); kill(pid, SIGKILL); return EXIT_SUCCESS; } else if (pid == (pid_t) 0) { close(mypipe[0]); char buf[100]; FILE *fp; char *fileName = argv[1]; int pidRacket = spawnfp(fileName, &amp;fp); write_to_pipe(mypipe[1], pidRacket); if (argc == 1) { printf("Not enough arguments!"); _exit(EXIT_FAILURE); } else if (argc == 2) { } sleep(1); while (fgets(buf, sizeof buf, fp)) { printf("%s\n", buf); } fclose(fp); kill(pid, SIGKILL); return 0; } } </code></pre> <p>I fixed some, but by no means all, of the issues identified in this revision of the code.</p> <hr> <p>Oh, and item 16: the read end of the pipe isn't closed until the third process terminates. You need to pass <code>mypipe[1]</code> to <code>spawnfp()</code>, which needs to relay it to <code>spawnpipe()</code>, and the child created there needs to close the pipe descriptor before executing 'racket'. This is compounded by <code>fscanf()</code> looking for either EOF or a non-digit at the end of the PID it reads from the pipe. You could provide a newline or something at the end and that would also free up the parent process to spin in its timing loop. Since you say <code>racket</code> doesn't terminate, that's why you don't see anything much.</p> <p>It's easier to paste the whole program again than present the diffs:</p> <pre><code>#include &lt;assert.h&gt; #include &lt;math.h&gt; #include &lt;signal.h&gt; #include &lt;stdint.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;time.h&gt; #include &lt;unistd.h&gt; static int read_from_pipe(int file) { int c; FILE *stream = fdopen(file, "r"); assert(stream != 0); if (fscanf(stream, "%d", &amp;c) != 1) { fprintf(stderr, "Failed to read integer from pipe\n"); exit(1); } fclose(stream); return c; } static void write_to_pipe(int file, int pidRacket) { FILE *stream = fdopen(file, "w"); assert(stream != 0); fprintf(stderr, "%d: pidRacket = %d\n", (int)getpid(), pidRacket); fprintf(stream, "%d", pidRacket); fclose(stream); } static int spawnpipe(char *fileName, int *fd, int pfd) { int pid; int pipe_fds[2]; char *command[] = {"racket", fileName, NULL}; if (pipe(pipe_fds) &lt; 0) { fprintf(stderr, "FE: pipe\n"); exit(1); } switch ((pid = fork())) { case -1: printf("syserr"); exit(1); case 0: close(pfd); close(1); //close(2); dup(pipe_fds[1]); close(pipe_fds[0]); close(pipe_fds[1]); execvp(*command, command); perror("execv"); exit(EXIT_FAILURE); default: fprintf(stderr, "%d: pid = %d\n", (int)getpid(), pid); *fd = pipe_fds[0]; close(pipe_fds[1]); return pid; } } static int spawnfp(char *fileName, FILE **fpp, int pfd) { int fd, pid; pid = spawnpipe(fileName, &amp;fd, pfd); *fpp = fdopen(fd, "r"); assert(*fpp != 0); return pid; } int main(int argc, char *argv[]) { pid_t pid; int mypipe[2]; if (pipe(mypipe)) { fprintf(stderr, "Pipe failed.\n"); return EXIT_FAILURE; } pid = fork(); if (pid &lt; (pid_t) 0) { fprintf(stderr, "Fork failed.\n"); return EXIT_FAILURE; } else if (pid != (pid_t) 0) { double diff = 0.0; clock_t launch = clock(); close(mypipe[1]); fprintf(stderr, "%d: Reading from pipe:\n", (int)getpid()); int pidRacket = read_from_pipe(mypipe[0]); fprintf(stderr, "%d: Read PID %d from pipe\n", (int)getpid(), pidRacket); while (diff &lt; 1.3) { clock_t done = clock(); diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC; printf("%f\n", diff); } kill(pidRacket, SIGKILL); kill(pid, SIGKILL); return EXIT_SUCCESS; } else if (pid == (pid_t) 0) { close(mypipe[0]); char buf[100]; FILE *fp; char *fileName = argv[1]; int pidRacket = spawnfp(fileName, &amp;fp, mypipe[1]); fprintf(stderr, "%d: Writing PID %d to pipe\n", (int)getpid(), pidRacket); write_to_pipe(mypipe[1], pidRacket); fprintf(stderr, "%d: Written PID to pipe\n", (int)getpid()); if (argc == 1) { printf("Not enough arguments!"); _exit(EXIT_FAILURE); } else if (argc == 2) { } sleep(1); while (fgets(buf, sizeof buf, fp)) { printf("%s\n", buf); } fclose(fp); fprintf(stderr, "%d: Finished reading from pipe\n", (int)getpid()); kill(pid, SIGKILL); return 0; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

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