Using named pipes in a single process - c

I am trying to use a named pipe for communication within a process.
Here is the code
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
void sigint(int num)
{
int fd = open("np", O_WRONLY);
write(fd, "y", 1);
close(fd);
}
main()
{
char ch[1];
int fd;
mkfifo("np", 0666);
signal(SIGINT, sigint);
fd = open("np", O_RDONLY);
read(fd, ch, 1);
close(fd);
printf("%c\n", ch[0]);
return;
}
What I want is for main to block till something is written to the pipe.
The problem is that the signal handler sigint() also blocks after opening the pipe. Is this supposed to happen given that the pipe is already opened for reading earlier in main() ?

You're blocking in open() , opening a fifo for reading blocks until someone opens it for writing.
And opening a fifo for writing blocks until someone opens it for reading.
the signal handler runs in the same thread as your main(), so you'll get a deadlock. Neither will be able to open the fifo.
You can check what's going on by running your program under strace.

From the man page:
Opening a FIFO for reading normally
blocks until some other process opens
the same FIFO for writing, and vice
versa.
and:
A process can open a FIFO in
non-blocking mode. In this case,
opening for read only will succeed
even if no-one has opened on the write
side yet; opening for write only will
fail with ENXIO (no such device or
address) unless the other end has
already been opened.
Under Linux, opening a FIFO for read
and write will succeed both in
blocking and non-blocking mode. POSIX
leaves this behaviour undefined. This
can be used to open a FIFO for writing
while there are no readers available.
A process that uses both ends of the
connection in order to communicate
with itself should be very careful to
avoid deadlocks.

Related

C fifo keeps blocked

I'm currently studying multithreading with C, but there is something I don't quite understand with our named pipe excersize.
We are expected to do an implementation of file search system that finds files and adds to a buffer with one process and the second process should take filenames from threads of first one, finds the search query inside that file and returns the position to first process via pipe. I did nearly all of it but i'm confused how to do the communication between two processes.
Here is my code that does the communication:
main.c
void *controller_thread(void *arg) {
pthread_mutex_lock(&index_mutex);
int index = t_index++; /*Get an index to thread*/
pthread_mutex_unlock(&index_mutex);
char sendPipe[10];
char recvPipe[10];
int fdsend, fdrecv;
sprintf(sendPipe, "contrl%d", (index+1));
sprintf(recvPipe, "minion%d", (index+1));
mkfifo(sendPipe, 0666);
execlp("minion", "minion", sendPipe, recvPipe, (char*) NULL);
if((fdsend = open(sendPipe, O_WRONLY|O_CREAT)) < 0)
perror("Error opening pipe");
if((fdrecv = open(recvPipe, O_RDONLY)) < 0)
perror("Error opening pipe");
while(1) {
char *fileName = pop(); /*Counting semaphore from buffer*/
if(notFile(fileName))
break;
write(fdsend, fileName, strlen(fileName));
write(fdsend, search, strlen(search));
char place[10];
while(1) {
read(fdrecv, place, 10);
if(notPlace(place)) /*Only checks if all numeric*/
break;
printf("Minion %d searching %s in %s, found at %s\n", index,
search, fileName, place);
}
}
}
From the online resources I found, I think this is the way to handle the fifo inside the main. I tried to write a test minion just to make sure it works, so here it is
minion.c
int main(int argc, char **argv) {
char *recvPipe = argv[1];
char *sendPipe = argv[2];
char fileName[100];
int fdsend, fdrecv;
return 0;
fdrecv = open(recvPipe, O_RDONLY);
mkfifo(sendPipe, 0666);
fdsend = open(sendPipe, O_WRONLY|O_CREAT);
while(1) {
read(fdrecv, fileName, 100);
write(fdsend, "12345", 6);
write(fds, "xxx", 4);
}
return 0;
}
When I run this way, the threads get blocked and prints no response if I change to O_NONBLOCK to mode of open. Then it prints "Error opening pipe no such device or address" error, so I know that somehow I couldn't open the recvPipe inside minion but I don't know what is the mistake
Among the problems with your code is an apparent misunderstanding about the usage of execlp(). On success, this function does not return, so the code following it will never be executed. One ordinarily fork()s first, then performs the execlp() in the child process, being certain to make the child terminate if the execlp() fails. The parent process may need to eventually wait for the forked child, as well.
Additionally, it is strange, and probably undesirable, that each process passes the O_CREAT flag when it attempts to open the write end of a FIFO. It should be unnecessary, because each one has just created the FIFO with mkfifo(). Even in the event that mkfifo() fails or that some other process removes it before it can be opened, you do not want to open with O_CREAT because that will get you a regular file, not a FIFO.
Once you fix the execlp() issue, you will also have a race condition. The parent process relies on the child to create one of the FIFOs, but does not wait for that process to do so. You will not get the desired behavior if the parent reaches its open attempt before the child completes its mkfifo().
I suggest having the parent create both FIFOs, before creating the child process. The child and parent must cooperate by opening the both ends of one FIFO before proceeding to open both ends of the other. One's open for reading will block until the other opens the same FIFO for writing.
Or you could use ordinary (anonymous) pipes (see pipe()) instead of FIFOs. These are created open on both ends, and they are more natural for communication between processes related by inheritance.
In any event, be sure to check the return values of your function calls. Almost all of these functions can fail, and it is much better to detect and handle that up front than to sort out the tangle that may form when you assume incorrectly that every call succeeded.
Fifos need some synchronization at open time. By default open(s) are blocking, so that an open for read is blocked until some other open the same fifo for writing, and the converse (this to let peers to be synchronized for a communication). You can use O_NONBLOCK to open for reading while there is no actual open peer, but the converse is false, because opening for writing while there is no reading peer leads to an error (letting a process trying to write while there is no reader is considered as non sense).
You may read Linux Fifo manual entry for example.

