How to use two pipes between three processes in C? - c

I trying to write my program in C with pipes. I have three processes: P (father), R (child) and W (child).
P and R communicate using the first pipe. P and W communicate using the second pipe. The child R reads the input file, passing every row to father P using the first pipe. Father P reads the words and checks if they are a palindrome; if the word is a palindrome, the father sends it to child W.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#define DIMBUF 1024
int palindroma(const char *stringa)
{
int len = strlen(stringa);
int j = 0;
for (int i = len - 1; i >= 0; i--)
{
if (stringa[i] == stringa[j])
{
j++;
}
else
return 0;
}
return 1;
}
void child_r(int piper, const char *filename, char tmp[DIMBUF])
{
FILE *w_stream, *file;
if ((w_stream = fdopen(piper, "w")) == NULL)
{
perror("writer piper_rp");
exit(1);
}
printf("Sono il figlio R\n");
if ((file = fopen(filename, "r")) == NULL)
{
perror("apertura file");
exit(1);
}
while (fgets(tmp, DIMBUF, file) != NULL)
{
printf("\tLeggo dal file: %s", tmp);
fputs(tmp, w_stream);
}
fclose(file);
fclose(w_stream);
}
void child_w(int piper, char tmp[DIMBUF])
{
FILE *r_stream;
if ((r_stream = fdopen(piper, "r")) == NULL)
{
perror("reader");
exit(1);
}
while (fgets(tmp, DIMBUF, r_stream) != NULL)
{
printf("\tMessaggio ricevuto: %s\n", tmp);
}
fclose(r_stream);
exit(0);
}
void father(int piper_rp, char tmp[DIMBUF], int piper_pw)
{
FILE *r_stream, *w_stream;
int len;
if ((r_stream = fdopen(piper_rp, "r")) == NULL)
{
perror("reader");
exit(1);
}
if ((w_stream = fdopen(piper_pw, "w")) == NULL)
{
perror("writer piper_pw");
exit(1);
}
while (fgets(tmp, DIMBUF, r_stream) != NULL)
{
len = strlen(tmp);
if (tmp[len - 1] == '\n')
tmp[len - 1] = 0;
int pal = palindroma(tmp);
if (pal)
{
printf("\tMessaggio inviato: %s\n", tmp);
fputs(tmp, w_stream);
}
}
fclose(w_stream);
fclose(r_stream);
}
int main(int argc, char const *argv[])
{
/* code */
int piper_rp[2];
int piper_pw[2];
char tmp[DIMBUF];
const char *filename = argv[1];
if (argc != 2)
{
fprintf(stderr, "Utilizzo %s file.txt \n ", argv[0]);
exit(1);
}
if (pipe(piper_pw) == -1)
{
perror("errore pipe_pw");
exit(1);
}
if (pipe(piper_rp) == -1)
{
perror("errore pipe_rp");
exit(1);
}
if (fork() == 0)
{
close(piper_rp[0]);
child_r(piper_rp[1], filename, tmp);
}
else
{
// padre
sleep(1);
close(piper_rp[1]);
close(piper_pw[0]);
printf("\nSono il padre P\n");
father(piper_rp[0], tmp, piper_pw[1]);
if (fork() == 0)
{
printf("\nSono il figlio W\n");
close(piper_pw[1]);
child_w(piper_pw[0], tmp);
}
else
wait(NULL);
}
return 0;
}
and this is my output:
Sono il figlio R
Leggo dal file: Ciao
Leggo dal file: Mondo
Leggo dal file: Ale
Leggo dal file: emme
Leggo dal file: piip
Leggo dal file: veffev
Leggo dal file: Scatola
Leggo dal file: computer
Leggo dal file: america
Leggo dal file: abba
Leggo dal file: acca
Leggo dal file: cielo
Leggo dal file: lampada
Leggo dal file: effe
Sono il padre P
Messaggio inviato: emme
Messaggio inviato: piip
Messaggio inviato: veffev
Messaggio inviato: abba
Messaggio inviato: acca
Messaggio inviato: effe
Why doesn't the child W have any output? Why does the program never enter the second fork?

