C on LINUX - Multiple child proces exec unusual number of times - c

I'm trying to create n = 10 child processes and make its execute a peace of code ..
However it creates 14 child processes indifferent of n.
Why is that?
This is the sample code :
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("It worked! ");
return 0;
}
And this is the main program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
int main (int argc, char *argv[])
{
int n = 10;
pid_t pid;
int status = 0;
int fd2[2];
int i = 0;
while (i < n)
{
/*create the pipe */
if (pipe(fd2) == -1)
{
fprintf(stderr, "Problem at pipe: %s\n", strerror(errno));
exit(1);
}
/*create fork*/
pid = fork();
if (pid == -1)
{
fprintf(stderr, "Problem at fork: %s\n", strerror(errno));
exit(1);
}
else if (pid == 0) /*in child*/
{
close(fd2[0]);
close(1);
dup2(fd2[1], 1);
close(fd2[1]);
execl("sample.bin", "sample.bin", NULL);
fprintf(stderr, "Problem at exec: %s", strerror(errno));
exit(1);
}
/* in parent */
close(fd2[1]);
char line[255];
if (n = read(fd2[0], line, 254))
{
printf("%d The message is: %s\n", i, line);
}
close(fd2[0]);
wait(&status);
i++;
}
return 0;
}

I corrected the code, now the output is what I've expected. And of course another problem was that I used at read the same variable n.
I modified from this:
if (n = read(fd2[0], line, 254))
{
printf("%d The message is: %s\n", i, line);
}
To this:
int m;
while((m = read(fd2[0], line, 254) > 0)
{
printf("%d The message is: %s\n", i, line);
}

Related

C program hangs after fork

I have made the following program :
The aim is to make 5 child processes and have parent process send a string to each child process
to print. If I pass the argument xyz then this program prints xyz 2 times and then hangs.
Not sure why that is happening.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int num_processes = 5;
int pipefd[num_processes][2];
pid_t cpid;
char buf;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
for (int i = 0; i < num_processes; i++)
{
if (pipe(pipefd[i]) == -1)
{
perror("pipe");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < num_processes; i++)
{
cpid = fork();
if (cpid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0)
{ /* Child reads from pipe */
close(pipefd[i][1]); /* Close unused write end */
while (read(pipefd[i][0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[i][0]);
}
else
{ /* Parent writes argv[1] to pipe */
close(pipefd[i][0]); /* Close unused read end */
write(pipefd[i][1], argv[1], strlen(argv[1]));
close(pipefd[i][1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
}
}
_exit(EXIT_SUCCESS);
}

Scanf in while loop not able to input anything

I'm using a Linux 2.0.26 VM and never have this problem.
The while loop works because I added a printf inside it in order to test it.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void main()
{
int i;
mknod("pipe.txt", S_IFIFO | 0666, 0);
for (i = 0; i < 2; i++) {
if (fork() == 0) {
if (i == 0)
to_pipe();
//else
// pipe_a_archivo();
}
}
wait(NULL);
unlink("pipe.txt");
}
void to_pipe()
{
int num, fdini;
fdini = open("pipe.txt", O_WRONLY);
do {
//printf("Test");
scanf("%d", &num);
write(fdini, &num, sizeof(int));
} while (num != 0);
close(fdini);
unlink("pipe.txt");
exit();
}
This program should get numbers from keyboard and write them in a file. My problem is that whenever I execute the program from the command line, nothing happens, scanf() doesn't work because it doesn't let me input any number. I know for sure that the loop works because if uncomment printf() it prints on the screen. Any help on solving this problem?
I think that most of your problem is due to you not implementing the pipe_a_archivo() function to read from the FIFO and write the data to a file. Certainly, the code in the question is not a good MCVE (Minimal, Complete, Verifiable Example). Amongst other problems, there is no action for the second iteration of the loop.
This code error checks function calls, and includes a plausible implementation of pipe_a_archivo(), and then works sensibly:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
static void to_pipe(void);
static void pipe_a_archivo(void);
#define FIFO_NAME "pipe.txt"
#define FILE_NAME "archive.txt"
int main(void)
{
if (mkfifo(FIFO_NAME, 0666) != 0)
{
fprintf(stderr, "failed to create FIFO '%s'\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
if (fork() == 0)
to_pipe();
if (fork() == 0)
pipe_a_archivo();
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %d exited with status 0x%.4X\n", corpse, status);
unlink("pipe.txt");
}
static void to_pipe(void)
{
int num, fdini;
fdini = open(FIFO_NAME, O_WRONLY);
do
{
printf("Enter a number: ");
fflush(stdout);
scanf("%d", &num);
write(fdini, &num, sizeof(int));
} while (num != 0);
close(fdini);
exit(0);
}
static void pipe_a_archivo(void)
{
int fd_in = open(FIFO_NAME, O_RDONLY);
if (fd_in < 0)
{
fprintf(stderr, "Failed to open FIFO '%s' for reading\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
FILE *fp_out = fopen(FILE_NAME, "w");
if (fp_out == NULL)
{
fprintf(stderr, "Failed to open file '%s' for writing\n", FILE_NAME);
exit(EXIT_FAILURE);
}
int num;
while (read(fd_in, &num, sizeof(num)) == sizeof(num))
{
fprintf(fp_out, "%d\n", num);
}
close(fd_in);
fclose(fp_out);
exit(0);
}
I removed the loop in main() because a loop that tests which iteration it is on and then calls an appropriate function is really not a good design. This code also only deletes the FIFO in the main program, and only after both child processes have exited.
Sample run:
$ ./fifo29
Enter a number: 23
Enter a number: 34
Enter a number: 12931344
Enter a number: 0
PID 10939 exited with status 0x0000
PID 10940 exited with status 0x0000
$ cat archive.txt
23
34
12931344
0
$

Sending and receiving character array using piping through argv in C

So, I'm trying to create a pipe that sends char arrays back and forth through pipes that connect through argv[]. Right now, I'm stuck at receiving the array (param which is sent to c_param from the parent to the child.) in interface.c to receiving the characters 3 and 5 at db.c. I know that 3 and 5 are the index for argv[] that my pipes are at, but I'm not sure how to take that and print out my message in db.c.
interface.c creates the pipes, forks into a parent process and a child process. The char array param is transfered to the child process to char array c_param. Using snprintf, I made my pipe into a char to send using execl with my char array c_param.
interface.c:
int main (int argc, char *argv[])
{
int to_Child[2];
int to_Parent[2];
int id, toChildPipe, toParentPipe, err;
char param[100] = "This is the parameter!";
char sendPipe[100];
char recPipe[100];
/*CREATING PIPE*/
toChildPipe = pipe(to_Child);
toParentPipe = pipe(to_Parent);
if(toChildPipe == -1 || toParentPipe == -1)
{
printf ("Error on pipe creation: %d", errno);
exit (1);
}
/*Creating Child Process*/
id = fork();
if(id == 0)
{
/**
*
* IN THE CHILD Process
*
*/
close(to_Child[1]); //reading
close(to_Parent[0]); //writing
char c_param[100];
toChildPipe = read(to_Child[0], c_param, 100);
if (toChildPipe == -1)
{
//If failed
printf("Error on read from pipe from parent: %d\n",errno);
//exit with error
exit(2);
}//Error pipe from parent
snprintf(sendPipe,sizeof(sendPipe), "%d",to_Parent[0]);
snprintf(recPipe,sizeof(recPipe), "%d",to_Child[0]);
err = execl("./db","db",sendPipe,recPipe,(char *)0);
if(err == -1)
{
printf("Error on execl: %d\n", errno);
}//Error execl
toChildPipe = read(to_Child[0], c_param, 100);
if (toChildPipe == -1)
{
//If failed
printf("Error on read from pipe from parent: %d\n",errno);
//exit with error
exit(2);
}//Error pipe from parent
}//CHILD PROCESS
else if (id > 0)
{
/**
*
*IN THE PARENT PROCESS
*
*/
close(to_Child[0]); //writing
close(to_Parent[1]); //reading
toChildPipe = write(to_Child[1],param,100);
if(toChildPipe == -1)
{
printf("Error on write to pipe: %d", errno);
exit(3);
}
/*Piping was successful!*/
exit(0);
}//PARENT PROCESS
else
{
exit(4);
}
}
db.c started up from interface.c execl and should receive the parameters over argv[], which then should print it out.
db.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE *finput;
int j = 0;
int fd;
int toChildPipe;
char c_param[100];
if(argc > 1)
{
for(j ; j < argc ; j++)
printf("argv = %s\n", argv[j]);
printf("argc = %d\n",argc);
}
fd = atoi(argv[1]);
printf("Statement: %s\n", argv[fd]);
strcpy(c_param, argv[3]);
printf("filename: %s\n", c_param);
}
This is the current output I'm getting, I'm aware that 5 and 3 are the indexes I need to send a message and receive the message that I'm currently trying to print in db.c
output(db.c):
argv = db
argv = 5
argv = 3
argc = 3
Statement: TERM=xterm
I hope I gave you enough information, I appreciate any help you are willing to give me. Thank you in advance!
There were lots of little things wrong. Your biggest problems were your assumptions/assertions in db.c about the parameters passed to it by interface.c — there was a total mismatch between what was passed and what was expected. There was also a good deal of extraneous code in interface.c. In particular, the child read from the pipe before executing db, so there was nothing left on the pipe for db to read.
Here's the 'fixed' code, with some debug code still in place.
interface.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
int to_Child[2];
int to_Parent[2];
int id;
char param[100] = "This is the parameter!";
char sendPipe[100];
char recPipe[100];
if (pipe(to_Child) == -1 || pipe(to_Parent) == -1)
{
printf("Error on pipe creation: %d", errno);
exit(1);
}
printf("Pipes: C(%d,%d), P(%d,%d)\n", to_Child[0], to_Child[1], to_Parent[0], to_Parent[1]);
id = fork();
if (id == 0)
{
close(to_Child[1]); // Child does not write to itself
close(to_Parent[0]); // Child does not read what it writes
snprintf(sendPipe, sizeof(sendPipe), "%d", to_Parent[1]);
snprintf(recPipe, sizeof(recPipe), "%d", to_Child[0]);
execl("./db", "db", sendPipe, recPipe, (char *)0);
fprintf(stderr, "Error on execl: %d\n", errno);
exit(2);
}
else if (id > 0)
{
close(to_Child[0]); // Parent does not read childs input
close(to_Parent[1]); // Parent does not
int nbytes = write(to_Child[1], param, 100);
if (nbytes == -1)
{
fprintf(stderr, "Error on write to pipe: %d\n", errno);
exit(3);
}
close(to_Child[1]);
if ((nbytes = read(to_Parent[0], param, 100)) <= 0)
{
fprintf(stderr, "Error on read from pipe: %d\n", errno);
exit(5);
}
printf("Data from pipe: [%.*s]\n", nbytes, param);
exit(0);
}
else
{
perror("fork failed");
exit(4);
}
}
### db.c
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("argc = %d\n", argc);
for (int j = 0; j < argc; j++)
printf("argv[%d] = %s\n", j, argv[j]);
if (argc != 3)
{
fprintf(stderr, "Usage: %s write-fd read-fd\n", argv[0]);
return 1;
}
int ofd = atoi(argv[1]);
int ifd = atoi(argv[2]);
printf("ifd = %d; ofd = %d\n", ifd, ofd);
char c_param[100];
int nbytes = read(ifd, c_param, sizeof(c_param));
if (nbytes <= 0)
{
fprintf(stderr, "Error: failed to read any data (%d)\n", errno);
return 1;
}
printf("Child: [%.*s]\n", nbytes, c_param);
assert(strlen(c_param) + sizeof(" - sent back to parent") <= sizeof(c_param));
strcat(c_param, " - sent back to parent");
if (write(ofd, c_param, nbytes) != nbytes)
{
fprintf(stderr, "Error: failed to write all the data (%d)\n", errno);
return 1;
}
return 0;
}
Sample run
Pipes: C(3,4), P(5,6)
argc = 3
argv[0] = db
argv[1] = 6
argv[2] = 3
ifd = 3; ofd = 6
Child: [This is the parameter!]
Data from pipe: [This is the parameter! - sent back to parent]
Note that the code reports errors to standard error (that's what it is for). It also delimits the printed data which can make it easier to spot
unexpected problems. It doesn't assume that the data is null padded; it limits the length printed to the length read, though in fact the data has numerous nulls at the end.

Parent process killing child process in infinite loop

To solve my problem, I set
prctl(PR_SET_PDEATHSIG, SIGHUP); as in stackoverflow answer before i called exec*, and took out the part where we pipe the PID. It works!!!!! Wow....
HOWEVER, stackoverflow won't let me say I've answered my own question yet...
So I tried to write a program, which I want to run a program, and kill that program after a cpl seconds if it doesn't finish. DADDY forks off a CHILD, which forks off another BABY, CHILD pipes the PID of the BABY to DADDY, which then waits a second and kills them both if they haven't wrapped up their business (it's a macabre scene). But it doesn't work, DADDY stays in S+ State, and the infinite loop that is Baby goes on forever until I ctr+c. On the bright side, this code is an amalgamation of everything I've learnt on stack-overflow. Here we go.
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
if (fscanf(stream, "%d", &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) < 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, &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 < (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 < 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, &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;
}
}
Credit to quinsley and vijay!
Various comments as I look at the code:
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.
Don't use _exit() if you want your error messages to appear, especially ones that don't end in a newline.
Don't report error messages on standard output; report them on standard error (that's what it is for!).
Writing else if (argc == 2) { } (with nothing in the braces) is a little odd if there is an else clause after it, but it is pointless when there is no else clause. You should arguably test for argc != 2 since that is the correct number of arguments (or, perhaps more accurately, any arguments beyond argc == 2 are ignored).
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, nanosleep() is probably the function to use.
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).
case -1: printf("syserr"); with no break; after it means that on error, the flow of control goes into the following case 0: code, which is not what's required. Either break; or exit(1); is probably appropriate. (Bullet 3 applies too.)
Don't close standard error. The 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);
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.
Some of the casts in:
diff = ((double)((uintmax_t)(clock_t)done) - (double)((uintmax_t)(clock_t)launch)) / (double)CLOCKS_PER_SEC;
are unnecessary. Since both done and launch are of the type clock_t, the casts to clock_t are unnecessary. The intermediate cast to uintmax_t also isn't really necessary. You could simply write:
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
and even then, two of the three casts are theoretically redundant (any two of the three could be removed).
The code in read_from_pipe() is curious and error prone. Since you've got a file stream, simply read an integer from it using fscanf(), rather than the curious construct using double arithmetic and fractional values that are then multiplied at the end. This is especially appropriate since the write_to_pipe() code uses printf("%d", ...); to write the data. Since c is already an int, the cast in return (int)c; is superfluous.
Theoretically, it would be a good idea to check the streams returned by fdopen() to ensure that the operation did not fail.
If the pipe() function fails, you report the error on standard output and then continue as nothing had gone wrong.
It is not clear what the racket command actually does. It doesn't exist on my machine.
argv in spawnfp() is unused.
pid = fork(); if (pidDos < (pid_t) 0) generates a warning (accurately) that pidDos might be used uninitialized. The condition should presumably be using pid, not pidDos. You then send a SIGKILL signal to the PID identified at random by pidDos, which is unlikely to lead to happiness.
When I copy cat to racket and invoke the following code (as a program mk built from mk.c) as mk /etc/passwd, I get to see the password file double-spaced (and the message from the shell about Killed: 9.
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
if (fscanf(stream, "%d", &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) < 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, &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 < (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 < 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, &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;
}
}
I fixed some, but by no means all, of the issues identified in this revision of the code.
Oh, and item 16: the read end of the pipe isn't closed until the third process terminates. You need to pass mypipe[1] to spawnfp(), which needs to relay it to spawnpipe(), and the child created there needs to close the pipe descriptor before executing 'racket'. This is compounded by fscanf() 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 racket doesn't terminate, that's why you don't see anything much.
It's easier to paste the whole program again than present the diffs:
#include <assert.h>
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
assert(stream != 0);
if (fscanf(stream, "%d", &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) < 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, &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 < (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 < 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, &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;
}
}
I made this a while back for stupid fun, it uses up a big chunk of your cpu to run but I'm sure you can modify it to break at a certain point or to fit your needs maybe.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc, char*argv[])
{
int childpid;
int pids[100];
int count1 = 0, count2 = 0;
int count3 = 0;
L1:
childpid = fork();
if(childpid == 0)
{
}
else
{
if(childpid != 0 && childpid != -1)
{
if(count3 < 100)
{
pids[count3] = childpid;
printf("Pid:%d\n",pids[count3]);
count3++;
goto L1;
}
else
{
count3--;
goto L2;
}
}
L2:
while(count3 > 0)
{
if(pids[count3] != -1 || pids[count3] != 1)
{
printf("Killing pid:%d\n",pids[count3]);
kill(pids[count3],SIGKILL);
}
count3--;
}
if(count3 == 0)
{
goto L1;
}
}
return 0;
}

child process pending after read in coprocess

I'm writing a coprocess program using pipe. It works fine when the child read some data, handle it and output it. But when I read all the data and handle it, it just pending. Any body have some idea? Thank you.
Here is the source code:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
#define MAXSIZE 1024
char workload[MAXSIZE];
char result[MAXSIZE];
workload[strlen(workload)] = EOF;
int workload_size = strlen(workload);
int fd1[2], fd2[2];
int n;
pid_t pid;
if (pipe(fd1) < 0 || pipe(fd2) < 0) {
fprintf(stderr, "pipe error: %s\n", strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
fprintf(stderr, "fork error: %s\n", strerror(errno));
exit(1);
} else if (pid > 0) {
close(fd1[0]);
close(fd2[1]);
while(fgets(workload, MAXSIZE, stdin) != NULL)
{
workload_size = strlen(workload);
if (write(fd1[1], workload, workload_size) != workload_size) {
fprintf(stderr, "write to pipe error: %s\n", strerror(errno));
exit(1);
}
if ((n = read(fd2[0], result, MAXSIZE)) < 0) {
fprintf(stderr, "read from pipe error: %s\n", strerror(errno));
exit(1);
}
if (n == 0) {
fprintf(stderr, "child closed the pipe\n");
exit(1);
}
result[n] = 0;
if (puts(result) == EOF) {
fprintf(stderr, "fputs error\n");
exit(1);
}
}
} else {
close(fd1[1]);
close(fd2[0]);
if (fd1[0] != STDIN_FILENO) {
if (dup2(fd1[0] ,STDIN_FILENO) != STDIN_FILENO) {
fprintf(stderr, "dup2 error to stdin.\n");
exit(1);
}
close(fd1[0]);
}
if (fd2[1] != STDOUT_FILENO) {
if (dup2(fd2[1] ,STDOUT_FILENO) != STDOUT_FILENO) {
fprintf(stderr, "dup2 error to stdout.\n");
exit(1);
}
close(fd2[1]);
}
if (execl("./a.out", "a.out", NULL) < 0) {
fprintf(stderr, "execl error: %s\n", strerror(errno));
exit(1);
}
exit(0);
}
return 0;
}
Here is the source code of a.out, it works well with this:
#include <stdio.h>
#include <string.h>
int main()
{
#define MAXSIZE 1024
char x[MAXSIZE];
int n;
while(scanf("%s", x) != EOF)
{
printf("len:%d %s", strlen(x), x);
fflush(stdout);
}
return 0;
}
But it seems just pending when I write the code like this:
#include <stdio.h>
#include <string.h>
int main()
{
#define MAXSIZE 1024
char x[MAXSIZE];
int n;
while(scanf("%s", x) != EOF);
printf("Ok\n");
fflush(stdout);
return 0;
}
The way you are calling scanf with %s may overflow the x buffer. You should at least modify the scanf with a width modifier.
#include <stdio.h>
#include <string.h>
int main()
{
#define MAXSIZE 1024
char x[MAXSIZE];
int n;
while(scanf("%1024s", x) != EOF)
{
printf("len:%d %s", strlen(x), x);
fflush(stdout);
}
return 0;
}
And similarly for your other program.
The reason your program is getting blocked is because your second a.out program is looped doing another scanf, when at the same time the parent program is trying to read a response back into result.
You should test and loop while not feof and you might use popen & pclose
You probably want to use some multiplexing system call like poll

Resources