bad file descriptor realted to threads - c

/*Write a server application that does the following :
open 5 named pipes in read­only mode & read from each in a separate thread created in your process – meaning, one thread per named pipe ; main threadoes not read from a named pipe, instead joins all the threads and 
terminates; each thread uses its own individual buffer for reading data from 
a specific named pipe
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<pthread.h>
#include<fcntl.h>
void* thread_routine1(void*fd1)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd1,buff,20)) >0)
{
printf("%s\n", buff);
write(stdout,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){perror("error"); }
close((int)fd1);
}
void* thread_routine2(void*fd2)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd2,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd2);
}
void* thread_routine3(void*fd3)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd3,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd3);
}
void* thread_routine4(void*fd4)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd4,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd4);
}
void* thread_routine5(void*fd5)
{
char buff[512];
int bytes_read;
while( (bytes_read = read((int)fd5,buff,512)) >0)
{
//printf("%s\n", buff);
write(STDOUT_FILENO,buff,bytes_read);
//fflush(stdout);
}
if(bytes_read<0){ }
close((int)fd5);
}
int main()
{
pthread_t thid[5];
int status,ret;
int fd1,fd2,fd3,fd4,fd5;
int res = mkfifo("/tmp/my_fifo1", 0777);
if (res == 0)
printf("FIFO 1created\n");
if(res<0)
perror("FIFO already created");
res = mkfifo("/tmp/my_fifo2", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO 2already created");
res = mkfifo("/tmp/my_fifo3", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO 3already created");
res = mkfifo("/tmp/my_fifo4", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO 4already created");
res = mkfifo("/tmp/my_fifo5", 0777);
if (res == 0)
printf("FIFO created\n");
if(res<0)
perror("FIFO5 already created");
fd1=open("/tmp/my_fifo1",O_RDONLY);
perror("open status is");
sleep(5);
fd2=open("/tmp/my_fifo2",O_RDONLY);
perror("open status is");
fd3=open("/tmp/my_fifo3",O_RDONLY);
perror("open status is");
fd4=open("/tmp/my_fifo4",O_RDONLY);
perror("open status is");
fd5=open("/tmp/my_fifo5",O_RDONLY);
perror("open status is");
ret=pthread_create(&thid[0],NULL,thread_routine1,(void*)&fd1);
if(ret<0)
perror("error in thread create1");
ret=pthread_create(&thid[4],NULL,thread_routine4,(void*)&fd5);
if(ret<0)
perror("error in thread create2");
ret=pthread_create(&thid[1],NULL,thread_routine3,(void*)&fd2);
if(ret<0)
perror("error in thread create3");
ret=pthread_create(&thid[2],NULL,thread_routine2,(void*)fd3);
if(ret<0)
perror("error in thread create4");
ret=pthread_create(&thid[3],NULL,thread_routine5,(void*)fd4);
if(ret<0)
perror("error in thread create5");
ret=pthread_join(thid[0],NULL);
ret=pthread_join(thid[1],NULL);
ret=pthread_join(thid[2],NULL);
ret=pthread_join(thid[3],NULL);
ret=pthread_join(thid[4],NULL);
ret=pthread_join(thid[5],NULL);
}
the above code for a process that creates a named pipe FIFO
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<strings.h>
int main(int argc, char *argv[])
{
char buf[512],wr_buf[512];
int ret,ret1,status;
int npfd1,npfd2,npfd3,npfd4,npfd5;
struct stat s1,s2;
// ret = mkfifo(argv[1],0600);
npfd1 = open("/tmp/my_fifo1", O_WRONLY); //opening the named pipe for reading
npfd2= open("/tmp/my_fifo2", O_WRONLY); //opening the named pipe for reading
npfd3 = open("/tmp/my_fifo3", O_WRONLY); //opening the named pipe for reading
npfd4 = open("/tmp/my_fifo4", O_WRONLY); //opening the named pipe for reading
npfd5 = open("/tmp/my_fifo5", O_WRONLY); //opening the named pipe for reading
//only
if(npfd1<0) {perror("error in opening the named pipe"); exit(1); }
printf("enter someting into the buffer\n");
bzero(buf,sizeof(buf));
gets(buf);
ret1 = write(npfd1,buf,20);
//printf("%s\n", buf);
write(STDOUT_FILENO,buf,ret1);
//fflush(stdout);
if(ret1<0){ printf("nothing is there\n");}
close(npfd1);
exit(0);
}
The above code is where i am creating the write end of FIFO. Now after running the two programs in different terminal i am getting a BAD FILE DESCRIPTOR error. when i try to write something to the first namedpipe ie. my_fifo1. Is it possible to pass the filedescriptor that is opened in main to threads the way i have done?

Your main() function is passing a pointer-to-int, but your thread functions are casting that back to an int and then trying to use it as a file descriptor. That's not going to work - you need to dereference the passed pointer in the thread functions (this is OK in this case, because those variables in main() are allocated one-per-thread, and main() doesn't exit until all the threads have finished).
void *thread_routine1(void *fd1)
{
char buff[512];
int bytes_read;
int fd = *(int *)fd1;
while ((bytes_read = read(fd,buff,20)) > 0)
/* ... */