You don't close enough pipe descriptors.
Rule of thumb: If you dup2() one end of a pipe to standard input or standard output, close both of the original file descriptors from pipe() as soon as possible. In particular, that means before using any of the exec*() family of functions. The rule also applies with either dup() or fcntl() with F_DUPFD.
Also, as pointed out by Aconcagua in a comment, you don't fork child W until far too late.
You don't wait for all the children to exit.
I see no merit in passing the tmp buffer from main() to each of the process functions — it can be a local variable in each function.
Here is some code that works, I think.
/* SO 7478-4122 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#define DIMBUF 1024
static int palindroma(const char *stringa)
{
int len = strlen(stringa);
for (int j = 0, i = len - 1; i > j; i--, j++)
{
if (stringa[i] != stringa[j])
return 0;
}
return 1;
}
static void child_r(int piper, const char *filename)
{
char tmp[DIMBUF];
FILE *w_stream, *file;
if ((w_stream = fdopen(piper, "w")) == NULL)
{
perror("writer piper_rp");
exit(EXIT_FAILURE);
}
printf("Sono il figlio R (%d)\n", getpid());
if ((file = fopen(filename, "r")) == NULL)
{
perror(filename);
exit(EXIT_FAILURE);
}
while (fgets(tmp, sizeof(tmp), file) != NULL)
{
printf("\tLeggo dal file: %s", tmp);
fputs(tmp, w_stream);
}
fclose(file);
fclose(w_stream);
}
static void child_w(int piper)
{
char tmp[DIMBUF];
FILE *r_stream;
printf("Sono il figlio W (%d)\n", getpid());
if ((r_stream = fdopen(piper, "r")) == NULL)
{
perror("reader");
exit(1);
}
while (fgets(tmp, sizeof(tmp), r_stream) != NULL)
printf("\tMessaggio ricevuto: %s", tmp);
fclose(r_stream);
}
static void father(int piper_rp, int piper_pw)
{
char tmp[DIMBUF];
FILE *r_stream, *w_stream;
if ((r_stream = fdopen(piper_rp, "r")) == NULL)
{
perror("fdopen(piper_rp, \"r\")");
exit(EXIT_FAILURE);
}
if ((w_stream = fdopen(piper_pw, "w")) == NULL)
{
perror("fdopen(piper_pw, \"w\")");
exit(EXIT_FAILURE);
}
while (fgets(tmp, sizeof(tmp), r_stream) != NULL)
{
tmp[strcspn(tmp, "\n")] = '\0';
if (palindroma(tmp))
{
printf("\tMessaggio inviato: %s\n", tmp);
fprintf(w_stream, "%s\n", tmp);
}
}
fclose(w_stream);
fclose(r_stream);
}
int main(int argc, char const *argv[])
{
int piper_rp[2];
int piper_pw[2];
const char *filename = argv[1];
if (argc != 2)
{
fprintf(stderr, "Utilizzo %s file.txt \n ", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(piper_pw) == -1 ||
pipe(piper_rp) == -1)
{
perror("errore pipe_pw");
exit(EXIT_FAILURE);
}
int pid1;
int pid2;
if ((pid1 = fork()) < 0)
{
perror("fork()");
exit(EXIT_FAILURE);
}
else if (pid1 == 0)
{
close(piper_pw[0]);
close(piper_pw[1]);
close(piper_rp[0]);
child_r(piper_rp[1], filename);
exit(21);
}
else if ((pid2 = fork()) < 0)
{
perror("fork()");
exit(EXIT_FAILURE);
}
else if (pid2 == 0)
{
close(piper_rp[0]);
close(piper_rp[1]);
close(piper_pw[1]);
child_w(piper_pw[0]);
exit(32);
}
else
{
close(piper_rp[1]);
close(piper_pw[0]);
printf("\nSono il padre P (%d)\n", getpid());
father(piper_rp[0], piper_pw[1]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
}
return 0;
}
I tested with this input file:
Ciao
Mondo
Ale
emme
piip
veffev
Scatola
computer
america
abba
acca
cielo
lampada
effe
amanaplanacanalpanama
ablewasiereisawelba
When run, the output was:
Sono il padre P (30483)
Sono il figlio R (30484)
Leggo dal file: Ciao
Leggo dal file: Mondo
Leggo dal file: Ale
Leggo dal file: emme
Leggo dal file: piip
Leggo dal file: veffev
Leggo dal file: Scatola
Leggo dal file: computer
Leggo dal file: america
Leggo dal file: abba
Leggo dal file: acca
Leggo dal file: cielo
Leggo dal file: lampada
Leggo dal file: effe
Leggo dal file: amanaplanacanalpanama
Leggo dal file: ablewasiereisawelba
Sono il figlio W (30485)
Messaggio inviato: emme
Messaggio inviato: piip
Messaggio inviato: veffev
Messaggio inviato: abba
Messaggio inviato: acca
Messaggio inviato: effe
Messaggio inviato: amanaplanacanalpanama
Messaggio inviato: ablewasiereisawelba
Messaggio ricevuto: emme
Messaggio ricevuto: piip
Messaggio ricevuto: veffev
Messaggio ricevuto: abba
Messaggio ricevuto: acca
Messaggio ricevuto: effe
Messaggio ricevuto: amanaplanacanalpanama
Messaggio ricevuto: ablewasiereisawelba
Child 30484 exited with status 0x1500
Child 30485 exited with status 0x2000
Note that after stripping the newline to test whether the string is a palindrome, it was necessary to add it when sending the message from the parent to the W child — otherwise, the child gets all the palindromes jammed together in a single line.

Related

Problem with progamming an intern comands in a shell interpeter (made by myself)

I had a project of operating systems where I had to program a command interpreter in shell in C. I've done it most part of it, the code I've already implemented allows to execute simple commands like ls, or commands in background and/or with pipes.
But now I also have to program an intern command (a new one). Its name is going to be myTime and it should allow you to measure the time that takes to a process to execute its function. For example if you execute the command sleep 10 in the Linux shell, the process should sleep at least the time indicated. The goal of the intern command myTime is to measure that time.
IMPORTANT: In the code I've been giving some help from the teachers that allows me with a function called obtain_orden obtain the command introduced (ex: calling argvv[i][0] for the i command introduced), the arguments (argvv[i][1], the first argument), and if it is or not in background (bg =0/1)
Also, the function pid_t fork() creates a new process or a new child process and returns 0 if it's the child or pid if it's the parent.
I have additional code to compile etc, if you need it or its something nogt clear tell me. Thanks!
I´ve been searching in the sys/time.h library and the function gettimeofday. But i haven't been able to show the message I'm required to in my project: "Time spent: %f secs.\n"
As this intern command should measure the time that takes to a process to execute I've been told that I should execute a fork() and an exec(), and measure the time once the child process has done its function.
It should show like this:
msh> mytime sleep 5
Time spent: 5.001719 secs
msh>
extern int obtain_order(); /* See parser.y for description */
int main(void)
{
char ***argvv;
//int command_counter;
int num_commands;
//int args_counter;
char *filev[3];
int bg;
int ret;
setenv("Acc","0",1);
setbuf(stdout, NULL); /* Unbuffered */
setbuf(stdin, NULL);
while (1)
{
fprintf(stderr, "%s", "msh> "); /* Prompt */
ret = obtain_order(&argvv, filev, &bg);
if (ret == 0) break; /* EOF */
if (ret == -1) continue; /* Syntax error */
num_commands = ret - 1; /* Line */
if (num_commands == 0) continue; /* Empty line */
if(num_commands==1){
//Implementación propia para salir del mini-shell
if(strcmp(argvv[0][0], "exit") == 0){
exit(0);
}
if(strcmp(argvv[0][0],"myTime")==0){
//HERE IS WHERE I HAVE TO IMPLEMENT THE INTERN COMMAND MYTIME
}else{ //For all other commands ls, etc... (with pipes (max 3)and background)
int pid;
int estado;
pid = fork();
switch(pid) {
case -1: /* error */
fprintf(stderr, "%s","Error en el fork del mandato simple\n");
return (-1);
case 0: /* hijo */
if (filev[0] != NULL) {
close(STDIN_FILENO);
open(filev[0],O_RDONLY);
}
if (filev[1] != NULL) {
close(STDOUT_FILENO);
open(filev[1],O_CREAT|O_WRONLY,0666);
}
if (filev[2] != NULL) {
close(STDERR_FILENO);
open(filev[2],O_CREAT|O_WRONLY,0666);
}
execvp(argvv[0][0], argvv[0]);
fprintf(stderr, "%s","Error en el execvp del mandato simple\n");
return(-1);
default: /* padre */
if(!bg){
while (wait(&estado) != pid);
}else printf("%d\n",pid);
} //fin switch (1 mandato)
} //fin if (si es comando interno o no)
}else if(num_commands==2){
int pid;
int estado;
int fd[2];
pipe(fd);
pid = fork();
switch(pid) {
case -1: /* error */
fprintf(stderr, "%s","Error en el fork del primer mandato\n");
return (-1);
case 0: /* hijo1 */
close(STDOUT_FILENO);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
if (filev[0] != NULL) {
close(STDIN_FILENO);
open(filev[0],O_RDONLY);
}
if (filev[2] != NULL) {
close(STDERR_FILENO);
open(filev[2],O_CREAT|O_WRONLY,0666);
}
execvp(argvv[0][0], argvv[0]);
fprintf(stderr, "%s","Error en el execvp del primer mandato\n");
return(-1);
default: /* padre */
pid = fork();
switch(pid) {
case -1: /* error */
fprintf(stderr, "%s","Error en el fork del segundo mandato\n");
return (-1);
case 0: /* hijo 2*/
close(STDIN_FILENO);
dup(fd[0]);
close(fd[0]);
close(fd[1]);
if (filev[1] != NULL) {
close(STDOUT_FILENO);
open(filev[1],O_CREAT|O_WRONLY,0666);
}
if (filev[2] != NULL) {
close(STDERR_FILENO);
open(filev[2],O_CREAT|O_WRONLY,0666);
}
execvp(argvv[1][0], argvv[1]);
fprintf(stderr, "%s","Error en el execvp del segundo mandato\n");
return(-1);
default: /* padre */
close(fd[0]);
close(fd[1]);
if(!bg){
while (wait(&estado) != pid);
}else printf("%d\n",pid);
} //fin switch2 (2 mandatos)
} //fin switch1 (2 mandatso)
}else if(num_commands==3){
int pid;
int estado;
int fd[2], fd2[2];
pipe(fd);
pid = fork();
switch(pid) {
case -1: /* error */
fprintf(stderr, "%s","Error en el fork del primer mandato\n");
return (-1);
case 0: /* hijo1 */
close(STDOUT_FILENO);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
if (filev[0] != NULL) {
close(STDIN_FILENO);
open(filev[0],O_RDONLY);
}
if (filev[2] != NULL) {
close(STDERR_FILENO);
open(filev[2],O_CREAT|O_WRONLY,0666);
}
execvp(argvv[0][0], argvv[0]);
fprintf(stderr, "%s","Error en el execvp del primer mandato\n");
return(-1);
default: /* padre */
pipe(fd2);
pid = fork();
switch(pid) {
case -1: /* error */
fprintf(stderr, "%s","Error en el fork del segundo mandato\n");
return (-1);
case 0: /* hijo 2*/
close(STDIN_FILENO);
dup(fd[0]);
close(STDOUT_FILENO);
dup(fd2[1]);
close(fd[0]);
close(fd[1]);
close(fd2[0]);
close(fd2[1]);
if (filev[2] != NULL) {
close(STDERR_FILENO);
open(filev[2],O_CREAT|O_WRONLY,0666);
}
execvp(argvv[1][0], argvv[1]);
fprintf(stderr, "%s","Error en el execvp del segundo mandato\n");
return(-1);
default: /* padre */
close(fd[0]);
close(fd[1]);
pid = fork();
switch(pid) {
case -1: /* error */
fprintf(stderr, "%s","Error en el fork del tercer mandato\n");
return (-1);
case 0: /* hijo 3*/
close(STDIN_FILENO);
dup(fd2[0]);
close(fd2[0]);
close(fd2[1]);
if (filev[1] != NULL) {
close(STDOUT_FILENO);
open(filev[1],O_CREAT|O_WRONLY,0666);
}
if (filev[2] != NULL) {
close(STDERR_FILENO);
open(filev[2],O_CREAT|O_WRONLY,0666);
}
execvp(argvv[2][0], argvv[2]);
fprintf(stderr, "%s","Error en el execvp del tercer mandato\n");
return(-1);
default: /* padre */
close(fd2[0]);
close(fd2[1]);
if(!bg){
while (wait(&estado) != pid);
}else printf("%d\n",pid);
} //fin switch 3 (3 mandatos)
} //fin switch2 (3 mandatos)
} //fin switch1 (tres mandatos)
} //fin if (número de mandatos)
} //fin while
return 0;
} //fin main

