I have main program which creates two children and one named pipe(FIFO). Each children executes a program called “sendSignal" via execv(). One of the argument of the “sendSignal” is the FIFO in the main program.
The children are going to send signal to each other. It decided with an argument in the main (in variable firstShooter)program which signal shoot first.
I want to know how these two children can send each other their pid through this named pipe.
Following is the main program:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
/* this program should be provided with 2 arguments */
int main(int argc, char **argv)
{
char str1[15];
char str2[15];
char fileDescriptor[15];
char *my_args[4];
char *myfifo = "myfifo";
int fd, pipeCheck;
pid_t pid1, pid2, wid;
/* If the user does not provide the argument to determin which child is firing first */
if(argc != 2)
{
fprintf(stderr,"%s: 2 arguments needed, got %d\n",argv[0],argc-1);
exit(1);
}
/* create the FIFO (named pipe) */
pipeCheck = mkfifo(myfifo, 0666);
/* check if the named pipe was created properly if not output an error */
if(pipeCheck == -1)
{
fprintf(stderr, "%s: Error creating named pipe: %s\n",argv[0], strerror(errno));
exit(1);
}
pid1 = fork();
if (pid1 < 0)
{
fprintf(stderr, ": fork failed: %s\n", strerror(errno));
exit(1);
}
if(pid1 == 0)
{
my_args[0] = "sendSignal";
my_args[1] = argv[1];
my_args[2] = myfifo; // the named pipe as arguemnt
my_args[3] = NULL;
execv("sendSignal",my_args);
fprintf(stderr,"sendSignal cannot be executed by first child...");
exit(-1);
}
pid2 = fork();
if(pid2 < 0)
{
fprintf(stderr, ": fork failed: %s\n", strerror(errno));
exit(1);
}
if(pid2 == 0)
{
my_args[0] = "sendSignal";
my_args[1] = argv[1];
my_args[2] = myfifo; // named pipe as arguemnt
my_args[3] = NULL;
// printf("this is converted = %s\n",my_args[1]);
execv("sendSignal",my_args);
fprintf(stderr,"sendSignal cannot be executed by second child...");
exit(-1);
}
close(fd);
unlink(myfifo);
wid = wait(NULL);
return 0;
}
here is the sendSignal:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
void sig_handler(int signo)
{
if(signo == SIGUSR1)
printf("signal received\n");
}
int main(int argc, char **argv)
{
char abspath[256] = "";
getcwd(abspath, 256);
strrchr(abspath, '/');
if(signal(SIGUSR1,sig_handler) == SIG_ERR)
printf("\n Cannot catch the signal\n");
char *myfifo = "myfifo";
int firstShooter = atoi(argv[1]); //define the first process to send the signal
int fd;
char str1[15];
char str2[15];
char pid1[15];
char pid2[15];
fd = open(argv[2],O_RDWR);
if(firstShooter == 1)
{
sprintf(pid1,"%d",getpid());
write(fd,pid1,sizeof(pid1));
}
if(firstShooter == 2)
{
sprintf(pid2,"%d",getpid());
write(fd,pid2,sizeof(pid2));
}
read(fd,str1,sizeof(str2));
read(fd,str2,sizeof(str2));
close(fd);
printf("str1 = %s\n",str1);
printf("str2 = %s\n",str2);
return 0;
}
Both of your children processes got the same arguments:
my_args[0] = "sendSignal";
my_args[1] = argv[1];
my_args[2] = myfifo; // the named pipe as argument
my_args[3] = NULL;
firstShooter parameter doesn't make sense as process cannot identify itself as first or second.
I suggest to add one more parameter - process index. sendSignal function logic can be modified this way:
char pid1[15];
char pid2[15];
int processIndex = atoi(argv[3]);
fd = open(argv[2],O_RDWR);
if (processIndex == firstShooter)
{
// Send firstShooter PID
sprintf(pid1,"%d",getpid());
write(fd,pid1,sizeof(pid1));
// Got the other PID
read(fd,pid2,sizeof(pid2));
}
else
{
// Got the firstShooter PID
read(fd,pid1,sizeof(pid1));
// Send the other PID
sprintf(pid2,"%d",getpid());
write(fd, pid2, sizeof(pid2));
}
close(fd);
printf("pid1 = %s\n",pid1);
printf("pid2 = %s\n",pid2);
There are some issues in the way you have implemented.
1.Calling two fork() in the main program will be creating more than two child processes.(3 child processes). So give a condition to check that you are calling the next fork in the context of the parent itself.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
/* this program should be provided with 2 arguments */
int main(int argc, char **argv)
{
int * status;
char str1[15];
char str2[15];
char fileDescriptor[15];
char *my_args[4];
char *myfifo = "myfifo";
int fd, pipeCheck;
pid_t pid1, pid2, wid;
/* If the user does not provide the argument to determin which child is firing first */
if(argc != 2)
{
fprintf(stderr,"%s: 2 arguments needed, got %d\n",argv[0],argc-1);
exit(1);
}
/* create the FIFO (named pipe) */
pipeCheck = mkfifo(myfifo, 0666);
/* check if the named pipe was created properly if not output an error */
if(pipeCheck == -1)
{
fprintf(stderr, "%s: Error creating named pipe: %s\n",argv[0], strerror(errno));
exit(1);
}
pid1 = fork();
if (pid1 < 0)
{
fprintf(stderr, ": fork failed: %s\n", strerror(errno));
exit(1);
}
if(pid1 == 0)//child
{
// printf("pid1=0\n");
printf("i am child 1 %d\n",getpid());
my_args[0] = "sendSignal";
my_args[1]=malloc(6);
sprintf(my_args[1] , "%d", getpid());
//my_args[1]="1";
printf("p%s\n",my_args[1]);
my_args[2] = myfifo; // the named pipe as arguemnt
my_args[3] ="1";
execv("sendSignal",my_args);
fprintf(stderr,"sendSignal cannot be executed by first child...");
exit(-1);
}
else if(pid1>0)// parent
{
// printf("pid1 %d",pid1);
waitpid(pid1,&status,WIFEXITED(status));
pid2 = fork();
// printf("p:%d",pid2);
if(pid2 < 0)
{
fprintf(stderr, ": fork failed: %s\n", strerror(errno));
exit(1);
}
if(pid2 == 0)
{
printf("i am child 2 %d\n",getpid());
my_args[0] = "sendSignal";
my_args[1]=malloc(6);
sprintf(my_args[1] , "%d", getpid());
my_args[2] = myfifo; // named pipe as arguemnt
my_args[3] = "2";
// printf("this is converted = %s\n",my_args[1]);
execv("sendSignal",my_args);
fprintf(stderr,"sendSignal cannot be executed by second child...");
exit(-1);
}
printf("done\n");
}
close(fd);
wait(NULL);
fd=open("fifo1", O_RDONLY);
char * space=(char *)malloc(6);
read(fd,space,6);
printf("from fifo1 %s",space);
fd=open("fifo2", O_RDONLY);
//char * space=(char *)malloc(6);
read(fd,space,6);
printf("from fifo2 %s",space);
//unlink(myfifo);
wid = wait(NULL);
unlink(myfifo);
return 0;
}
2. The two child process are accessing the same pipe. Pipe is for one way communication with an end for reading and another for writing. So create two pipes each for a process. I would suggest better not to go for pipes.
Related
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);
}
I am trying to run the child processes (S and H) on different shells, the processes need to be able to communicate in both directions, for this i used two unamed pipes.
When I use "x-terminal-emulator -e" to run them, the child processes return the same error in write and select: "Bad File Descriptor", which didn't happen if I ran them on the same shell.
(READ_END = 0, WRITE_END = 1)
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include "robot.h"
int spawn_s(int read, int write, bool external);
int spawn_h(int read, int write, bool external);
int main(int argc, char *argv[])
{
pid_t pids[2]; //process
int s_h[2];
int h_s[2];
if (pipe(s_h) < 0)
{
perror("Error opening pipe");
return 1;
}
if (pipe(h_s) < 0)
{
perror("Error opening pipe");
return 1;
}
pids[0] = spawn_s(h_s[READ_END], s_h[WRITE_END], true);
pids[1] = spawn_h(s_h[READ_END], h_s[WRITE_END], true);
}
int spawn_s(int read, int write, bool external)
{
pid_t child_pid = fork();
if (child_pid != 0)
return child_pid; /* This is the parent process. */
else
{
char p1[16], p2[16];
sprintf(p1, "%d", read);
sprintf(p2, "%d", write);
char *args[] = {"./s", p1, p2, (char *)NULL};
char *args_e[] = {"x-terminal-emulator", "-e", "./s", p1, p2, (char *)NULL};
if (external)
execvp(args_e[0], args_e);
else
execvp(args[0], args);
fprintf(stderr, "An error occurred in execvp\n");
exit(EXIT_FAILURE);
}
}
int spawn_h(int read, int write, bool external)
{
pid_t child_pid = fork();
if (child_pid != 0)
return child_pid; /* This is the parent process. */
else
{
char p1[16], p2[16];
sprintf(p1, "%d", read);
sprintf(p2, "%d", write);
char *args[] = {"./h", p1, p2, (char *)NULL};
char *args_e[] = {"x-terminal-emulator", "-e", "./h", p1, p2, (char *)NULL};
if (external)
execvp(args_e[0], args_e);
else
execvp(args[0], args);
fprintf(stderr, "An error occurred in execvp\n");
exit(EXIT_FAILURE);
}
}
Is there anything I need to set up before running them on different shells?
I don't understand how to use the created pipe from mp.c in the child process sp.c. I (think I) can't seem to access proper file descriptor when using execl for outside process.
/***************mp.c*****************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *procpath = "/mypath/sp";
char *procname = "sp";
pid_t pid;
int fd[2];
int ret;
char buf[20];
memset(&buf[0], 0, sizeof(buf));
ret = pipe(fd);
if(ret == -1){
perror("pipe");
exit(1);
}
pid = fork();
printf("%d\n",pid);
if (pid == 0){
//dup2(mypipefd[1],STDOUT_FILENO);
ret = execl(procpath, procpath, "1","2",NULL);
perror("execl failed to run slave program");
exit(1);
}
else if (pid > 0){
/* Parent process*/
printf("execl ret val = %d",ret);
printf("Parent process \n");
close(fd[1]);
read(fd[0],buf,15);
// close(fd[1]);
close(fd[0]);
printf("buf: %s TEST\n", buf);
printf("buf: %s TEST\n", buf);
}
else{
printf("call to fork failed, no child\n");
exit(-1);
}
exit(0);
}
and the created process...
/***************sp.c*****************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]){
int ret;
//printf("Child process \n");
int fd[2];
pipe(fd);
//dup2(fd[1],1);
//int out;
/*ret = dup2(fd[1],1);
if (ret = -1){
printf("%s\n", strerror(errno));
};*/
//sprintf()
//printf("%d\n", ret);
//mypipefd = argv[1];
printf("Child process \n");
//close(fd[0]);
write(fd[1], "Hello there!",12);
close(fd[1]);
exit(0);
}
The problem is that you are creating a different pipe in each application. In order to correctly communicate over a pipe, two program should share the same pipe ( one of the file descriptor create by the pipe function).
Basically to solve this problem, you must create the pipe in one application and send the file descriptor to the other program without calling again the system call pipe. A file descriptor can be sent to another process by using a socket unix domain. Look a this post Can I share a file descriptor to another process on linux or are they local to the process?.
Here's a program I'm trying to make:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* arguments[] = {"superabundantes.py", NULL};
int my_pipe[2];
if(pipe(my_pipe) == -1)
{
fprintf(stderr, "Error creating pipe\n");
}
pid_t child_id;
child_id = fork();
if(child_id == -1)
{
fprintf(stderr, "Fork error\n");
}
if(child_id == 0) // child process
{
close(my_pipe[0]); // child doesn't read
dup2(my_pipe[1], 1); // redirect stdout
execvp("cat", arguments);
fprintf(stderr, "Exec failed\n");
}
else
{
close(my_pipe[1]); // parent doesn't write
char reading_buf[1];
while(read(my_pipe[0], reading_buf, 1) > 0)
{
write(1, reading_buf, 1); // 1 -> stdout
}
close(my_pipe[0]);
wait();
}
}
I want to execute the exec in the child redirecting the stdout of the child to the parent (through the pipe). I think the problem might be related to dup2, but I haven't used it before.
You need to also provide argv[0] when you call exec. So your arguments should read:
char* arguments[] = {"cat", "superabundantes.py", NULL};
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
//char* arguments[] = {"cat","tricky.txt", NULL};
char* arguments[] = {"./son1", NULL};
int my_pipe[2];
if(pipe(my_pipe) == -1)
{
fprintf(stderr, "Error creating pipe\n");
}
pid_t child_id;
child_id = fork();
if(child_id == -1)
{
fprintf(stderr, "Fork error\n");
}
if(child_id == 0) // child process
{
close(my_pipe[0]); // child doesn't read
dup2(my_pipe[1], 1); // redirect stdout
execvp(arguments[0], arguments);
fprintf(stderr, "Exec failed\n");
}
else
{
close(my_pipe[1]); // parent doesn't write
char reading_buf[1];
while(read(my_pipe[0], reading_buf, 1) > 0)
{
write(1, reading_buf, 1); // 1 -> stdout
}
close(my_pipe[0]);
wait();
}
}
/*
if ./son1 returns
printf() in son1 will be output by write(1 ..) in parent
if son1 is in dead loop then
printf() in son1 will NOT be output by write(1 ..) in parent
void main()
{
printf( "***** son run *****\n\r" );
return;
while(1);
}
any idea?
*/
I'm trying to redirect the stdin from the parent to the child through the pipe "my_pipe", but when I run my program, I do not see the expected results.
When I execute the program, it expects input from the stdin, so why didn't it redirect stdin in dup2?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* arguments[] = {"sort", NULL};
int my_pipe[2];
if(pipe(my_pipe) == -1)
{
fprintf(stderr, "Error creating pipe\n");
}
pid_t child_id;
child_id = fork();
if(child_id == -1)
{
fprintf(stderr, "Fork error\n");
}
if(child_id == 0) // child process
{
close(my_pipe[1]); // child doesn't write
dup2(0, my_pipe[0]); // redirect stdin
execvp(argv[0], arguments);
fprintf(stderr, "Exec failed\n");
}
else
{
close(my_pipe[0]); // parent doesn't read
char reading_buf[1];
write(my_pipe[1], "hello", strlen("hello"));
write(my_pipe[1], "friend", strlen("friend"));
close(my_pipe[1]);
wait();
}
}
Your arguments to dup2 are backwards. Try dup2(my_pipe[0], STDIN_FILENO)