C reading all data from pipe

My program creates child process and sets pipes to communicate with it. The problem occurs when i try to read data from the pipe. Since child process has ended (i use wait to ensure that) EOF should be on the end of the data stream thus ending the read (As in the man page for pipe). But instead read just freezes and waits for more data to come.
What am i missing here?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void setfd(int *in, int *out) {
dup2(out[1], 1);
dup2(in[0], 0);
}
int main(int argc, char *argv[]) {
int status;
int pipe2ch[2], pipe2pr[2];
char *newargv[] = {NULL, NULL};
newargv[0] = argv[1];
pipe(pipe2ch);
pipe(pipe2pr);
setfd(pipe2pr, pipe2ch);
int a;
if (!(a = fork())) {
setfd(pipe2ch, pipe2pr);
execve(newargv[0], newargv, NULL);
exit(1);
} else {
printf("hello!\n");
fflush(stdout);
char str;
wait(&status);
while (read(pipe2pr[0], &str, 1) > 0) {
fprintf(stderr, "%c", str);
}
exit(0);
}
}
Since child process has ended (i use wait to ensure that) EOF should be on the end of the data stream thus ending the read (As in the man page for pipe).
I'm not sure what you've read to suggest that. Or maybe it's your wording that I don't understand. EOF is not a character on the stream.
But instead read just freezes and waits for more data to come. What am i missing here?
Several things. The most important one is probably that when a process forks, the child's copies of the parent's open file descriptors refer to the same entries in the kernel's underlying table of open files as the parent's do, each of which remains open until all handles on it are closed. The child closes all its file descriptors when it exits, but both ends of both pipes remain open in the parent, so end-of-file will not be signaled to readers. Each process must close the pipe ends it doesn't use or is finished using.
Additionally, you should read() first, then wait(), for if the child process writes enough data to the pipe then it may block, and if the parent does not read until after the child exits then you'll have a deadlock.
Furthermore, I don't see any reason to dupe either pipe end onto the parent's standard streams (resulting in closing the original ones). Just manipulate the pipes via their file descriptors, as you already half do. If you want a stream interface to those, then use fdopen() to get one.

Reading from FIFO after unlink()