Creating a pipe with dup2

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
int pfd1[2];
int pfd2[2];
pid_t pid1, pid2, pid3;
if(pipe(pfd1)==-1) {
perror("Creazione pipe");
exit(EXIT_FAILURE);
}
if(pipe(pfd2)==-1) {
perror("Creazione pipe");
exit(EXIT_FAILURE);
}
printf("Sono il padre\n");
switch(pid1=fork()) {
printf("%d\n", pid1);
case -1: {
perror("Creazione figlio 1");
exit(EXIT_FAILURE);
}
case 0: { //figlio 1
printf("Sono il figlio 1\n");
if(dup2(pfd1[1],1)==-1) { //redirige lo stdout sul descrittore scrittura
perror("Prima redirezione");
exit(EXIT_FAILURE);
}
close(pfd1[0]);
close(pfd1[1]); //lo chiudo perchè sto redirigendo lo stdout
close(pfd2[0]);
close(pfd2[1]);
execlp("ps", "ps", "-A", "-ostat,pid", (char*) NULL);
}
}
waitpid(pid1,NULL,0);
switch(pid2=fork()) {
case -1: {
perror("Creazione figlio 2");
exit(EXIT_FAILURE);
}
case 0: { //figlio 2
printf("Sono il figlio 2\n");
if(dup2(pfd1[0],0)==-1) { //redirige lo stdin sul descrittore lettura
perror("Seconda redirezione");
exit(EXIT_FAILURE);
}
printf("Prima redirezione figlio 2\n");
if(dup2(pfd2[1],1)==-1) {
perror("Terza redirezione");
exit(EXIT_FAILURE);
}
close(pfd1[1]);
close(pfd1[0]);
close(pfd2[0]);
close(pfd2[1]);
execlp("grep", "grep", "-e", "[zZ]", (char*) NULL);
}
waitpid(pid2, NULL,0);
switch(pid3=fork()) {
case -1: {
perror("Creazione terzo figlio");
exit(EXIT_FAILURE);
}
case 0: { //figlio 3
printf("Sono il figlio 3\n");
if(dup2(pfd2[0],0)==-1) {
perror("Quarta redirezione");
exit(EXIT_FAILURE);
}
close(pfd1[0]);
close(pfd1[1]);
close(pfd2[0]);
close(pfd2[1]);
execlp("awk", "awk", "'{print $2}'", (char*) NULL);
}
}
/*padre*/
//waitpid(pid1, NULL, 0);
//waitpid(pid2, NULL, 0);
waitpid(pid3, NULL, 0);
close(pfd2[0]);
close(pfd2[1]);
close(pfd1[0]);
close(pfd1[1]);
return 0;
}
}
Hello,
I'm trying to create a pipe of shell bash commands using the system call dup2.
The output I expect should be the same as
bash $> ps -A -ostat,pid | grep -e [zZ] | awk '{print $2}'
what I do is forking 3 children and make them communicate through two pipes. Each one of the children executes one part of the command.
The problem is my program gets stuck on the second child which apparently doesn't even get to do the exec.
I'm sure there are some problems with my code, but since it's the first time for me trying to use dup2 I'm a bit confused.
Also, don't mind the printfs, they're just for debugging.
Thanks a lot!
Basically you have to close pipes in the right positions and you failed to close a bracket in the switch statement. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h> /*lib for waitpid()*/
int main(void) {
int pfd1[2];
int pfd2[2];
pid_t pid1, pid2, pid3;
if(pipe(pfd1)==-1) {
perror("Creazione pipe");
exit(EXIT_FAILURE);
}
if(pipe(pfd2)==-1) {
perror("Creazione pipe");
exit(EXIT_FAILURE);
}
printf("Sono il padre\n");
switch(pid1=fork()) {
printf("%d\n", pid1);
case -1: {
perror("Creazione figlio 1");
exit(EXIT_FAILURE);
}
case 0: { //figlio 1
printf("Sono il figlio 1\n");
if(dup2(pfd1[1],1)==-1) { //redirige lo stdout sul descrittore scrittura
perror("Prima redirezione");
exit(EXIT_FAILURE);
}
close(pfd1[0]);
close(pfd1[1]); //lo chiudo perchè sto redirigendo lo stdout
close(pfd2[0]);
close(pfd2[1]);
execlp("ps", "ps", "-A", "-ostat,pid", (char*) NULL);
}
}
waitpid(pid1,NULL,0);
switch(pid2=fork()) {
case -1: {
perror("Creazione figlio 2");
exit(EXIT_FAILURE);
}
case 0: { //figlio 2
printf("Sono il figlio 2\n");
if(dup2(pfd1[0],0)==-1) { //redirige lo stdin sul descrittore lettura
perror("Seconda redirezione");
exit(EXIT_FAILURE);
}
printf("Prima redirezione figlio 2\n");
if(dup2(pfd2[1],1)==-1) {
perror("Terza redirezione");
exit(EXIT_FAILURE);
}
close(pfd1[0]);
close(pfd1[1]);
close(pfd2[0]);
close(pfd2[1]);
execlp("grep", "grep", "-e", "[Ss]", (char*) NULL);
}
} /*You forgot that bracket*/
/*
* Close the pipe before waitpid because 2rd child
* will wait until you close it. Check pipe theory
*/
close(pfd1[1]);
close(pfd1[0]);
waitpid(pid2, NULL,0);
switch(pid3=fork()) {
case -1: {
perror("Creazione terzo figlio");
exit(EXIT_FAILURE);
}
case 0: { //figlio 3
printf("Sono il figlio 3\n");
if(dup2(pfd2[0],0)==-1) {
perror("Quarta redirezione");
exit(EXIT_FAILURE);
}
close(pfd2[0]);
close(pfd2[1]);
/*' ' removed from the "{print $2}"*/
execlp("awk", "awk", "{print $2}", (char*) NULL);
}
}
/*
* Close the pipe before waitpid because 3rd child
* will wait until you close it. Check pipe theory
*/
close(pfd2[0]);
close(pfd2[1]);
waitpid(pid3, NULL, 0);
return 0;
}

