child process pending after read in coprocess - c

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

Related

Interprocess message queue in c?

I'm writing a program in C using inter-process communication, specifically I'm trying to write a program using an inter-process message queue. The program should work like this:
The command line accepts n-files (at least one). N-processes will be created as much as files.
The n processes must send the contents of the file to a process called Receiver which will have the task of printing the messages received.
The problem is: not all the contents of the file are printed, even if the processes send the messages. Why ? Could anyone tell me where I'm going wrong?
This is my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#define DIM_MSG 1024
#define TYPE_W 2
typedef struct
{
long mtype;
char eof;
char mtext[DIM_MSG];
} msg;
void child_r(int coda, const char *file)
{
FILE *r_stream;
if ((r_stream = fopen(file, "r")) == NULL)
{
perror("errore apertura file");
exit(1);
}
printf("%s:\n",file);
msg messaggio;
while (fgets(messaggio.mtext, DIM_MSG, r_stream) != NULL)
{
messaggio.mtype = TYPE_W;
messaggio.eof = 0;
if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long) , 0) == -1)
{
perror("msgsnd");
exit(1);
}
printf("\tMessage send: %s", messaggio.mtext);
}
strcpy(messaggio.mtext, "quit");
messaggio.eof = 1;
messaggio.mtype = TYPE_W;
if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long) , 0) == -1)
{
perror("msgsnd");
exit(1);
}
fclose(r_stream);
exit(0);
}
void child_f(int coda)
{
msg messaggio;
printf("\nReceiver\n");
do
{
if (msgrcv(coda, &messaggio, sizeof(msg) - sizeof(long), TYPE_W, 0) == -1)
{
perror("msgrcv");
exit(1);
}
if (strcmp(messaggio.mtext, "quit") != 0)
{
printf("\tMessage rcv: %s ", messaggio.mtext);
}
} while (messaggio.eof != 1);
exit(0);
}
int main(int argc, char const *argv[])
{
char *file_name = NULL;
struct stat sb;
int child=0;
int ds_coda;
if(argc<1)
{
fprintf(stderr,"Utilizzo %s <file-1> <file-2> <file-n>....",argv[0]);
exit(1);
}
if((ds_coda=msgget(IPC_PRIVATE,IPC_CREAT|IPC_EXCL|0600))==-1)
{
perror("coda");
exit(1);
}
/* analizza la command-line */
for (int i = 1; i < argc; i++) {
if ((stat(argv[i], &sb) == 0) && (S_ISREG(sb.st_mode)))
{
file_name = (char*)argv[i];
child++;
if(fork()==0)
{
child_r(ds_coda, file_name);
}
}
else {
perror(argv[i]);
exit(1);
}
}
if(child==0)
{
fprintf(stderr,"Parametri non validi!\n");
exit(1);
}
if(fork() == 0)
{
// child_w
sleep(1);
child_f(ds_coda);
}
else wait(NULL);
msgctl(ds_coda, IPC_RMID, NULL);
return 0;
}
A few issues ...
The main process needs to loop on wait before doing IPC_RMID. Otherwise, the sender processes will fail on msgsnd because the ds_coda is no longer valid. The main process has "raced" with the sender/receiver processes and removed the id with IPC_RMID before the other processes have completed.
All senders will set messsaggio.eof but the receiver stops after receiving the first one. It must know how many senders there are and wait until all have sent EOF. (i.e.) It must maintain a count.
Before I could debug this, I had to enhance the logging. So, I created tscgetf, logopen, and logprt to create separate logs for each process with timestamps.
When I was getting close, I added the from field to the message because the receiver was getting data but didn't know which process sent it. This helped diagnose the EOF issue.
Here is the refactored code. It is annotated with the bugs and fixes.
By default, it will show the EOF issue (i.e. it will hang). To apply the fix for the EOF issue, compile with -DFIXEOF
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <time.h>
#define DIM_MSG 1024
#define TYPE_W 2
typedef struct {
long mtype;
int from;
char eof;
char mtext[DIM_MSG];
} msg;
int pididx; // linear process ID (0=main)
int child = 0; // number of spawned children
int ds_coda;
FILE *xflog; // debug log stream
#define logprt(_fmt...) \
do { \
fprintf(xflog,"[%.9f/%5.5d] ",tscgetf(),pididx); \
fprintf(xflog,_fmt); \
fflush(xflog); \
} while (0)
double tsczero;
// tscget -- get timestamp
// RETURNS: elapsed seconds
double
tscgetf(void)
{
struct timespec ts;
double sec;
clock_gettime(CLOCK_MONOTONIC,&ts);
sec = ts.tv_nsec;
sec /= 1e9;
sec += ts.tv_sec;
sec -= tsczero;
return sec;
}
void
logopen(void)
{
char logf[100];
if (xflog != NULL)
fclose(xflog);
sprintf(logf,"log%3.3d",pididx);
xflog = fopen(logf,"w");
if (xflog == NULL) {
perror(logf);
exit(1);
}
}
void
child_r(int coda, const char *file)
{
FILE *r_stream;
logopen();
if ((r_stream = fopen(file, "r")) == NULL) {
perror("errore apertura file");
exit(1);
}
logprt("child_r: reading %s\n", file);
msg messaggio;
messaggio.from = pididx;
while (fgets(messaggio.mtext, DIM_MSG, r_stream) != NULL) {
messaggio.mtype = TYPE_W;
messaggio.eof = 0;
if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long), 0) == -1) {
perror("msgsnd");
exit(1);
}
logprt("Message send: %s", messaggio.mtext);
}
strcpy(messaggio.mtext, "quit");
messaggio.eof = 1;
messaggio.mtype = TYPE_W;
#if 1
strcpy(messaggio.mtext,"I_AM_EOF\n");
#endif
if (msgsnd(coda, &messaggio, sizeof(msg) - sizeof(long), 0) == -1) {
perror("msgsnd");
exit(1);
}
logprt("Message EOF: %s", messaggio.mtext);
fclose(r_stream);
logprt("child_r: finished %s\n", file);
fclose(xflog);
exit(0);
}
void
child_f(int coda)
{
msg messaggio;
logopen();
// NOTE: we are started last so the count we need to wait for is one less
int waitcnt = pididx - 1;
logprt("Receiver starting -- waitcnt=%d\n",waitcnt);
while (1) {
if (msgrcv(coda, &messaggio, sizeof(msg) - sizeof(long), TYPE_W, 0) == -1) {
perror("msgrcv");
exit(1);
}
if (strcmp(messaggio.mtext, "quit") != 0) {
logprt("Message rcv (from %d): %s",
messaggio.from, messaggio.mtext);
}
if (messaggio.eof == 1) {
// NOTE/BUG: we can't stop after the first EOF message -- we must wait for all
// of them
#if ! FIXEOF
logprt("got EOF\n");
break;
#else
logprt("got EOF -- waitcnt=%d\n",waitcnt);
if (--waitcnt <= 0)
break;
#endif
}
}
logprt("child_f: complete\n");
fclose(xflog);
exit(0);
}
// start_rcv -- start receiver process
void
start_rcv(void)
{
logprt("start_rcv:\n");
child++;
pid_t pid = fork();
if (pid == 0) {
pididx = child;
// child_w
// NOTE/BUG: not necessary with other fixes
#if 0
sleep(1);
#endif
child_f(ds_coda);
}
logprt("start_rcv: pid=%d child=%d\n",pid,child);
}
int
main(int argc, char const *argv[])
{
char *file_name = NULL;
struct stat sb;
tsczero = tscgetf();
#if 1
pid_t pid;
setlinebuf(stdout);
setlinebuf(stderr);
#endif
logopen();
if (argc < 1) {
fprintf(stderr, "Utilizzo %s <file-1> <file-2> <file-n>....", argv[0]);
exit(1);
}
if ((ds_coda = msgget(IPC_PRIVATE, IPC_CREAT | IPC_EXCL | 0600)) == -1) {
perror("coda");
exit(1);
}
// NOTE: early attempt to fix (receiver should start first) but didn't fix it
// and won't work because receiver needs to know the number of EOF messages to
// wait for
#if RCVEARLY
start_rcv();
#endif
/* analizza la command-line */
for (int i = 1; i < argc; i++) {
if ((stat(argv[i], &sb) == 0) && (S_ISREG(sb.st_mode))) {
file_name = (char *) argv[i];
child++;
pid = fork();
if (pid == 0) {
pididx = child;
child_r(ds_coda, file_name);
}
#if 1
else {
logprt("forked: pid=%d child=%d\n",pid,child);
}
#endif
}
else {
perror(argv[i]);
exit(1);
}
}
if (child == 0) {
fprintf(stderr, "Parametri non validi!\n");
exit(1);
}
// NOTE/FIX: main process must wait for _all_ children to complete before
// doing IPC_RMID
#if 1
#if ! RCVEARLY
start_rcv();
#endif
while (1) {
pid_t pid = wait(NULL);
logprt("waitfor: %d child=%d\n",pid,child);
if (pid <= 0)
break;
--child;
}
#endif
msgctl(ds_coda, IPC_RMID, NULL);
fclose(xflog);
return 0;
}
In the code above, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k

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

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);
}