I have created a FIFO, wrote to it and unlinked it.
To my surprise I was able to read data from the fifo after unlinking, why is that?
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAX_BUF 256
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
int pid = fork();
if (pid != 0)
{
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
write(fd, "Hi", sizeof("Hi"));
close(fd);
/* remove the FIFO */
unlink(myfifo);
}
else
{
wait(NULL);
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
close(fd);
return 0;
}
return 0;
}
Unless you pass the O_NONBLOCK flag to open(2), opening a FIFO blocks until the other end is opened. From man 7 fifo:
The FIFO must be opened on both ends (reading and writing) before data
can be passed. Normally, opening the FIFO blocks until the other end
is opened also.
A process can open a FIFO in nonblocking mode. In this case, opening
for read only will succeed even if no-one has opened on the write side
yet, opening for write only will fail with ENXIO (no such device or
address) unless the other end has already been opened.
Which is to say, your parent / child processes are implicitly synchronized upon opening the FIFO. So by the time the parent process calls unlink(2), the child process opened the FIFO long ago. So the child will always find the FIFO object and open it before the parent calls unlink(2) on it.
A note about unlink(2): unlink(2) simply deletes the filename from the filesystem; as long as there is at least one process with the file (FIFO in this case) open, the underlying object will persist. Only after that process terminates or closes the file descriptor will the operating system free the associated resources. FWIW, this is irrelevant in the scope of this question, but it seems worth noting.
A couple of other (unrelated) remarks:
Don't call wait(2) on the child. It will return an error (which you promptly ignore), because the child didn't fork any process.
mkfifo(3), fork(2), open(2), read(2), write(2), close(2) and unlink(2) can all fail and return -1. You should gracefully handle possible errors instead of ignoring them. A common strategy for these toy programs is to print a descriptive error message with perror(3) and terminate.
If you just want parent to child communication, use a pipe: it's easier to setup, you don't need to unlink it, and it is not exposed in the filesystem (but you need to create it with pipe(2) before forking, so that the child can access it).

POLLHUP vs POLLNVAL, or what is POLLHUP? [duplicate]