Troubles with execlp's output and pipes

I'm writing a program that has an interface like:
myprog file1 file2 c
This program creates two children and P2 with an execlp opens file2, makes a grep -c on this file for founding c and gives the results to his brother P1 (I have to do it closing the STDOUT's FD and dupping the pipe p2p1 between them). P1 receives this from p2p1 and sends this value to P0. Moreover this also makes the same thing with file1 and gives the result to P0, which will print them.
The problem is: the father P0 reads something, but it is wrong.
What I'm supposed to do? Here's the code and thanks for your attention.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define MAX_STRING_LENGTH 128
/**************************/
/* DICHIARAZIONE FUNZIONI */
/**************************/
void wait_child();
void processo_p2(char *inputfile, char *c);
void processo_p1(char *inputfile, char *c);
/*********************/
/* VARIABILI GLOBALI */
/*********************/
int p1p0[2], p2p1[2];
int main(int argc, char* argv[])
{
int pid[2], i, value, count=0;
char *c, buf[10];
if (argc !=4)
{
fprintf(stderr, "Numero di argomenti errato\n");
fprintf(stderr, "Usage: %s file1 file2 C\n", argv[0]);
exit(EXIT_FAILURE);
}
c=argv[3];
/* Init */
pipe(p1p0);
pipe(p2p1);
for (i=0; i<2; i++)
{
pid[i] = fork();
if (pid[i] < 0)
{
fprintf(stderr, "P0: Errore nella fork");
exit(EXIT_FAILURE);
}
else if (pid[i] == 0)
{
if (i==0) /*P1*/
{
close(p1p0[0]);
close(p2p1[1]);
sleep(1);
processo_p1(argv[1], c);
close(p2p1[0]);
close(p1p0[1]);
exit(EXIT_SUCCESS);
}
else if (i==1)
{
close(p2p1[0]);
close(p1p0[0]);
close(p1p0[1]);
processo_p2(argv[2],c);
close(p2p1[1]);
exit(EXIT_SUCCESS);
}
}
else
{
printf("P0: created child P%d with PID %d\n", i+1, pid[i]);
close(p2p1[0]);
close(p2p1[1]);
close(p1p0[1]);
}
}
i=0;
int nread;
while ( (nread = read(p2p1[0], &buf[i], sizeof(char)) ) > 0 ) {
i++;
buf[i] = '\0';
printf("%s\n",buf);
for(i=0;i<2;i++)
{
wait_child();
}
return 0;
}
void processo_p2(char *inputfile, char *c)
{
int fd, nread, i=0, found=0;
char temp, row[100];
close(1);
dup(p2p1[1]);
execlp("grep", "grep", "-c", c, inputfile, (char *)0);
perror("P2: errorr in exec");
close(1);
}
void processo_p1(char *inputfile, char *c)
{
int fd, nrw, sk, nread, p2=0, i=0;
int value=1;
char temp, row[100], buf[10];
//RECEIVING DATA FROM P2 AND SENDING TO P0
while ( (nread = read(p2p1[0], &buf[i], sizeof(char)) ) > 0 ) {
i++;
}
buf[i] = '\0';
printf("from p2: %s\n",buf); //NOTHING STAMPED
write(p1p0[1],&buf,strlen(buf)+1);
close(1);
dup(p1p0[1]);
execlp("grep", "grep", "-c", c, inputfile, (char *)0);
perror("P1: errore in exec");
close(p1p0[1]);
}
void wait_child() {
int pid_terminated,status;
pid_terminated=wait(&status);
if (pid_terminated < 0)
{
fprintf(stderr, "%d\n", getpid());
perror("P0: errore in wait");
exit(EXIT_FAILURE);
}
if(WIFEXITED(status))
{
printf("P0: terminazione volontaria del figlio %d con stato %d\n",
pid_terminated, WEXITSTATUS(status));
if (WEXITSTATUS(status) == EXIT_FAILURE)
{
fprintf(stderr, "P0: errore nella terminazione del figlio pid_terminated\n");
exit(EXIT_FAILURE);
}
}
else if(WIFSIGNALED(status))
{
fprintf(stderr, "P0: terminazione involontaria del figlio %d a causa del segnale %d\n",
pid_terminated,WTERMSIG(status));
exit(EXIT_FAILURE);
}
}
Trivia (but it stops the code compiling): The code shown originally has a close brace in the wrong place — the functions are all apparently embedded inside main(). The last brace should be moved up the file considerably.
In the loop that launches the child processs, you have the parent process execute:
printf("P0: created child P%d with PID %d\n", i+1, pid[i]);
close(p2p1[0]);
close(p2p1[1]);
close(p1p0[1]);
In the parent process, immediately after the loop, you have:
int nread;
while ( (nread = read(p2p1[0], &buf[i], sizeof(char)) ) > 0 ) {
i++;
buf[i] = '\0';
printf("%s\n",buf);
for(i=0;i<2;i++)
{
wait_child();
}
return 0;
}
'Tis a pity that you closed the file descriptor you're trying to read from. The parent should be reading from p1p0[0], which you did leave open.
Fixes:
Move the set of three closes out of the loop.
Read from the correct file descriptor.
Insert a missing close brace for the while loop shown, or remove its open brace.
The question in the comments has, as usual for comments, inscrutable code. The problem though is that you have too big a loop.
This is what the tail of my fixed version of your main() function looks like:
…rest of loop to launch children…
else
{
printf("P0: created child P%d with PID %d\n", i + 1, pid[i]);
}
}
close(p2p1[0]);
close(p2p1[1]);
close(p1p0[1]);
i = 0;
int nread;
while ((nread = read(p1p0[0], &buf[i], sizeof(char)) ) > 0)
i++;
buf[i] = '\0';
printf("%s\n", buf);
for (i = 0; i < 2; i++)
{
wait_child();
}
return 0;
}
Given that I saved the source code in a file pip.c and created the program pip from it, a sample run produced:
$ ./pip pip.c pip.c c
P0: created child P1 with PID 75458
P0: created child P2 with PID 75459
from p2: 49
49
P0: terminazione volontaria del figlio 75459 con stato 0
P0: terminazione volontaria del figlio 75458 con stato 0
$
I'm not entirely happy with all the newlines, but at least the same answer is given twice, as it obviously should be.