Redirect stdin/out to pipe and use in child process

I'm writing a simple application which will use anonymous pipes to communicate with child process called using execl().
Child process is simple echo application.
I want to redirect stdin and stdout to pipes and use them to receive data sent by child in parent.
Now only two lines are echoed.
Any ideas what is wrong?
Here is my code:
(parent.c)
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
int main()
{
int parent_to_child[2];
int child_to_parent[2];
if(pipe(parent_to_child) == -1) exit(-1);
if(pipe(child_to_parent) == -1) exit(-1);
switch(fork())
{
case -1: exit(-1);
case 0: //child
if(close(0) == -1) exit(-1);
if(dup(parent_to_child[0]) != 0) exit(-1);
fprintf(stderr, "stdin changed\n");
if(close(1) == -1) exit(-1);
if(dup(child_to_parent[1]) != 1) exit(-1);
fprintf(stderr, "stdout changed\n");
close(parent_to_child[0]);
close(parent_to_child[1]);
close(child_to_parent[0]);
close(child_to_parent[1]);
execl("./child_process","child_process", (char*)NULL);
exit(-1);
default: //parent
close(parent_to_child[0]);
close(child_to_parent[1]);
size_t size = 1024;
char* line = (char *) malloc(size);
while(getline(&line, &size, stdin) != -1)
{
if(write(parent_to_child[1], line, (strlen(line)+1)*sizeof(char)) == -1)
{
printf("%d", errno);
exit(-1);
}
read(child_to_parent[0], line, size);
printf("%s", line);
}
}
return 0;
}
(child_process.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
size_t size = 1024;
char* line = (char*) malloc(size);
setlinebuf(stdout);
setlinebuf(stdin);
fprintf(stderr, "child started\n");
while(getline(&line, &size, stdin) != -1)
{
printf("%s", line);
}
fprintf(stderr, "exiting");
free(line);
return 0;
}

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;
}