Related

named pipe won't open in C program

I have user read/write permissions on a pipe. Group has read. Other has read. But program gets "stuck" when I run it. Program 1 is the "parent". Program 2 is the "child".
Program 1:
int main(int argc, char * argv[])
{
FILE *fptr; //for opening and closing input file
int fdw;// write to pipe;
int fdr; //read to pipe;
pid_t pid;
int inputarray[500];
int arraylength = 0; int j =0;
char *mypipe = "mypipe";
if (argc < 2)
{
printf("Need to provide the file's name. \n");
return EXIT_FAILURE;
}
//open input file
fptr = fopen(argv[1], "r");
if (fptr==NULL)
{
printf("fopen fail.\n");
return EXIT_FAILURE;
}
//read input file and fill array with integers
while (!feof(fptr))
{
fscanf(fptr,"%d",&inputarray[arraylength]);
arraylength = arraylength + 1;
}
fclose(fptr); //close input file
pid = fork();
mkfifo(mypipe, 0666);
fdw = open("mypipe",O_WRONLY);
if (fdw < 0)
{
perror("File can't open to write.");
return;
}
int b;
b=3;
write(fdw,&b,sizeof(b));
close(fdw);
if ( pid ==-1)
{
perror("fork");
exit(1);
}
int status; //exit status of child
if(pid==0)//if child process
{
execl("program2", (char*) NULL);
}
else //if parent process
{
wait(&status);}
if((WIFEXITED(status)))
{
printf("Child's exit code %d", WEXITSTATUS(status));
}
else{
printf("Child did not terminate with exit");}
}
Program 2:
int fdl;
int data;
fdl = open("mypipe",O_RDONLY);
if ( fdl < 0)
{
perror("File can't open to read.");
return;
}
read(fdl,&data,sizeof(data));
close(fdl);
The program will block on writing to the fifo until what it's writing is being read. The reading in the child process won't happen since the execl() doesn't happen until after the writing.
Also, it looks like both processes will actually attempt to write to the fifo since you fork() and then immediately start writing.
You should fork(), then test on the returned PID. The parent should then write to the fifo while the child should call execl(). The fifo should be created by the parent before the fork() call.
You should also consider using indent or clang-format to properly format your code, which eases reading it and may expose bugs (forgotten curly braces etc.).
A simple complete example program. The parent writes a string to the child and the child reads it character by character and outputs it to standard output:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
void parent(void);
void child(void);
int main(void) {
pid_t pid;
mkfifo("myfifo", 0666); /* fails if exists, but we don't care here */
if ((pid = fork()) < 0)
abort();
if (pid == 0)
child(); /* will not return */
else
parent();
return EXIT_SUCCESS;
}
void parent(void) {
int fd;
int len;
int ret;
int stat;
char *ptr;
char *msg = "Hello World!";
if ((fd = open("myfifo", O_WRONLY)) < 0)
abort();
len = strlen(msg) + 1;
ptr = msg;
puts("Parent: About to write to child");
while ((ret = write(fd, ptr, len)) != 0) {
if (ret > 0) {
len -= ret;
ptr += ret;
} else
abort();
}
close(fd);
puts("Parent: Waiting for child to exit");
wait(&stat);
printf("Parent: Child exited with status %d\n", stat);
}
void child(void) {
int fd;
int ret;
char ch;
if ((fd = open("myfifo", O_RDONLY)) < 0)
abort();
puts("Child: About to read from parent");
while ((ret = read(fd, &ch, 1)) != 0) {
if (ret > 0)
putchar(ch);
else
abort();
}
putchar('\n');
close(fd);
puts("Child: I'm done here");
exit(EXIT_SUCCESS);
}
In this case, since both child and parent processes are in the same context, I could have used an anonymous pipe pair created with pipe(), but this illustrates the flow, including the creation of the named pipe.