WHy are my processes behaving like this?

it's some implementation of linux shell in c. Since i have added background process support i have some output that i fail to understand. Here is the code:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <wait.h>
#define DEFAULT_PROMPT "\nLog710H2014%>"
#define EXIT_CMD "exit"
#define CD_CMD "cd"
#define HOME_ENV_VAR "HOME"
#define NEW_LINE "\n**************************************************\n"
#define BCG_CMD_FLAG "&"
void cd_handler(int argc, char *argv[]);
int lire(char *chaine, int longueur);
char** init_command(int* size,char *str);
int execProg(int *argc, char **argv);
int execProgBg(int *argc, char **argv);
void sigchldHandler(int sig_num);
struct beanProcess {
pid_t pid;
int job_num;
char *command;
};
struct beanProcess *beans;
int jobCount = 1;
int main() {
printf(NEW_LINE);
printf("Bienvenue sur le shell de l'equipe 1");
printf(NEW_LINE);
while(1){
char str[200];
printf(DEFAULT_PROMPT);
lire(str, 200);
int commArgsC = 0, bg = 0;
char** comms = init_command(&commArgsC, str);
if(commArgsC == 0){
printf("Saisie vide, veuillez entrez une commande.");
continue;
}
if(strcmp(comms[commArgsC-1], BCG_CMD_FLAG) == 0){
bg = 1;
comms[commArgsC-1] = 0;
}
if(strcmp(comms[0], CD_CMD) == 0){
cd_handler(commArgsC, comms);
commArgsC = commArgsC -1;
}
else if (strcmp(comms[0], EXIT_CMD) == 0){
exit(0);
}
else {
if(bg){
execProgBg(&commArgsC, comms);
}
else{
execProg(&commArgsC, comms);
}
}
}
exit;
}
void cd_handler(int argc, char *argv[]){
char buff[512];
char * directory;
if(argc < 2){
directory = getenv(HOME_ENV_VAR);
}else if (argc == 2){
directory = argv[1];
}else{
exit(1);
}
if (chdir(directory) == -1) {
printf ("Erreur de changement de repertoire actif", strerror (errno));
}else{
if (getcwd(buff, sizeof(buff)) == NULL)
perror("Impossible d'afficher le repertoire courant");
else
printf("le repertoire courant est: %s\n", buff);
}
}
//Cette fonction est adaptée a partir du code de refp sur http://stackoverflow.com/questions/11198604/c-split-string-into-an-array-of-strings
char** init_command(int* size, char* str){
char ** res = NULL;
char * p = strtok (str, " ");
int n_spaces = 0;
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL){
exit (-1);
}
res[n_spaces-1] = p;
p = strtok (NULL, " ");
}
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
*size = n_spaces;
return res;
}
//cette fonction est tirée d'un exemple de http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-c/recuperer-une-chaine-de-caracteres
int lire(char *chaine, int longueur)
{
char *positionEntree = NULL;
if (fgets(chaine, longueur, stdin) != NULL)
{
positionEntree = strchr(chaine, '\n');
if (positionEntree != NULL)
{
*positionEntree = '\0';
}
return 1;
}
else
{
return 0;
}
}
int execProg(int *argc, char **argv){
char path[] = "/bin/";
strcat(path,argv[0]);
printf("\nThis is the %d process executing the code in non bg mode\n", getpid());
printf("Voici le resultat de l'execution de votre commande\n");
pid_t pid;
pid = fork();
if (pid < 0) {
perror("Creation de processus avec fork echouee");
exit(-1);
}
else if (pid == 0) {
if(execvp(argv[0], argv) == -1){
printf("\nthis is the child process %d executing the command in non bg mode\n", getpid());
perror("execv");
return EXIT_FAILURE;
}
}
else {
printf("\nthis is the parent process %d showing the stats in non bg mode\n", getpid());
struct rusage rusg;
long temp, tempCpu;
wait (NULL);
getrusage(RUSAGE_CHILDREN, &rusg);
printf("\nStatistique de la commande %s:\n", argv[0]);
temp = (rusg.ru_utime.tv_sec * 1000) + (rusg.ru_utime.tv_usec / 1000);
tempCpu = (rusg.ru_stime.tv_sec * 1000) + (rusg.ru_stime.tv_usec / 1000);
printf("\nLe temps wall-clock (ms): %ld", temp);
printf("\nLe temps CPU (ms) %ld", tempCpu);
printf("\nNB interruptions volontaires: %ld", rusg.ru_nvcsw);
printf("\nNB interruptions involontaires: %ld", rusg.ru_nivcsw);
printf("\nNB defaults de pages: %ld", rusg.ru_majflt);
printf("\nNB defaults de pages satifaits du noyau : %ld", rusg.ru_minflt);
}
return EXIT_SUCCESS;
}
int execProgBg(int *argc, char **argv){
signal(SIGCHLD, sigchldHandler);
printf("\nThis is the %d process executing the code in bg mode\n", getpid());
pid_t pid;
pid = fork();
if (pid < 0) {
perror("Creation de processus avec fork echouee");
return EXIT_FAILURE;
}
else if (pid == 0) {
//printf("This is the pid %d", getpid());
printf("\nthis is the child process %d executing the command in bg mode\n", getpid());
if(execvp(argv[0], argv) == -1){
perror("execvp");
return EXIT_FAILURE;
}
}
else {
printf("\nthis is the parent process %d showing the queue in bg mode\n", getpid());
printf("[%d] %d", jobCount, pid);
jobCount++;
//cleanJobList(childPid);
//ajoutProcess();
}
return EXIT_SUCCESS;
}
void sigchldHandler(int sig_num)
{
int status;
int childPid;
childPid = waitpid(-1, &status, 1);
printf("Hello the process %d has died\n", childPid);
//cleanJobList(childPid);
}
When i execute a bg command like "ls &", here's the output:
**************************************************
Bienvenue sur le shell de l'equipe 1
**************************************************
Log710H2014%>ls &
This is the 23464 process executing the code in bg mode
this is the parent process 23464 showing the queue in bg mode
[1] 23472
Log710H2014%>
this is the child process 23472 executing the command in bg mode
Debug PARTIE3.c
Hello the process 23472 has died
This is the 23464 process executing the code in non bg mode
Voici le resultat de l'execution de votre commande
this is the parent process 23464 showing the stats in non bg mode
Debug PARTIE3.c
Statistique de la commande ls:
Le temps wall-clock (ms): 0
Le temps CPU (ms) 2
NB interruptions volontaires: 2
NB interruptions involontaires: 9
NB defaults de pages: 0
NB defaults de pages satifaits du noyau : 644
Log710H2014%>
Why is that the parent process overlapping the lire() function and going directly to execProg function after the first execution ?
You are in a while loop. When your execProgBg function returns, no matter what it returns, the loop keeps going. If you want to stop you need to break or call exit from execProgBg.
Why is that the parent process overlapping the lire() function and
going directly to execProg function after the first execution
I don't know how you are executing your program but it looks like the second time around fgets fails, which you don't notice since you don't check the return code of the lire function. SO you go on and reuse the buffer from the previous call. It seems likely that you pass EOF to the program - perhaps by hitting ctrl-d.
I decided to run the code and obtained the same result as the OP does by hitting CTRL-D after the first ls &.
It is besides the point but warrants some explanation:
exit;
This evaluates the function exit converting it to a function pointer and throws away the result. It does not call the function. More importantly, calling exit as the last statement of main is pointless, since main is exiting anyway. You should just return some_code to indicate success of failure.

