I am supposed to write a program that runs two scripts in two separate processes and returns which one finished first. Unfortunately, my program returns the slower process, which confuses me. I made sure that the pids were not 0, so that they weren't child processes. I then compared the pids of each process to the pid of the process that finished first, but for some reason, the slower program gets printed.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
if (argc != 3) {
printf("Invalid number of arguments!");
exit(1);
}
pid_t one;
pid_t two;
int status = 0;
pid_t winner;
char const *args[] = {"/bin/sh", argv[1], argv[2], NULL};
if ((one = fork()) == 0) {
printf("%s is starting.\n",argv[1]);
execv(args[0], args[1]);
}
if ((two = fork()) == 0 && (one != 0)) {
printf("%s is starting\n",argv[2]);
execv(args[0], args[2]);
}
if (one != 0 && two != 0) {
winner = wait(&status);
if (winner == -1) {
if (one == winner) {
kill(one, SIGKILL);
printf("%s wins by default!\n", argv[2]);
}
else if (two == winner) {
kill(two, SIGKILL);
printf("%s wins by default!\n", argv[1]);
}
}
else {
if (one == winner) {
kill(two, SIGKILL);
printf("%s is finished!\n", argv[1]);
printf("%s is the winner\n", argv[1]);
}
if (two == winner) {
kill(one, SIGKILL);
printf("%s is finished!\n", argv[2]);
printf("%s is the winner\n", argv[2]);
}
}
}
return 0;
}
Related
I am trying to learn processes in C and I thiiink I understood the logic of pipe, but can't understand fifo, even if I read a lot about it. I recently made a program using pipe that takes a string from standard input, writes it in pipe1, checks if it's alphanumeric and if so, pipe3 reads it and shows it. If the string only contains digits, pipe2 reads it and replaces digits with _, then pipe4 reads the new string and shows it.
I'm putting it here, because I want to make something similar using fifo:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
#include<ctype.h>
int main()
{
int p1[2];
int p2[2];
int p3[2];
int p4[2];
char input_str[100];
pid_t fork1;
pid_t fork2;
if (pipe(p1)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(p2)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(p3)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(p4)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
scanf("%s", input_str);
int isAlpha = 0;
int onlyDigits = 0;
for (int i=0; input_str[i]!= '\0'; i++)
{
if (isalpha(input_str[i]) != 0) {
isAlpha = 1;
onlyDigits = 0;
}
else if (isdigit(input_str[i]) != 0) {
isAlpha = 1;
onlyDigits = 1;
}
else {
isAlpha = 0;
onlyDigits = 0;
}
}
fork1 = fork();
if (fork1 < 0)
{
fprintf(stderr, "fork Failed" );
return 1;
}
else if (fork1 > 0)
{
close(p1[0]);
write(p1[1], input_str, strlen(input_str)+1);
}
else
{
close(p1[1]);
char string_from_p1[100];
read(p1[0], string_from_p1, 100);
close(p1[0]);
fork2 = fork();
if (onlyDigits) {
for (int i=0; string_from_p1[i]!= '\0'; i++) {
if (isdigit(string_from_p1[i]) != 0)
string_from_p1[i] = '_';
}
write(p2[1], string_from_p1, strlen(string_from_p1)+1);
}
else if (isAlpha) {
write(p3[1], string_from_p1, strlen(string_from_p1)+1);
}
if (fork2 < 0) {
fprintf(stderr, "fork Failed" );
return 1;
}
else if (fork2 > 0) {
char string_from_p2[100];
char string_from_p3[100];
char string_from_p4[100];
if (onlyDigits) {
close(p2[1]);
read(p2[0], string_from_p2, 100);
close(p2[0]);
write(p4[1], string_from_p2, strlen(string_from_p2)+1);
close(p4[1]);
read(p4[0], string_from_p4, 100);
printf("String from pipe4: %s\n", string_from_p4);
}
else if (isAlpha) {
close(p3[1]);
read(p3[0], string_from_p3, 100);
printf("String from pipe3: %s\n", string_from_p3);
}
}
exit(0);
}
}
Not sure how correct that is, but the FIFO program will only have 3 processes, it first reads from standard input lines of max 30 characters, writes in first exit (process2) the digits and in second exit (process3) the letters. then in process2 only shows the result (digits found), and in process3 turns small letters into capital letters and shows the result.
Can someone please help me?
As a starting point you could try something like this (most of the functions needs still to be implemented, see comments):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
void read_and_write(const char *digits_fifo, const char *chars_fifo);
pid_t spawn_digits_child(const char *digits_fifo);
pid_t spawn_chars_child(const char *chars_fifo);
void digits_child(const char *digits_fifo);
void chars_child(const char *chars_fifo);
void wait_until_children_finish(pid_t pid1, pid_t pid2);
#define MAX_INPUT 30
int main() {
char *digits_fifo = "/tmp/digits_fifo";
char *chars_fifo = "/tmp/chars_fifo";
mkfifo(digits_fifo, 0666);
mkfifo(chars_fifo, 0666);
//fork digits process
pid_t pid_digits = spawn_digits_child(digits_fifo);
//fork chars process
pid_t pid_chars = spawn_chars_child(chars_fifo);
//parent
read_and_write(digits_fifo, chars_fifo);
wait_until_children_finish(pid_digits, pid_chars);
exit(0);
}
pid_t spawn_digits_child(const char *digits_fifo) {
pid_t pid1;
if ((pid1 = fork()) < 0) {
fprintf(stderr, "fork error digits process\n");
exit(-1);
} else if (pid1 == 0) {
digits_child(digits_fifo);
exit(0);
}
return pid1;
}
pid_t spawn_chars_child(const char *chars_fifo) {
//do sth similar then in spawn_digits_child but for chars child process
}
void wait_until_children_finish(pid_t pid1, pid_t pid2) {
//use waitpid to wait for child process termination
}
void read_and_write(const char *digits_fifo, const char *chars_fifo) {
//read input string
//open the two named pipes with O_WRONLY
//check with isdigit respective isalpha and send to the corresponding named pipe
//don't forget to close file handles
}
void chars_child(const char *chars_fifo) {
//open named piped with O_RDONLY
//e.g. int chars_fd = open(chars_fifo, O_RDONLY);
//read from pipe
//do uppercase string
//output it with printf
}
void digits_child(const char *digits_fifo) {
//open named piped with O_RDONLY
//e.g. int chars_fd = open(digits_fifo, O_RDONLY);
//read from pipe
//output it with printf
}
I'm trying to code a simple fork() and pipe() program which gets input from the user and outputs it through the pipe in the childprocess. But somehow I'm not getting the result I wished to get.
The first input works fine, for example I type in "Hi" and get the result "Prozessmanager: Hi", but as soon as I try to input the next string, it crashes or somehow stops working until I input a "Q" which exits my Program.
I tried to debug it and got the result, that I'm trying to write into a broken pipe.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
//#include <signal.h>
#define BUFSIZE 512
//int clock = 0;
//void handler(int signum) {
//clock++;
//printf("Clock: 00:00:%d\n", clock);
//}
int main(int argc, char** argv) {
pid_t prozessmanager;
pid_t reporter;
int pipefd[2];
int status;
char str[BUFSIZE];
char buf[BUFSIZE];
if ((pipe(pipefd)) == -1) {
perror("pipe() error");
exit(1);
}
if ((prozessmanager = fork()) == -1) {
perror("fork() error");
exit(1);
} else if (prozessmanager == 0) { //Prozessmanager prozess
while (1) {
//signal(SIGALRM, handler);
//while(1){
//alarm(1);
//}
close(pipefd[1]);
read(pipefd[0], buf, sizeof (buf));
/*if (*buf == 'S') {
//handler(clock);
} else {*/
if (*buf == 'P') {
if ((reporter = fork()) == -1) {
perror("fork() error");
exit(1);
} else if (reporter == 0) { //Reporter prozess
printf("Im a Report Prozess, PID: %d\n", getpid());
exit(0);
} else { //Prozessmanager waits for Reporter
wait(&status);
printf("Report terminated, PID: %d\n", reporter);
break;
}
} else if (*buf == 'Q') {
printf("Exit Prozessmanager, PID: %d\n", getpid());
exit(0);
} else {
printf("Prozessmanager: %s", buf);
break;
}
//}
}
} else { //Kommandant prozess
while (1) {
close(pipefd[0]);
fgets(str, 80, stdin);
write(pipefd[1], str, sizeof (str));
if (*str == 'Q') {
break;
}
}
wait(&status);
printf("Exit Kommandant, PID: %d\n", getpid());
exit(0);
}
return (0);
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
int main(int argc, char **argv){
int n = atoi(argv[1]);
int superdaddy = getpid();
int p[n+1][2];
int i=0;
int cpid,output;
int result = 0;
if(pipe(p[0])<0){
perror("1");
return 1;
}
if(pipe(p[n])<0){
perror("2");
return 1;
}
output = p[0][1];
if(getpid()==superdaddy){
if(write(p[0][1],&result,sizeof(result))<0){
perror("3");
return 1;
}
if(close(p[0][1])<0){
perror("4");
return 1;
}
}
while(1){
if(i==n){
if(read(p[n-1][0],&result,sizeof(result)<0)){
perror("5");
return 1;
}
result++;
output = p[n][1];
if(write(output,&result,sizeof(result))<0){
perror("6");
return 1;
}
if(close(p[n-1][0])<0){
perror("7");
return 1;
}
if(close(p[n][1])<0){
perror("8");
return 1;
}
break;
}
i++;
cpid = fork();
if(cpid==0){
if(i==n)
continue;
if(pipe(p[i])<0){
perror("9");
return 1;
}
if(read(p[i-1][0],&result,sizeof(result))<0){
perror("10");
return 1;
}
result++;
output = p[i][1];
if(write(output,&result,sizeof(result))<0){
perror("11");
return 1;
}
if(close(p[i-1][0])<0){
perror("12");
return 1;
}
if(close(p[i][1]<0)){
perror("13");
return 1;
}
continue;
}
else if(cpid<0){
perror("14");
return 1;
}
break;
}
if(getpid()==superdaddy){
wait(NULL);
if(read(p[n][0],&result,sizeof(result))<0){
perror("15");
return 1;
}
printf("Result: %d\n",result);
if(close(p[n][0])<0){
perror("16");
return 1;
}
}
return 0;
}
The Program aims to read a number n from command line and then forks n child process and create n pipes. process p0 will be parent of process p1, p1 will be parent of p2, so and so on. One variable (named result here) will be passed through pipes, every time it is passed it will be added by 1. So the output should be n as well. Pipe Fi connects Pi and P(i+1). Attached is my code.
When n=1 or n=2, the program can output correctly, which is 1 and 2 correspondingly. However, when n=3, it gives me a bad file error at error 5. I have hand-tracked the code for the whole afternoon but got no idea what is wrong with it. Anyone could help? Appreciate it first!
when n=3, it gives me a bad file error at error 5.
This could be fixed by removing that if(close(p[i][1]<0)){ in your code, because you need to read from p[i][0] in your last iteration, i.e.
if (i == n) {
if(read(p[n-1][0],&result,sizeof(result)<0)){
...
}
}
This is an implementation of your idea, I hope it may be helpful:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s N\n", argv[0]);
exit(EXIT_FAILURE);
}
int n = atoi(argv[1]);
int pipes[n][2];
int i, val;
pid_t pid;
val = 0;
for (i = 0; i < n; i++) {
if (pipe(pipes[i]) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
if ((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0) {
close(pipes[i][1]);
if (read(pipes[i][0], &val, sizeof(val)) != sizeof(val)) {
perror("read");
exit(EXIT_FAILURE);
}
printf("C %d read %d\n", getpid(), val);
val++;
}
else {
close(pipes[i][0]);
printf("P %d writes %d\n", getpid(), val);
if (write(pipes[i][1], &val, sizeof(val)) != sizeof(val)) {
perror("write");
exit(EXIT_FAILURE);
}
if (waitpid(pid, NULL, 0) != pid) {
perror("waitpid");
exit(EXIT_FAILURE);
}
printf("%d is going to leave.\n", getpid());
exit(EXIT_SUCCESS);
}
}
printf("%d is going to leave.\n", getpid());
exit(EXIT_SUCCESS);
}
Testing run:
$ ./a.out 3
P 2005 writes 0
C 2006 read 0
P 2006 writes 1
C 2007 read 1
P 2007 writes 2
C 2008 read 2
2008 is going to leave.
2007 is going to leave.
2006 is going to leave.
2005 is going to leave.
Explanation:
The frame of that code is for (i = 0; i < n; i++) { pipe(); fork(); }, which means it will create n pipes, and n new processes. In each iteration, the parent will write to pipes[i][1] and child will read from pipes[i][0]. Eventually, it will create a process chain connected by a series of pipes, and a value is passed down from the first process to the last through that series of pipes.
I have a program which I would like to sort the first column in a file, from a child process, and return the output to the parent process. How can I retrieve the response from the execlp and print it? Here is what I have so far:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define WRITE 1
#define READ 0
int main(int argc, char **argv)
{
int i, k;
int p1[2], p2[2];
int p1[2], p2[2];
pid_t childID;
if (pipe(p1) < 0 || pipe(p2) < 0) {
perror("pipe");
exit(0);
}
childID = fork();
if (childID < 0) {
perror("fork");
exit(0);
}
else if (childID == 0){
close(p1[WRITE]);
close(p2[READ]);
dup2(p1[READ], STDIN_FILENO);
close(p1[READ]);
dup2(p2[WRITE], STDOUT_FILENO);
close(p2[WRITE]);
execlp("sort", "-k1", "-n", "temp.txt", (char *)NULL);
perror("exec");
exit(0);
}
else {
//parent process
//Not sure how to get response from exec
}
}
After call execlp(), the memory image of current process will be replaced by the called progame, so you cannot get what you want through return value. What you can do is let the child process write its result to somehere, such as a temporal file or a pipe, and the parent process read the result from this place.
After proper setup a pipe to communite between parent and child processes, you can write the result of child process in its stdout, and read the result in parent processes from its stdin.
Something like this:
else if (childID == 0){
close(p1[READ]);
dup2(p1[WRITE], STDOUT_FILENO);
close(p1[WRITE]);
execlp("sort", "-k1", "-n", "temp.txt", (char *)NULL);
perror("exec");
exit(0);
}
else {
close(p1[WRITE]);
dup2(p1[READ], STDIN_FILENO);
close(p1[READ]);
while (scanf("%ms ", &l) != EOF) {
printf("%s\n", l);
free(l);
}
}
Here is full code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define WRITE 1
#define READ 0
int main(int argc, char **argv)
{
int p1[2];
char *l;
pid_t childID;
if (pipe(p1) < 0) {
perror("pipe");
exit(0);
}
childID = fork();
if (childID < 0) {
perror("fork");
exit(0);
}
else if (childID == 0){
close(p1[READ]);
dup2(p1[WRITE], STDOUT_FILENO);
close(p1[WRITE]);
execlp("sort", "-k1", "-n", "temp.txt", (char *)NULL);
perror("exec");
exit(0);
}
else {
close(p1[WRITE]);
dup2(p1[READ], STDIN_FILENO);
close(p1[READ]);
while (scanf("%ms ", &l) != EOF) {
printf("%s\n", l);
free(l);
}
}
return 0;
}
And test file temp.txt:
$ cat temp.txt
a
e
b
d
f
c
Result of a test run:
$ ./a.out
a
b
c
d
e
f
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;
}