Named pipe block child process that uses pipe in C

The child_filter has to read values from pipefd and write these in a named pipe.
The problem is that if i try to un-comment the comment[3] (the open of the named-pipe) the function won't print values, it seem to be stuck on read() call. Instead, if i do not open the fifo pipe it works.
I need named pipe for other stuffs.
What shall i modify? Maybe pipe and named-pipe conflicts using them together?
Thanks.
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFONAME "./my-fgrep-named-pipe"
typedef struct{
int i;
int v;
int word;
int filename;
char word_string[250];
char filename_string[250];
}parameters;
int pipefd[2];
void child_reader(parameters params){
FILE* fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
if(params.filename==0)
fp = stdin;
else
fp = fopen(params.filename_string, "r");
close(pipefd[0]); /* Close unused read end */
if (fp != NULL){
while ((read = getline(&line, &len, fp)) != -1) {
//printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
write(pipefd[1], line, strlen(line));
}
fclose(fp);
}
free(line);
printf("child reader > end\n");
exit(0);
}
void child_filter(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int fifofd;
close(pipefd[1]); /* Close unused write pipe end */
printf("read from pipe\n");
if( (fifofd = open(FIFONAME, O_WRONLY)) == -1) printf("Error WW\n");
while (read(pipefd[0], &c, 1) > 0){
if (c == '\n' || c == '\r'){
temp[i] = '\n';
if(i>0){
temp2=strtok(temp, "\n");
//temp2[i] = '\n';
// printf("[%s]\n", temp2);
write(fifofd, temp2, strlen(temp2));
}i=0;
}
else{
temp[i] = c;
i++;
}
}
close(fifofd);
printf("child filter > end\n");
exit(0);
}
void child_writer(parameters params){
char c;
int fifofd;
char temp[250];
int i=0;
char *temp2;
if( (fifofd = open(FIFONAME, O_RDONLY)) == -1) printf("Error RR\n");
while (read(fifofd, &c, 1) > 0){
printf("entry > [%c] \n", c);
}
printf("exit-------------\n");
close(fifofd);
unlink(FIFONAME);
exit(0);
}
int main(int argc, char *argv[]){
char* temp1;
parameters params;
int forkResult;
params.i=0;
params.v=0;
params.word=0;
params.filename=0;
int pid_r, pid_w, pid_f;
if(argc<2){
printf("error\n");
exit(0);
}
if(strcmp(argv[1],"-i") == 0)
params.i++;
if(strcmp(argv[1],"-v") == 0)
params.v++;
if(argc>2){
if(strcmp(argv[2],"-i") == 0)
params.i++;
if(strcmp(argv[2],"-v") == 0)
params.v++;
}
if(params.i == 0 && params.v == 0){
params.word++;
strcpy(params.word_string, argv[1]);
if(argc>2){
params.filename++;
strcpy(params.filename_string, argv[2]);
}
}
else if(params.i != 0 && params.v != 0){
if(argc>3){
params.word++;
strcpy(params.word_string, argv[3]);
}
if(argc>4){
params.filename++;
strcpy(params.filename_string, argv[4]);
}
}
else{
if(argc>2){
params.word++;
strcpy(params.word_string, argv[2]);
}
if(argc>3){
params.filename++;
strcpy(params.filename_string, argv[3]);
}
}
printf("Result: i[%d], v[%d], name[%d], filename[%d]\n", params.i, params.v, params.word, params.filename);
if(params.word==0){
printf("Error X\n");
exit(0);
}
if (pipe(pipefd) == -1) {
printf("pipe error\n");
exit(0);
}
unlink(FIFONAME);
if( mkfifo(FIFONAME, 0666) != 0) printf("Error fifo1\n");
if( (pid_r=fork()) == 0 ){
child_reader(params);
}
if( (pid_f=fork()) == 0 ){
child_filter(params);
}
if( (pid_w=fork()) == 0 ){
child_writer(params);
}
waitpid(pid_r, NULL, 0);
printf("Reader finished\n");
close(pipefd[1]);
waitpid(pid_f, NULL, 0);
close(pipefd[0]);
printf("filter finished\n");
waitpid(pid_w, NULL, 0);
printf("Done!\n");
exit(0);
}
If you open a named pipe for writing then it'll block until the other end is opened for reading. That's an expected behaviour.
I need named pipe for other stuffs
Well, if there's no one reading from the pipe then what other stuff can you do with the write end of the pipe? So, you have to ensure there's a reader from the pipe or delay opening the pipe until there's someone ready to read from it. One other option is to open with O_RDWR.
The problem was that forks dupe file descriptors and so they were still opened.
Due to this reason, child process won't finish.
Fixed code:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFONAME "./my-fgrep-named-pipe"
typedef struct{
int i;
int v;
int word;
int filename;
char word_string[250];
char filename_string[250];
}parameters;
int pipefd[2];
void child_reader(parameters params){
FILE* fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
if(params.filename==0)
fp = stdin;
else
fp = fopen(params.filename_string, "r");
close(pipefd[0]); /* Close unused read end */
if (fp != NULL){
while ((read = getline(&line, &len, fp)) != -1) {
//printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
write(pipefd[1], line, strlen(line));
}
fclose(fp);
}
free(line);
close(pipefd[1]); /* Close unused read end */
printf("child reader > done\n");
exit(0);
}
void child_filter(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int fifofd;
close(pipefd[1]); /* Close unused write pipe end */
if( (fifofd = open(FIFONAME, O_WRONLY)) == -1) printf("Error fifoWW\n");
printf("read from pipe\n");
while (read(pipefd[0], &c, 1) > 0){
if (c == '\n' || c == '\r'){
temp[i] = '\n';
if(i>0){
temp2=strtok(temp, "\n");
//temp2[i] = '\n';
//printf("[%s]\n", temp2);
write(fifofd, temp2, strlen(temp2)); //prima senza +1;
}i=0;
}
else{
temp[i] = c;
i++;
}
}
close(fifofd);
close(pipefd[0]);
printf("child filter > done\n");
exit(0);
}
void child_writer(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int size;
int fifofd;
if( (fifofd = open(FIFONAME, O_RDONLY)) == -1) printf("Error fifoRR\n");
do{
printf("entry> [%c] \n", c);
size = read(fifofd, &c, 1);
printf("next size read> %d\n", size);
}while(size > 0);
close(fifofd);
printf("exit-------------\n");
//unlink(FIFONAME);
exit(0);
}
int main(int argc, char *argv[]){
char* temp1;
parameters params;
int esitoFork;
params.i=0;
params.v=0;
params.word=0;
params.filename=0;
int pid_r, pid_w, pid_f;
FILE *myfifo;
if(argc<2){
printf("error \n");
exit(0);
}
if(strcmp(argv[1],"-i") == 0)
params.i++;
if(strcmp(argv[1],"-v") == 0)
params.v++;
if(argc>2){
if(strcmp(argv[2],"-i") == 0)
params.i++;
if(strcmp(argv[2],"-v") == 0)
params.v++;
}
if(params.i == 0 && params.v == 0){ // [3] ho il nome, [4] ho il filename
params.word++;
strcpy(params.word_string, argv[1]);
if(argc>2){
params.filename++;
strcpy(params.filename_string, argv[2]);
}
}
else if(params.i != 0 && params.v != 0){ // [2] ho il nome, [3] ho il filename
if(argc>3){
params.word++;
strcpy(params.word_string, argv[3]);
}
if(argc>4){
params.filename++;
strcpy(params.filename_string, argv[4]);
}
}
else{ // [3] ho il nome, [4] ho il filename
if(argc>2){
params.word++;
strcpy(params.word_string, argv[2]);
}
if(argc>3){
params.filename++;
strcpy(params.filename_string, argv[3]);
}
}
printf("Result: i[%d], v[%d], nome[%d], filename[%d]\n", params.i, params.v, params.word, params.filename);
if(params.word==0){
printf("Error syntax\n");
exit(0);
}
if (pipe(pipefd) == -1) {
printf("pipe error\n");
exit(0);
}
if( mkfifo(FIFONAME, 0666) != 0) printf("Error fifo\n");
if( (pid_r=fork()) == 0 ){
child_reader(params);
}
if( (pid_f=fork()) == 0 ){
child_filter(params);
}
close(pipefd[0]);
close(pipefd[1]);
if( (pid_w=fork()) == 0 ){
child_writer(params);
}
waitpid(pid_r, NULL, 0);
printf("Reader finished\n");
waitpid(pid_f, NULL, 0);
printf("filter finished\n");
waitpid(pid_w, NULL, 0);
printf("Done!\n");
unlink(FIFONAME);
exit(0);
}