Communication process with two other processes

I read the following file (file.txt) line by line:
1
-5
6
-8
-33
21
The father sends negative numbers to a process, and sends positive numbers to a second process:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
void Fils1(int *tube1)
{
int n;
int cpt = 0;
close (tube1[1]);
while (read (tube1[0], &n, 1) >0)
{
cpt+=n;
}
printf("Son 1, count : %i \n", cpt);
exit (1) ;
}
void Fils2(int *tube2)
{
int n;
int cpt = 0;
close (tube2[1]);
while (read (tube2[0], &n, 1) >0)
{
cpt+=n;
}
printf("Son 2, count : %i \n", cpt);
exit (1) ;
}
int main(int argc, char *argv[])
{
FILE* file;
int n;
file = fopen (argv[1], "r");
if (file == NULL){
printf("Error open file %s\n", argv[1]);
exit(1);
}
int tube1[2];
int tube2[2];
if (pipe(tube1) != 0)
{
fprintf(stderr, "Error tube 1\n");
return EXIT_FAILURE;
}
if (pipe(tube2) != 0)
{
fprintf(stderr, "Error tube 2\n");
return EXIT_FAILURE;
}
int pid1 = fork();
if(pid1 == 0)
{
printf("Creation of the first son ! \n");
Fils1 (tube1);
}
else
{
int pid2 = fork();
if(pid2 == 0)
{
printf("Creation of the second son ! \n");
Fils2 (tube2);
}
else
{
printf("I'm the father! \n");
close (tube1[0]);
close (tube2[0]);
while (!feof(file))
{
fscanf (file,"%d",&n);
if (n>0)
{
write (tube1[1], &n, 1);
}
else
{
write (tube2[1], &n, 1);
}
}
fclose (file);
if(wait(NULL) == -1)
{
printf("Error wait()\n");
exit(1);
}
}
}
return EXIT_SUCCESS;
}
Each son is counting, and displays it on screen.
When I execute, I have only that :
I'm the father!
Creation of the first son!
Creation of the second son!
When I expect also
Son1, count : 28
Son2, count : 46
The problem is you're not closing the pipes as you should.
Child1 should close tube2 (both ends)
Child2 should close tube1 (both ends);
The parent should close write end (after the while)

Resources