I have a situation where I need to check if the other side of a fifo has opened it, however I can't use a open because otherwise the program will start doing stuff.
Why I have to do this: I have a program (a monitor) that launches a server program (both created by me). The monitor uses this fifo to communicate beacause the monitor can be closed/reopened while the server is already started.
The problem is when the monitor starts the server: in this case I have to wait in some way for fifos to be created and then open them.
Actually I'm using a while on the monitor that checks when the fifos are created, however in this way it opens the fifos before the server could do it (even if the instruction after the mkfifo is actually the open!!!).
You may say that I'm opening the fifos in wrong order on the monitor (I'm opening the Write fifo(WRONLY) before the read fifo), the problem is that I can't revert this order because it's required that the server will wait for clients on the open (RDONLY) fifo.
Any suggestion on how to avoid this race condition?
I'm actually using a sleep in the monitor after checking if fifos are created, this obviusly solves the problem but I think is definitely not correct.
Thanks to everyone
Edit 1:
This is how things are working at the moment
Server
mkfifo(fifo1)
mkfifo(fifo2)
open(fifo1 O_RDONLY)
open(fifo2 O_WRONLY)
Monitor
while (fifo1 doesn't exists && fifo2 doesn't exists);
open(fifo1 O_WRONLY)
open(fifo2 O_RDONLY)
I think the race condition is quite explicit now, it's important to notice that fifos are blocking (only RDONLY are blocking, WRONLY will not block even if there isn't anyone on the other side => this is a unix behaviour, not designed by me).
Edit 2:
The race condition happens at first fifo open level. I must open the first fifo on the server before the monitor does it.
You may want to use a named semaphore using sem_open() that is visible to each program at the file-system level in order to synchronize the two programs. Basically your monitor program will wait on the locked semaphore until the server increases it. At that point, all the fifo's will be initialized, and you can move foward with your monitor with the fifo's in a known-state.
Make sure to use the O_CREAT and O_EXCL flags on the initial call to sem_open() so that the creation of the semaphore is atomic. For example, both the monitor and the server program will attempt to create the semaphore at startup if it doesn't already exist ... if it exists, the call will fail, meaning the either the monitor or the server, but not both programs, gained the right to create the semaphore and initialize it. The monitor then waits on the semaphore while the server initializes the fifo's ... once the fifo's are initialized, the server releases the semaphore, and the monitor is then able to continue.
Here's the process as I'm envisioning it ... I believe it should effectively solve your race condition:
In the monitor:
Create the named semaphore and set it in a locked state
Launch the server
Wait for the FIFO's to be visible at the file-system level
Open fifo1 for writing (non-blocking)
Open fifo2 for reading (blocks until the server opens fifo2 for writing)
Wait on the semaphore (possibly with a timeout) until the server unlocks it, indicating that it has now opened both FIFO's successfully.
In the server:
Create the FIFO's
Open fifo1 (blocks until the monitor opens it for writing)
Open fifo2 (non-blocking)
Unlock the semaphore now that the server has opened both FIFO's
So basically your monitor cannot continue until there is a "known-state" where everything is properly initialized ... the server indicates that state to the monitor via the named semaphore.
At least what I found 'till now makes me understand that there isn't a way to detect if a fifo is opened, except if you open it too.
Edit 1:
As Jason stated, there are two ways (both not allowed in my homework however):
1) *You could do a search through /proc/PID/fd (replace PID with a numerical process ID) to see what client processes had already opened your FIFO*
2) Another option would be to call fuser on your FIFO
However, the first one requires something that teachers don't want: watching inside proc/PID/fd. The second one I heared requires root privileges, and this is again something I can't do. Hopefully this will help someone else in the future.
If you do the open()s in the right order, there is no race condition. (the only possible race would be a third process interfering with the same fifos) From the fine manual :
"However, it has to be open at both ends simultaneously before you can proceed to do any input or output operations on it. Opening a FIFO for reading normally blocks until some other process opens the same FIFO
for writing, and vice versa."
This means that the ordering
{ process 1: open (fifo1, RO); process2: open (fifo1, WO); }
...
{ process 1: open (fifo2, WO); process2: open (fifo2, RO); }
will always succeed (given no process starvation) The order of operations on each fifo is unimportant; for fifo1 either process1 or process2 can go first (and will be blocked until the other side succeeds).
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define FIFO1 "fifo1"
#define FIFO2 "fifo2"
void do_master(void);
void do_slave(void);
void randsleep(unsigned max);
/************************************/
void do_master(void)
{
int in,out, rc;
char buff[20];
randsleep(5);
mkfifo(FIFO1, 0644);
randsleep(7);
mkfifo(FIFO2, 0644);
out = open(FIFO2, O_WRONLY);
if (out == -1) {
fprintf(stderr, "[Master]: failed opening output\n" );
return;
}
fprintf(stderr, "[Master]: opened output\n" );
in = open(FIFO1, O_RDONLY);
if (in == -1) {
fprintf(stderr, "[Master]: failed opening input\n" );
close(out);
return;
}
fprintf(stderr, "[Master]: opened input\n" );
rc = write( out, "M2S\n\0" , 5);
fprintf(stderr, "[Master]: wrote %d\n", rc );
rc = read( in, buff , sizeof buff);
fprintf(stderr, "[Master]: read %d: %s\n", rc, buff );
unlink(FIFO1);
unlink(FIFO2);
}
/***********************************/
void do_slave(void)
{
int in,out, rc;
unsigned iter=0;
char buff[20];
loop1:
in = open(FIFO2, O_RDONLY);
if (in == -1) {
fprintf(stderr, "[Slave%u]: failed opening input\n", ++iter );
randsleep(2);
goto loop1;
}
fprintf(stderr, "[Slave]: opened input\n" );
loop2:
out = open(FIFO1, O_WRONLY);
if (out == -1) {
fprintf(stderr, "[Slave%u]: failed opening output\n", ++iter );
randsleep(3);
goto loop2;
}
fprintf(stderr, "[Slave]: opened output\n" );
rc = write( out, "S2M\n\0" , 5);
fprintf(stderr, "[Slave]: wrote %d\n", rc );
rc = read( in, buff , sizeof buff);
fprintf(stderr, "[Slave]: read %d:%s\n", rc, buff );
}
/*************************************/
void randsleep(unsigned max)
{
unsigned val;
val = rand();
val %= max;
sleep(val);
return;
}
/*************************************/
int main(void)
{
int rc;
switch (rc=fork()) {
case -1: exit(1); break;
case 0: do_slave(); break;
default: do_master(); break;
}
exit (0);
}
Consider using a Unix domain sockets of type SOCK_STREAM. The server will bind its socket to a name in the filesystem. Each client gets its own bidirectional connection to the server.
Related
I have a parent and child process using fork who communicate using a FIFO pipe. The program will sometimes work and other times it will crash when the writer process (parent) goes faster than the reader process (child).
The following code is what I currently have.
void writeprocess(char* text);
void readprocess(void);
#define FIFO_NAME "MYTESTFIFO"
#define MAX 200
int main(int argc, const char * argv[]) {
pid_t pid;
pid = fork();
if(pid==0){
printf("Started child process.\n");
mkfifo(FIFO_NAME, 0666);
readprocess();
printf("Child process finished.\n");
exit(EXIT_SUCCESS);
}
else{
printf("Started parent process.\n");
mkfifo(FIFO_NAME, 0666);
writeprocess("Message 1");
writeprocess("Message 2");
writeprocess("Message 3");
writeprocess("Message 4");
writeprocess("terminate");
printf("Waiting for child process to finish.\n");
int returnStatus;
waitpid(pid, &returnStatus, 0);
printf("Parent process also finished.\n");
exit(EXIT_SUCCESS);
}
}
void writeprocess(char* text){
FILE *fp;
char *send_buf;
fp = fopen(FIFO_NAME, "w");
asprintf( &send_buf, "%s\n", text);
if ( fputs( send_buf, fp ) == EOF )
{
fprintf( stderr, "Error writing data to fifo\n");
exit( EXIT_FAILURE );
}
printf("Message send: %s", send_buf);
free( send_buf );
fclose(fp);
}
void readprocess(){
sleep(1);
FILE *fp;
char *str_result = NULL;
char recv_buf[MAX];
int stringdifference = 1;
while (stringdifference)
{
fp = fopen(FIFO_NAME, "r");
str_result = fgets(recv_buf, MAX, fp);
if ( str_result != NULL )
{
printf("Message received: %s", recv_buf);
}
fclose( fp );
stringdifference = strncmp(str_result, "terminate", 9);
}
}
When the writer writes faster to the FIFO pipe than the reader can read, I get an exit error with the following message: "Terminated due to signal 13". How can I avoid this from happening while keeping my program run at full performance?
I do want the parent process to be able to end the process and I have to keep working using a FIFO pipe.
When the writer writes faster to the FIFO pipe than the reader can read, I get an exit error with the following message: "Terminated due to signal 13".
You have mischaracterized the nature of the problem. As your other answer already observes, signal 13 is SIGPIPE, which is delivered if you try to write to a pipe that has no readers.
There is normally some (limited) protection against entering that situation with FIFOs, in that opening one end of a FIFO blocks until the other end is opened as well. Therefore if a process opens a FIFO successfully, it knows that there is initially another process with the other end open. The one with the write end open can then expect a high likelihood of writing successfully (but not necessarily without blocking). As soon as the last reader closes the FIFO, however, further attempts to write to it will cause a SIGPIPE to be delivered to the writer. Of course, if the same or a new reader opens the FIFO, that permits writing to resume -- something that's possible with a FIFO, but not with an ordinary pipe.
So the problem is not that the reader does not keep up, but rather that it keeps opening and closing the FIFO. This creates a race condition, in that there are multiple intervals in which the writer will elicit a SIGPIPE if it tries to write. Since the writer also repeatedly opens and closes the FIFO, it follows that to receive a SIGPIPE, the writer must reopen the FIFO before the reader closes it after a previous message, but that doesn't mean the writer is outpacing the reader. The reader cannot finish reading a given message before the writer finishes writing it, so their behaviors are staggered. The writer does nothing else between closing the FIFO and reopening it, so it is not surprising that it sometimes reopens before the reader closes.
The solution is simple: have each process keep the pipe open continuously until it is done communicating with the other. There is no upside to opening and closing for each message, but plenty of downside. For your particular use, however, it may be beneficial to put the writer's stream in line-buffered mode (setvbuf(); default will be fully-buffered).
Signal 13 is SIGPIPE. This happens because nobody is reading from the FIFO.
You cannot write to a FIFO if there is no process that currently has that FIFO open for reading. If you try to do this, your process will get SIGPIPE (which can be ignored, which turns it into EPIPE... but either way, it fails).
One way to handle this correctly:
Create the FIFO in the parent.
Fork.
In the writer process, open it for writing. This will block until the reader has opened it. Keep it open.
In the reader process, open it for writing. This will block until the writer has opened it. Keep it open.
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.
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).
I wrote and maintain a program rlwrap that uses a pseudo-terminal to communicate with a child process. Pseudo-terminals (ptys) are found in all Unix(-like) systems, but they behave slightly differently on different platforms.
Case in point: In rlwrap, the parent process keeps the slave pty open to keep tabs on the child's terminal settings (on Linux and FreeBSD one can use the master for that, but not in Solaris, for example)
On FreeBSD (8.2) (but not Linux) this leads to the loss of the child's final output. For example:
#include <stdio.h>
/* save as test.c and compile with gcc -o test test.c -lutil */
#define BUFSIZE 255
int main(void) {
int master, slave;
char buf[BUFSIZE];
int nread;
openpty(&master, &slave, NULL, NULL, NULL);
if (fork()) { /* parent: */
close(slave); /* leave this out and lose slave's final words ... WHY? */
do {
nread = read(master, buf, BUFSIZE);
write(STDOUT_FILENO, buf, nread); /* echo child's output to stdout */
} while (nread > 0);
} else { /* child: */
login_tty(slave); /* this makes child a session leader and slave a controlling */
/* terminal for it, then dup()s std{in,out,err} to slave */
printf("Feeling OK :-)\n");
sleep(1);
printf("Feeling unwell ... Arghhh!\n"); /* this line may get lost */
}
return 0;
}
The parent process will echo the child's output, as expected, but when I omit the close(slave) (keeping it open like in rlwrap):
on FreeBSD, the parent doesn't see the final output line, it reads an EOF instead. (If anything, I would have expected the opposite - that keeping the slave end open would prevent the output from being lost)
On Linux, on the other hand, an EOF is never seen, not even after the child has died (whether we close the slave or not)
Is this behaviour documented somewhere? Is there a rationale for it? Can I circumvent it without closing the slave in the parent process?
I found out that not making the slave a controlling terminal - replacing the login_tty call with a few simple dup() calls - will cure the problem. This is no solution for rlwrap however: quite a few commands need a controlling terminal (/dev/tty) to talk to, so rlwrap has to provide one for them.
I think there is unique separate behaviour for the Pty.
The system terminates if the last data is written
The system terminates if the child exits (broken pipe?)
The code relies on the pipe existing long enough to send the data through, but the child exiting may cause the virtual channel to be deleted before the data is received.
This would be unique to Pty, and not exist for real terminal.
On FreeBSD 10-STABLE I do get both output lines.
(You can replace openpty and fork with forkpty which basically takes care of login_tty as well.)
In FreeBSD 8.0, the old pty(4) driver was replaced by pts(4).
The new pty(4) behaves differently from the old one. From the manual;
Unlike previous implementations, the master and slave device nodes are destroyed when the PTY becomes unused. A call to stat(2) on a nonexistent master device will already cause a new master device node to be created. The master device can only be destroyed by opening and closing it.
There might well have been significant changes between 8.0-RELEASE and 10.0-RELEASE
You also might want to look at the patch that is applied in the FreeBSD ports tree.
printf does buffered output depending of the class of output device. Just try to put fflush(stdout); after the last printf to see if it's a problem with buffered output.
here is what I found on ubuntu linux
Note: always check for errors
#include <stdio.h>
#include <stdlib.h>
#include <pty.h> // openpty(),
#include <utmp.h> // login_tty()
#include <unistd.h> // read(), write()
/* save as test.c and compile with gcc -o test test.c -lutil */
#define BUFSIZE (255)
int main(void)
{
int master, slave;
char buf[BUFSIZE];
int nread;
pid_t pid;
if( -1 == openpty(&master, &slave, NULL, NULL, NULL) )
{ // then openpty failed
perror( "openpty failed" );
exit( EXIT_FAILURE );
}
// implied else, openpty successful
pid = fork();
if( -1 == pid )
{ // then fork failed
perror( "fork failed" );
exit( EXIT_FAILURE );
}
// implied else, fork successful
if( pid )
{ /* parent: */
close(slave); /* leave this out and lose slave's final words ... WHY? */
do
{
if( -1 == (nread = read(master, buf, BUFSIZE) ) )
{// then, error occurred
perror( "read failed" );
exit( EXIT_FAILURE );
}
// implied else, read successful
if ( nread )
{
write(STDOUT_FILENO, buf, nread); /* echo child's output to stdout */
}
} while (nread); /* nread == 0 indicates EOF */
}
else // pid == 0
{ /* child: */
if( -1 == login_tty(slave) ) /* this makes child a session leader and slave a controlling */
/* terminal for it, then dup()s std{in,out,err} to slave */
{ // then login_tty failed
perror( "login_tty failed" );
exit( EXIT_FAILURE );
}
// implied else, login_tty successful
printf("Feeling OK :-)\n");
sleep(1);
printf("Feeling unwell ... Arghhh!\n"); /* this line may get lost */
} // end if
return 0;
} // end function: main
when the close() statement is commented out
then the parent never exits due to the read() statement blocking
when the close() statement is part of the source
then the parent exits with a read error from trying to read from a terminal that is 'missing' when the child exits
here is the output when close() commentedpout
Feeling OK :-)
Feeling unwell ... Arghhh!
then the parent hangs on the read() statement
here is the output when close() is not commented out
Feeling OK :-)
Feeling unwell ... Arghhh!
read failed: Input/output error
I'm not sure if I get this right:
independent from pty or not, as long as one process has the channel open, the OS should not pass an EOF to the reader (because there is still a writer). (after the fork there are two open channels) only if you close the parent, a close on the slave should forward the EOF.
On a PTY, are you sure that NL's are handled correctly, since normally a CR should trigger the new-line.
(just a thought:
if it is a controling tty, things might change since the OS handles singal deliveries differently and closing the chanel would normaly terminate all children processes of the child. Could this be an issue if the parent still has the handle open? )
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.