C - put fifo log events in text file

I am tryinIg to send log-events from different threads through a FIFO, read the events and write them to a file.
First I forked my main(). In the Child I want to run the FIFO reader and in the Parent i start my threads (these works fine).
#define FIFO "logFifo"
#define MAX_BUF 1024
int main(int argc, char *argv[]){
pid_t pid;
pid=fork();
if(pid<0){
printf("error with fork() \n");exit(1);
}
if(pid == (pid_t) 0){
//FIFO lezen van log_file
int err;
char buf[MAX_BUF];
char * str_result;
FILE *log;
err = mkfifo(FIFO, 0666);
CHECK_MKFIFO(err);
log = fopen(FIFO, "r");
FILE_OPEN_ERROR(log);
while(1){
//presult = pthread_mutex_lock( &log_mutex);
//pthread_err_handler( presult, "pthread_mutex_lock", __FILE__);
str_result = fgets(buf, MAX_BUF,log);
if(str_result != NULL){
FILE *fp;
fp = fopen("gateway.log","w");
fprintf(fp,"%s \n",buf);
//fclose(fp);
}
//presult = pthread_mutex_unlock( &log_mutex);
//pthread_err_handler( presult, "pthread_mutex_unlock", __FILE__ );
sequence++;
//usleep(1);
}
//unlink(FIFO);
}
else{
//Parent code}
return 0;}
I made a function that will send the log-events:
void send_log(char * message){
FILE *log;
int err;
err = mkfifo(FIFO, 0666);
CHECK_MKFIFO(err);
log = fopen(FIFO, "w");
FILE_OPEN_ERROR(log);
char *msg;
asprintf(&msg, "%d %lu %s", sequence,(unsigned long)time(NULL),message);
printf("log message: %s \n",msg);
if( fputs(msg,log) == EOF){
fprintf(stderr, "error writing data to fifo \n");
exit (EXIT_FAILURE);
}
FFLUSH_ERROR(fflush(log));
free(msg);
sequence++;
/*err = fclose(log);
FILE_CLOSE_ERROR(err);*/
}
I know I put some things in commment, but I tried it also with those in code. Can anyone help me out?
Thank you!
EDIT : solution was to use "aw" instead of "w" and open my gateway.log in the while loop

Linux inter-processes communication

I have to implement a testing program(quiz), which besides displaying the question and reading the answer, it has to display the time left at each one minute past. After finishing the examination time, by finishing the questions or by running out of time,the program has to get back from the beginning, when before the start, we enter the name of the candidate. This implementation has to be done using processes. Below is the code that i have written so far. The problem is that i am not sure that i am making a good communication between the process and the subprocesses, especially because i am not using a pipe. Some opinions?
#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<unistd.h>
#include<sys/wait.h>
#define T 180
void firstChildAction(){
static const char filename[] = "/home/osystems01/laura/text";
char question[100];
char answer[100];
FILE *file = fopen(filename,"r");
if(file != NULL){
while(fgets(question,sizeof question,file) != NULL){
fputs(question, stdout);
scanf("%s",&answer);
}
fclose(file);
}
else{
perror(filename);
}
}
void secondChildAction(){
int i;
for(i = T; i >= 0; i-=60){
if( i/60 != 0){
printf("You have %d %s left.\n", i/60,(i/60 > 1)?"minutes":"minute");
sleep(60);
}
else{
printf("The time is over\n");
break;
}
}
}
int main() {
pid_t pidA;
pid_t pidB;
pid_t wPid;
char name[20];
while(1){
printf("Enter the candidate name or Quit to exit: \n");
scanf("%s",&name);
if(strcmp(name,"Quit") == 0 || strcmp(name,"quit") == 0){
printf("The program is terminating.....\n");
break;
}
else{
pidA = fork();
if(pidA == 0){
firstChildAction();
exit(0);
}
else{
pidB = fork();
if(pidB == 0){
secondChildAction();
exit(0);
}
}
int status;
while(wPid = wait(&status)) > 0 ){
if(WIFEXITED(status)){
int result = WEXITSTATUS(status);
printf("Exit status of %d is %d\n", wPid, result);
if(wPid == pidA){
kill(pidB,SIGTERM);
kill(pidA,SIGTERM);
}
else if(wPid == pidB){
kill(pidA,SIGTERM);
kill(pidB,SIGTERM);
}
}
}
}
}
return 0;
}
Pipes as such don't require you to provide a regular file, but they can have a unique, globally visible name, which is provided by a (unused) filename you have to specify. The contents of the file, if any, is handled by the library.
There are (simple) pipes for communication among related processes (such as a child and a parent process in the same process hierarchy) where the pipe handle can easily be passed to other processes.
The other flavor is called 'named pipes' for processes with any relation, where one can lookup the pipe handle using the global name (as explained in the answer of the question I linked). You can think of a pipe as of a directly connected speaking tube, allowing two processes to chitchat about whatever they like, using read and write functions. On Linux, a pipe is a simplex (at a time, one talks, the other one listens). One would nee two pipes for bidirectional async IO in this case (https://unix.stackexchange.com/questions/53641/how-to-make-bidirectional-pipe-between-two-programs). The immediate buffer for input and output is abstracted. Its just like with network sockets.
I'd suggest to compile this nice example in the accepted answer to play around with: https://stackoverflow.com/a/2789967/1175253
Edit
Example code with error handling. Treat pipe.h & pipe.c as a library (link NamedPipeReader and NamedPipeWriter against it).
This code would need further testing, however, the code is able to (re)open named pipes in any order.
pipe.h
#ifndef PIPE_H_
#define PIPE_H_
//C headers
#include <errno.h>
#include <assert.h>
//Linux headers
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __cplusplus
extern "C"
{
#endif
int open_named_pipe(const char* const name, const int permissions, const int mode, int* pipe_created);
#ifdef __cplusplus
}
#endif
#endif /* PIPE_H_ */
pipe.c
#include "pipe.h"
#include <stdio.h>
int open_named_pipe(const char* const name, const int permissions, const int mode, int* pipe_created)
{
int fd;
assert(name);
assert(permissions);
assert(pipe_created);
//Create or use an existing pipe special file
if (0 == mkfifo(name, permissions))
{
*pipe_created = 1;
printf("Successfully created named pipe '%s'\n", name);
}
else
{
switch (errno)
{
case EEXIST:
//this is OK, as the other process might already has created the special file
printf("Opened existing named pipe '%s'\n", name);
break;
default:
fprintf(stderr, "Failed to create or access named pipe '%s'\n", name);
perror(" ");
return -1;
};
}
fd = open(name, mode);
if (fd < 0)
{
perror("Could not open pipe for writing");
if (*pipe_created)
{
if (0 == unlink(name))
{
*pipe_created = 0;
}
else
{
perror("Failed to unlink named pipe");
}
}
}
return fd;
}
NamedPipeReader.c
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "pipe.h"
//Globals
const char* const pipe_name = "/tmp/myfifo";
const int pipe_permissions = 0600;
const size_t read_buffer_size = 1024; //[bytes]
const size_t read_retry_delay = 25000; //[us]
int fd = -1;
int pipe_created = 0;
char* read_buffer = NULL;
//Handles EPIPE signal
void signal_handler(int signal)
{
fprintf(stderr, "cought signal %d\n", signal);
}
//Handles cleanup on exit
void exit_handler(void)
{
if (read_buffer)
free(read_buffer);
if (fd >= 0)
close(fd);
//if this process created the FIFO, we unlink it
if (pipe_created == 0)
unlink(pipe_name);
}
int main()
{
//Locals
int run = 1;
int received = 0;
//Install the exit handler
atexit(&exit_handler);
signal(EPIPE, signal_handler);
signal(EACCES, signal_handler);
//Allocate the buffer
read_buffer = (char*) malloc(read_buffer_size);
if (!read_buffer)
{
perror("Failed to allocate buffer");
return EXIT_FAILURE;
}
restart: ;
//Close if already open
if(fd >= 0)
close(fd);
//Create or use an existing pipe special file
fd = open_named_pipe(pipe_name, pipe_permissions, O_RDONLY, &pipe_created);
if (fd < 0)
{
return EXIT_FAILURE;
}
while (run)
{
assert(fd >= 0);
assert(read_buffer_size > 1);
received = read(fd, read_buffer, read_buffer_size - 1);
if (received > 0)
{
//add a NUL char for string termination
read_buffer[received] = '0';
printf("local process %llu received: %s\n", (unsigned long long) getpid(), read_buffer);
}
else if (received == 0)
{
//EOF reached, this happens in case the writer has closed its handle.
//Perform a delayed restart and recreate the named pipe
usleep(read_retry_delay);
printf("Restarting...\n");
goto restart;
}
else
{
switch (errno)
{
case EAGAIN:
//Wait, if the pipe is empty,
//happens when opened with the O_NONBLOCK flag
usleep(read_retry_delay);
break;
case EPIPE:
case EBADF:
case EBADFD:
perror("Pipe error");
printf("Restarting...\n");
goto restart;
default:
perror("Pipe error");
return EXIT_FAILURE;
};
}
}
return EXIT_SUCCESS;
}
NamedPipeWriter.c
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include "pipe.h"
//Globals
const char* const pipe_name = "/tmp/myfifo";
const int pipe_permissions = 0600;
const size_t write_buffer_size = 1024; //[bytes]
const size_t write_retry_delay = 25000; //[us]
const size_t write_interval = 1000000;
int fd = -1;
int pipe_created = 0;
char* write_buffer = NULL;
//Handles EPIPE signal
void signal_handler(int signal)
{
fprintf(stderr, "cought signal %d\n", signal);
}
//Handles cleanup on exit
void exit_handler(void)
{
if (write_buffer)
free(write_buffer);
if (fd >= 0)
close(fd);
//if this process created the FIFO, we unlink it
if (pipe_created == 0)
unlink(pipe_name);
}
//Main Function
int main()
{
//Locals
int run = 1;
int sent = 0;
int msg_len = 0;
//Install the exit handler
atexit(&exit_handler);
signal(EPIPE, signal_handler);
signal(EACCES, signal_handler);
//Allocate the buffer
write_buffer = (char*) malloc(write_buffer_size);
if (!write_buffer)
{
perror("Failed to allocate buffer");
return EXIT_FAILURE;
}
restart: ;
//Close if already open
if(fd >= 0)
close(fd);
//Create or use an existing pipe special file
fd = open_named_pipe(pipe_name, pipe_permissions, O_WRONLY, &pipe_created);
if (fd < 0)
{
return EXIT_FAILURE;
}
while (run)
{
//Print message into the buffer
msg_len = snprintf(write_buffer, write_buffer_size, "Greetings from process %llu\n", (unsigned long long) getpid());
{
char* msg_ptr = write_buffer;
char* msg_end = write_buffer + msg_len;
while (msg_ptr != msg_end)
{
assert(fd >= 0);
assert(msg_ptr < msg_end);
sent = write(fd, msg_ptr, msg_end - msg_ptr);
if (sent > 0)
{
msg_ptr += sent;
}
else if (sent == 0)
{
//retry delay for nonblocking writes
usleep(write_retry_delay);
}
else
{
switch (errno)
{
case EAGAIN:
//Wait, if the pipe is full,
//happens when opened with the O_NONBLOCK flag
usleep(write_retry_delay);
break;
case EPIPE:
case EBADF:
case EBADFD:
perror("Pipe error");
printf("Restarting...\n");
goto restart;
default:
perror("Pipe error");
return EXIT_FAILURE;
};
}
}
printf("Written: %s\n", write_buffer);
usleep(write_interval);
}
}
return EXIT_SUCCESS;
}

Pipe to and from child process is not working

I am trying to learn pipes and I am trying out this program:
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<fcntl.h>
#define MAXLINE 100
void main(){
int pipe1[2],pipe2[2];
pid_t childpid;
if(pipe(pipe1)<0){
perror("Unable to create the pipe for pipe1");
exit(-1);
}
if(pipe(pipe2)<0){
perror("Unable to create the pipe for pipe1");
exit(-1);
}
childpid=fork();
printf("The child PID is:%d\n",childpid);
if(childpid==0){
printf("In the child process");
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0],pipe2[1]);
exit(0);
}
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0],pipe1[1]);
waitpid(childpid,NULL,0);
exit(0);
}
void client(int readfd,int writefd){
int n,len;
char buff[MAXLINE];
printf("Please enter the name of the file to be read:");
fgets(buff,MAXLINE,stdin);
len=strlen(buff);
if(buff[len-1]=='\n')
len--;
write(writefd,buff,len);
printf("File name written into the pipe\n");
printf("The num of bytes written are:\n",read(readfd,buff,MAXLINE));
while((n-read(readfd,buff,MAXLINE))>0){
printf("Trying to read the content\n");
write(STDOUT_FILENO,buff,n);
}
}
void server(int readfd,int writefd){
int fd,n;
char buff[MAXLINE + 1];
write(writefd,"Yello in the server process",strlen("Yello in the server process"));
if((n=read(readfd,buff,MAXLINE))==0)
perror("End of file while reading");
buff[n]='\0';
if((fd=fopen(buff,O_RDONLY))<0){
snprintf(buff+n,sizeof(buff)-n,"Can't open, %s",strerror(errno));
n=strlen(buff);
write(writefd,buff,n);
}
while( (n=read(fd,buff,MAXLINE))>0){
write(writefd,buff,n);
close(fd);
}
}
The problem is I enter the file name and the program just exits. I tried to gdb the child process by setting set "follow-fork-mode child", and still nothing happens. Any ideas as to where I could be going wrong?
Ok, some more additional debugging info is: I set the follow-fork-mode to child.and it is causing a segmentation fault at the opening of the file.
Program received signal SIGSEGV, Segmentation fault.
[Switching to process 28025]
0x00197f08 in _IO_file_fopen () from /lib/libc.so.6
This code in client() looks suspicious:
while((n-read(readfd,buff,MAXLINE))>0){
Surely, that should be:
while ((n = read(readfd, buff, MAXLINE)) > 0)
{
The change from - to = is the important one, of course; the rest are cosmetic (and one is even controversial).
You should also pay attention to compiler warnings. Given:
int fd,n;
...
if((fd=fopen(buff,O_RDONLY))<0){
There's no way this should be compiling without major warnings; fopen() returns a FILE *, not a file descriptor (int).
You also seem to have some odd communications. The server sends a message to the client before reading the file name from the client. The client, OTOH, does not necessarily read that message separately; it gets a glob of information and reports how many bytes it got. That may have included some of the file as well as the introductory message.
You shouldn't close a file in the loop that is reading from it:
while( (n=read(fd,buff,MAXLINE))>0){
write(writefd,buff,n);
close(fd);
}
The close should be outside the loop.
This code more or less works; it is messier than I'd like, but it does more or less work.
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXLINE 100
static void server(int readfd, int writefd);
static void client(int readfd, int writefd);
int main(void)
{
int pipe1[2], pipe2[2];
pid_t childpid;
if (pipe(pipe1)<0)
{
perror("Unable to create the pipe for pipe1");
exit(-1);
}
if (pipe(pipe2)<0)
{
perror("Unable to create the pipe for pipe2");
exit(-1);
}
childpid = fork();
printf("The child PID is:%d\n", childpid);
if (childpid == 0)
{
printf("In the child process\n");
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0], pipe2[1]);
exit(0);
}
close(pipe1[0]);
close(pipe2[1]);
client(pipe2[0], pipe1[1]);
waitpid(childpid, NULL, 0);
return 0;
}
static void client(int readfd, int writefd)
{
int n, len;
char buff[MAXLINE];
printf("Please enter the name of the file to be read:");
fgets(buff, MAXLINE, stdin);
len = strlen(buff);
if (buff[len-1]=='\n')
len--;
write(writefd, buff, len);
printf("File name (%.*s) written into the pipe\n", len, buff);
printf("The num of bytes written are: %d\n", (int)read(readfd, buff, MAXLINE));
while ((n = read(readfd, buff, MAXLINE)) > 0)
{
printf("Trying to read the content\n");
write(STDOUT_FILENO, buff, n);
}
}
static void server(int readfd, int writefd)
{
int fd, n;
char buff[MAXLINE + 1];
fprintf(stderr, "Server: %d\n", (int)getpid());
write(writefd, "Yello in the server process", strlen("Yello in the server process"));
if ((n = read(readfd, buff, MAXLINE))==0)
perror("End of file while reading");
buff[n] = '\0';
if ((fd = open(buff, O_RDONLY)) < 0)
{
snprintf(buff+n, sizeof(buff)-n, "Can't open, %s", strerror(errno));
n = strlen(buff);
write(writefd, buff, n);
}
else
{
while ((n = read(fd, buff, MAXLINE)) > 0)
{
if (write(writefd, buff, n) != n)
{
fprintf(stderr, "Write failed in server\n");
break;
}
}
close(fd);
}
}
Note that the code does not try using a file descriptor that it fails to open. It does not crash; the n-read(...) problem is one major part of the trouble, comments notwithstanding. The misuse of fopen() for open() was another major part of the trouble.

Resources