This question already has answers here:
How to handle the Linux socket revents POLLERR, POLLHUP and POLLNVAL?
(4 answers)
Closed 8 years ago.
The manpages say for poll(2):
POLLHUP - Hang up (output only)
POLLNVAL - Invalid request: fd not open (output only)
What exactly is the difference? Writing a simple program shows that POLLNVAL will trigger if I close a file descriptor, then try reading from the closed fd. However, I can't figure out a way to return a POLLHUP.
POLLNVAL is equivalent to EBADF: it means the file descriptor does not actually refer to any open file, i.e. it was closed or never open to begin with. This can never happen except as a result of a programming error or intentional attempt to query whether a file descriptor is invalid. External conditions, such as a peer closing its end of a network socket or pipe, can never close your file descriptor to your end of the socket or pipe. If it could, this would lead to massive vulnerabilities in basically any program using sockets/pipes/etc.
POLLHUP, on the other hand, indicates that your file descriptor is valid, but that it's in a state where:
A device has been disconnected, or a pipe or FIFO has been closed by the last process that had it open for writing. Once set, the hangup state of a FIFO shall persist until some process opens the FIFO for writing or until all read-only file descriptors for the FIFO are closed. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.
Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
If you want to see POLLHUP, simply open a pipe, close the reading end, and query the writing end with poll.
If your goal is to write a program that triggers POLLHUP, try something like opening a pipe, closing the write end of it and then poll()ing the read end (code modified from http://www.greenend.org.uk/rjk/tech/poll.html):
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main(void)
{
int p[2];
struct pollfd ufd;
if (pipe(p) < 0) {
perror("pipe");
return EXIT_FAILURE;
}
if (close(p[1]) < 0) { /* close the write fd */
perror("close");
return EXIT_FAILURE;
}
memset(&ufd, 0, sizeof ufd);
ufd.fd = p[0]; /* poll the read fd after the write fd is closed */
ufd.events = POLLIN;
if (poll(&ufd, 1, 1000) < 0) {
perror("poll");
return EXIT_FAILURE;
}
switch(ufd.revents & (POLLIN|POLLHUP)) {
case POLLIN: printf("POLLIN\n"); break;
case POLLHUP: printf("POLLHUP\n"); break;
case POLLIN|POLLHUP: printf("POLLIN|POLLHUP\n"); break;
case POLLERR: printf("POLLERR\n"); break;
default: printf("%#x\n", (unsigned)ufd.revents); break;
}
return EXIT_SUCCESS;
}
The above prints POLLHUP for me.
POLLNVAL means that the file descriptor value is invalid. It usually indicates an error in your program, but you can rely on poll returning POLLNVAL if you've closed a file descriptor and you haven't opened any file since then that might have reused the descriptor.
POLLHUP basically means that what's at the other end of the connection has closed its end of the connection. POSIX describes it as
The device has been disconnected. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred.
This is clear enough for a terminal: the terminal has gone away (same event that generates a SIGHUP: the modem session has been terminated, the terminal emulator window has been closed, etc.). POLLHUP is never sent for a regular file. For pipes and sockets, it depends. Linux sets POLLHUP when the program on the writing end of a pipe closes the pipe, and sets POLLIN|POLLHUP when the other end of a socket closed the socket, but POLLIN only for a socket shutdown. Recent *BSD set POLLIN|POLLUP when the writing end of a pipe closes the pipe, and the behavior for sockets is more variable.
To observe POLLHUP, have your program read from a terminal and close the terminal. Or, on Linux, have your program read from a pipe and close the writing end (e.g. sleep 1 | yourprogram).

I Have a problem with 2 FIFO for read and write in each

The attached code should allow the communication between 2 terminals. The communication is made through 2 FIFO, which are created in the current directory. The program has to open the 2 fifos and the son reads from STDIN and puts on the fifo1 and the father reads from the other fifo and prints on terminal. In this way the communication takes place since the call to the program is: ./myprog fifo1 fifo2 (for the first terminal) and ./myprog fifo2 fifo1 (for the second terminal). The code does not work well, I suspect that the child write() performs on the fifo does not work well. Hoping that I explained well, help meeee :'(
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
int main(int argc,char* argv[])
{
if(argc<3)
{
printf("Error: Too few arguments...\n");
exit(-1);
}
char** buffer_in=(char**) malloc(sizeof(char*));
char** buffer_out=(char**) malloc(sizeof(char*));
size_t dim_buff=sizeof(char*);
FILE* stream;
FILE* input;
int fifo_in, fifo_out, num_poll_c, num_poll_f, read_count, i,write_b;
pid_t pid;
ssize_t length;
struct pollfd* fd_set_c=(struct pollfd*) malloc(sizeof(int));//for the child
struct pollfd* fd_set_f=(struct pollfd*) malloc(sizeof(int));//for the father
printf("Write character e press enter:\n");
if((fifo_in=open(argv[1],O_RDWR|O_NONBLOCK))==-1)
perror("error open");
if((fifo_out=open(argv[2],O_RDWR|O_NONBLOCK))==-1)
perror("error open");
if((input=fdopen(STDIN_FILENO,"r"))==NULL)
perror("error fdopen");
if((pid=fork())==-1)
perror("error fork");
while(1)
{
if(pid==0) /*child*/
{
fd_set_c->fd=STDIN_FILENO;
fd_set_c->events=POLLIN;
if((num_poll_c=poll(fd_set_c, 1, -1))==-1)
perror("error poll child");//poll on fifo_in
if((length=getline(buffer_in,&dim_buff,input))==-1)
perror("error getline");
printf("The written word is::%s\n",*buffer_in);/*my control for see what in buffer_in is*/
if((write_b=write(fifo_in,*buffer_in,dim_buff))==-1)
perror("error write");
}
else /*father*/
{
fd_set_f->fd=fifo_out;
fd_set_c->events=POLLIN;
if((num_poll_f=poll(fd_set_f, 1, 5000))==-1)
perror("error poll father");//poll on fifo_out
if((read_count=read(fifo_out,*buffer_out,SSIZE_MAX))==-1)
perror("error read");//read on fifo_out
for(i=0;i<=read_count;i++)
printf("%s",buffer_out[i]);//print on stdout buffer_out
}
}
return 0;
}
You should use pipes(man 2 pipe. or shared memory: man shmget) for communication between your processes and a semaphore to protect reads/writes. Look for "producer/consumer" on google.
take a look at this: http://users.evtek.fi/~tk/rtp/sem-producer-consumer.c
and this: http://knol.google.com/k/producer-consumer-problem#
You have a mess here.
Parent might block in read() from FIFO because there are still open writable file descriptors for it. And the open writable file descriptor belongs to the parent process itself. And since it is blocked in the read() it can't write into it.
Put opening of FIFOs after fork(). Open in a stricter mode: either only for writing or only for reading, not wildcard O_RDWR. That way you would mirror the logic generally applied to pipe()s.
Additionally, poll()ing on STDIN_FILENO is dangerous, as stdio is buffered. File descriptor might have nothing to read - because it was all already read out before, but is inside the stdio buffer. If you really sure you know what you do, at least try to disable buffering, man setvbuf. But I still wouldn't do it in the presence of fork(): buffered data might be read twice: once by child and once by parent.

Resources