console based chat application in c

i created this application in which two processes communicate. everything is well
but i want that when the user press esc the process ends automatically.
s*econdly it is getting only one line from user. at a time in one process*. and before entering second line we have to add a line to the other process also.
here is the code for process 1(i called server)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
extern int errno;
#define FIFO1 "/tmp/fifo.1"
#define FIFO3 "/tmp/fifo.3"
#define PERMS 0666
#define MESSAGE1 "client Says:"
main()
{
char buff[BUFSIZ];
int readfd, writefd;
int n, size;
if ((mknod (FIFO1, S_IFIFO | PERMS, 0) < 0) && (errno != EEXIST)) {
perror ("mknod FIFO1");
exit(1);
}
if (mkfifo(FIFO3, PERMS) < 0 && (errno != EEXIST)) {
unlink (FIFO1);
perror("mknod FIFO3");
exit(1);
}
if ((readfd = open(FIFO1, 0)) < 0) {
perror ("open FIFO1");
exit(1);
}
if ((writefd = open(FIFO3, 1)) < 0) {
perror ("open FIFO3");
exit(1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
loop:
while(1)
{
if ((n = read(readfd, buff, 100)) < 0) {
perror ("server read"); exit (1);
}
write(1,MESSAGE1,strlen(MESSAGE1));
if (write(1, buff, n) != n) {
perror ("client write2"); exit(1);
}
/////////////////////////////////////////////////////////////////////////////////////////////
while(1)
{
printf("server says:");
//strcpy(buff,"I say:");
fgets(buff,100,stdin);
n=strlen(buff) + 1;
if (write(writefd, buff,n) < n) {
perror("server write1"); exit (1);
}
goto loop;
}
}//end of first for
close (readfd); close (writefd);
}
the second process (i called client)
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
extern int errno;
#define FIFO1 "/tmp/fifo.1"
#define FIFO3 "/tmp/fifo.3"
#define PERMS 0666
#define MESSAGE1 "server Says:"
main()
{
char buff[BUFSIZ];
char buf[]="logout";
int readfd, writefd, n, size;
if ((writefd = open(FIFO1, 1)) < 0) {
perror ("client open FIFO1"); exit(1);
}
if ((readfd = open(FIFO3, 0)) < 0) {
perror ("client open FIFO3"); exit(1);
}
///////////////////////////////////////////////////////////
loop:
while(1)
{
printf("client says:");
fgets(buff,100,stdin);
n=strlen(buff) + 1;
if (write(writefd, buff,n) < n)
{
perror("server write1"); exit (1);
}
////////////////////////////////////////////
while(1)
{
if ((n = read(readfd, buff, 100)) < 0)
{
perror ("client read"); exit(1);
}
write(1,MESSAGE1,strlen(MESSAGE1));
if (write(1, buff, n) != n)
{
perror ("client write2"); exit(1);
}
goto loop;
}
}//end of first for
close(readfd); close(writefd);
/* Remove FIFOs now that we are done using them */
if (unlink (FIFO1) < 0) {
perror("client unlink FIFO1");
exit(1);
}
if (unlink (FIFO3) < 0) {
perror("client unlink FIFO3");
exit(1);
}
exit(0);
}
If I understand you correctly, you want the two programs to be non blocking, i.e. they should be able to read from either the user or from the pipe.
If that is the case then I suggest you look into the select system call. It can be used to poll for input from arbitrary file descriptors.
You could do something like the following pseudo-code:
while (1)
{
/* Poll for input */
select(...);
if (is_pipe_readable())
read_from_pipe_and_print_to_stdout();
else if (is_stdin_readable())
read_from_stdin_and_write_to_pipe();
}
Note that a file descriptor becomes readable when it's been closed. So if the write-end of a pipe is closed, the read-end becomes readable, with read returning zero.

Resources