PDA

View Full Version : Problem with O_NONBLOCK Pipe



hosseinyounesi
08-16-2009, 03:17 PM
Hi,
I'm trying to send and receive using pipes:

send.cpp


struct
{
long a;
long b;
}T;
cout << "1" << endl;
if ( access ( FIFO_NAME, F_OK ) == -1 ) {
res = mkfifo ( FIFO_NAME, 0755 );
if ( res != 0 )
cout << " Can't make fifo" << endl;
}

cout << "2" << endl;
pipe_fd = open ( FIFO_NAME, O_WRONLY);
cout << "3: " << pipe_fd << endl;
a=b=1;
res = write ( pipe_fd, &T, sizeof ( T ) );
cout << "4" << endl;
close(pipe_fd);


recv.cpp


cout << "1" << endl;
pipe_fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK);
cout << "2" << endl;
res = read(pipe_fd, &T, sizeof(T));
cout << T.a << T.b << endl;
close(pipe_fd);




./send
./recv


open is correct, but when send.cpp executes "write" the program terminates and "4" is not displayed!!!! I recv side the T.a and T.b are not correct !

What's wrong with my programs?! (I have to say that programs are working correct when I remove O_NONBLOCK falg)

thanks

bithub
08-17-2009, 03:30 PM
What is the pipe_fd that is printed out in the sender?

hosseinyounesi
08-17-2009, 03:37 PM
pipe_fd is an int var as file descriptor. I've used it in write function.

bithub
08-17-2009, 03:44 PM
That wasn't my question...

cout << "3: " << pipe_fd << endl;
What is the output of that line of code.

hosseinyounesi
08-17-2009, 03:49 PM
ou, sorry! It changes in every execution but Is not -1

hosseinyounesi
08-19-2009, 02:25 PM
Unknown problem? No one has used O_NONBLOCK before?!!!!

bithub
08-19-2009, 02:37 PM
Well you are probably getting a SIGPIPE sent to your application due to writing before the receiver has opened its side of the pipe.

From the documentation:

The kernel maintains exactly one pipe object for each FIFO special file
that is opened by at least one process. 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.
Since you are opening the pipe as non-blocking, that bolded part does not happen for you. This is why it works when you don't use O_NONBLOCK, but it doesn't work for you now.

hosseinyounesi
08-19-2009, 02:43 PM
Thanks, I know this, But how can I use pipes in nonblocking mode? I couldn't find any example :(

bithub
08-19-2009, 03:01 PM
Do you need to use nonblocking mode? What problem are you trying to solve?

Kennedy
08-19-2009, 04:03 PM
If you are in non-blocking mode you'll have to poll the device (or use select()) to see when data is there (and that would be in a loop).

hosseinyounesi
08-20-2009, 06:06 AM
Thanks, would you mind give me an example or use select in the program I wrote in the first post?

Kennedy
08-20-2009, 06:51 AM
int main(void)
{
int file, retval;
char buf[1024];

if ((file = open("something", O_NONBLOCK)) < 0){
return -EFAULT;
}
while (1){
retval = read(fd, buf, 1023);
if (retval < 0){
break;
}
if (retval){
buf[retval] = '\0';
printf("Got data: len = %i, data = %s\n", retval, buf);
}
if (!strcmp(buf, "STOPLOOP")){
break;
}
}
if (retval < 0){
printf("Got an error: %i\n", retval);
if (errno){
perror("read");
}
}
close(fd);
return retval;
}


SELECT(2) Linux Programmer's Manual SELECT(2)

NAME
select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing

SYNOPSIS
/* According to POSIX.1-2001 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

#include <sys/select.h>

int pselect(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, const struct timespec *timeout,
const sigset_t *sigmask);

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

pselect(): _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600

DESCRIPTION
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors
become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to
perform the corresponding I/O operation (e.g., read(2)) without blocking.

The operation of select() and pselect() is identical, with three differences:

(i) select() uses a timeout that is a struct timeval (with seconds and microseconds), while pselect() uses a struct timespec
(with seconds and nanoseconds).

(ii) select() may update the timeout argument to indicate how much time was left. pselect() does not change this argument.

(iii) select() has no sigmask argument, and behaves as pselect() called with NULL sigmask.

Three independent sets of file descriptors are watched. Those listed in readfds will be watched to see if characters become avail-
able for reading (more precisely, to see if a read will not block; in particular, a file descriptor is also ready on end-of-file),
those in writefds will be watched to see if a write will not block, and those in exceptfds will be watched for exceptions. On exit,
the sets are modified in place to indicate which file descriptors actually changed status. Each of the three file descriptor sets
may be specified as NULL if no file descriptors are to be watched for the corresponding class of events.

Four macros are provided to manipulate the sets. FD_ZERO() clears a set. FD_SET() and FD_CLR() respectively add and remove a given
file descriptor from a set. FD_ISSET() tests to see if a file descriptor is part of the set; this is useful after select() returns.

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval stucture are zero,
then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.

sigmask is a pointer to a signal mask (see sigprocmask(2)); if it is not NULL, then pselect() first replaces the current signal mask
by the one pointed to by sigmask, then does the "select" function, and then restores the original signal mask.

Other than the difference in the precision of the timeout argument, the following pselect() call:

ready = pselect(nfds, &readfds, &writefds, &exceptfds,
timeout, &sigmask);

is equivalent to atomically executing the following calls:

sigset_t origmask;

sigprocmask(SIG_SETMASK, &sigmask, &origmask);
ready = select(nfds, &readfds, &writefds, &exceptfds, timeout);
sigprocmask(SIG_SETMASK, &origmask, NULL);

The reason that pselect() is needed is that if one wants to wait for either a signal or for a file descriptor to become ready, then
an atomic test is needed to prevent race conditions. (Suppose the signal handler sets a global flag and returns. Then a test of
this global flag followed by a call of select() could hang indefinitely if the signal arrived just after the test but just before
the call. By contrast, pselect() allows one to first block signals, handle the signals that have come in, then call pselect() with
the desired sigmask, avoiding the race.)

The timeout
The time structures involved are defined in <sys/time.h> and look like

struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};

and

struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};

(However, see below on the POSIX.1-2001 versions.)

Some code calls select() with all three sets empty, nfds zero, and a non-NULL timeout as a fairly portable way to sleep with subsec-
ond precision.

On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this.
(POSIX.1-2001 permits either behavior.) This causes problems both when Linux code which reads timeout is ported to other operating
systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it.
Consider timeout to be undefined after select() returns.

RETURN VALUE
On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is,
the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything
interesting happens. On error, -1 is returned, and errno is set appropriately; the sets and timeout become undefined, so do not
rely on their contents after an error.

ERRORS
EBADF An invalid file descriptor was given in one of the sets. (Perhaps a file descriptor that was already closed, or one on which
an error has occurred.)

EINTR A signal was caught; see signal(7).

EINVAL nfds is negative or the value contained within timeout is invalid.

ENOMEM unable to allocate memory for internal tables.

hosseinyounesi
08-21-2009, 02:21 AM
Thanks a lot, I'm gonna test it and I will report the result here :)

hosseinyounesi
08-21-2009, 01:42 PM
I wrote the program to 'write' on the read program you wrote. But some times the write program fails on write and read program sometimes crashes on open or read. Also, you haven't used 'select' function !!!

hosseinyounesi
08-23-2009, 04:12 PM
I'm going to be disappointed :(
But I think using a blocking read after successful nonblocking read will do my job!

Another question: After closing my program, will the pipe file be deleted? I think no. So why?

Thanks anyone

MK27
08-24-2009, 07:28 AM
Another question: After closing my program, will the pipe file be deleted? I think no. So why?


Because it's a named file you created. Remove it after you close the handle with unlink().

hosseinyounesi
09-18-2009, 02:13 PM
This is what I tried, and it is working now :)

read:


fd_set rfds;
int res=0;
int retval;
struct timeval tv;
//////////////////
FD_ZERO(&rfds);

int pipe_fd = open( FIFO_NAME, O_RDONLY | O_NONBLOCK);

FD_SET(pipe_fd, &rfds);

tv.tv_sec = 1;
tv.tv_usec = 0;
int nfds = max( pipe_fd,1 ) + 1;
retval = select(nfds, &rfds, NULL, NULL, &tv);

if ( retval!=-1 )
{
if (FD_ISSET(pipe_fd,&rfds))
res = read(pipe_fd, &T, sizeof(T));
}
close(pipe_fd);

//Ignore Invalid Messages
if(res != sizeof(T)) return -1;


write:


int pipe_fd=0, res=0;
//////////////////
while(1)
{
pipe_fd = open ( FIFO_NAME.c_str(), O_WRONLY );
if ( pipe_fd == -1 )
cout << "open error" << endl;

res = write ( pipe_fd, &T, sizeof ( T ) );
if ( res == -1 )
cout << "write error" << endl;

close ( pipe_fd );
sleep ( 1 );
}


So, there is a select, controlling pipe with FD_ISSET and a sleep. If there is any AMBIGUITY or something is missed, please tell me.

Thanks