LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
LinkBack Search this Thread
Old 05-21-2008, 05:20 AM   #1
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Rep: Reputation: 15
Question on using select() function call with FIFO


Hi

I am trying to use FIFO to communicate between two processes A (reader par) and B(writer part)

In A, i am creating FIFO, opening in non-blocking mode and then waiting in select for 10 secs. In B, i am opening the FIFO in non-blocking mode, writing to FIFO and then closing the FIFO.

Now, If there is any incoming data in the read side, select returns and the corresponding bit in readfds is set. If there is no data, select returns on timeout. These two are normal scenario and work fine for me.

Now my requirement is to detect any abnormal conditions or any unexpected/fatal errors and take appropriate action(say reopening the fifo in read mode again and if once again reopen fails, recreating the fifo, reopening the FIFO and then going back and waiting in select).

But how do i detect unexpected error conditions when the read process blocks in select? Should i check for return of select (-1) or should i check if the bit for errorFds is set?

Please clarify

Thanks,
Sathya
 
Old 05-21-2008, 06:33 AM   #2
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: ubuntu
Posts: 2,524

Rep: Reputation: 93
Quote:
Originally Posted by Sathya View Post
But how do i detect unexpected error conditions when the read process blocks in select? Should i check for return of select (-1) or should i check if the bit for errorFds is set?
What do you mean by "[..]when the read process blocks in select"? The main reason to use select() is to make sure read() won't block.. Inside select() there is no "read process".

When select() returns it tells you what descriptor(s) will not block on a read(), write(), etc. This includes error conditions on descriptors: When there is an error condition on a descriptor, select() will return and will have the error-ing descriptoar flagged as well as those ready for reading/writing, since a read() or write() on a error-ing descriptor will not block either, but return immediately with an error code. So do the regular error-checking after read()/write()/.. and you will get the error for the read().write() call itself.

Since read()/write() will not block when select return, why use non-blocking I/O in combination with select()? AFAIKS this can only make things overly complex and buggy.

I'd recommend reading (at least) the section "SELECT LAW" of the select_tut(2) man page.

By the way: what is "errorFds"?
 
Old 05-22-2008, 02:28 AM   #3
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
Let me clearly explain why i posted that question

My requirement is, a process A(reader) has to look at the FIFO continuously and if there is any data from FIFO, process it. Now the situation is such that, FIFO might get data once in a week also. The writer process (B) opens the FIFO during a particular case, write into FIFO and immediately closes the FIFO.

So at other times(when no data written into fifo), this reader process should "log a heart beat in a file for every say t seconds" so that another "monitor" process will know that my process A is alive otherwise it will raise alarm to notify everyone.

So if i open FIFO in blocking mode, my reader process will always be blocked in open call / read function call. And there wont be any way for me to log a heart beat. This is why i went in for opening Nonblocking mode and inside a for loop, wait in select for "timeout t" secs. Within this timeout secs, if there is activity in FIFO, select returns and i can read data, or select returns with 0, in which case i can once again go to select and wait for another "timeout" seconds and so on.


So when i used select in this way, I was just wondering how to handle exceptional conditions/internal errors.

I came across a piece of code that handled error scenario as below:

Open FIFO in blocking mode for reading
read a character from Fifo
if character==EOF, then this means some internal error. So they try to reopen FIFO, and if that fails, they try to recreate FIFO and then reopen, and if that also fails, exit the reader process.

I was just wondering how to handle the exception condition in my scenario. I cannot definitely check for EOF because, if there is no activity in FIFO, select will return 0, and in that case read will give EOF only. But this is not an error case. So i did not know a way of differentiating the error and the "no data in FIFO scenario".

Please let me know how to handle this.

Thanks
Sathya
 
Old 05-22-2008, 06:13 AM   #4
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: ubuntu
Posts: 2,524

Rep: Reputation: 93
Quote:
Originally Posted by Sathya View Post
I was just wondering how to handle the exception condition in my scenario. I cannot definitely check for EOF because, if there is no activity in FIFO, select will return 0, and in that case read will give EOF only. But this is not an error case. So i did not know a way of differentiating the error and the "no data in FIFO scenario".

Please let me know how to handle this.
When EOF appears in the fifo, select will see this as activity and so will not return 0 in that case. 0 is only returned if select() times out.

In half-C / half-pseudo-code I'd try something like this:
Code:
while (1) {
    numfds = select(timeout);
    if (numfds < 0) {
        perror("select()");
        exit(1);
    }
    if (numfds == 0) { /* timeout */ 
        continue;  /* restart loop */
    }

    /* from here on there is some activity on one or more
     * file descriptors that select() was watching.
     *
     * Assumed one descriptor only for simplicity.
     * otherwise loop over all descriptors select() watched.
     */

    data = read(descriptor);
    if (read error) {
        perror("read()"); /* or handle in another way if you need to */
        exit(1);
    }
    if (EOF) { /* writer closed fifo, we're done for this week */
        continue;  /* restart loop */
    }

    /*** Handle data just read here. ***/

} /* end of loop */
When using non-blocking I/O this becomes more complex and more error prone.

Last edited by Hko; 05-22-2008 at 06:16 AM.
 
Old 05-23-2008, 11:00 AM   #5
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
What would be the possibility of a read error after select returns > 0? How can that happen?

How do u handle that error for blocking mode and nonblocking mode? Should we check the return of read/fread for EOF? Or should we check the errno value?

I am terribly confused with this error handling part of FIFO's.

Please clarify
 
Old 05-23-2008, 11:19 AM   #6
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: ubuntu
Posts: 2,524

Rep: Reputation: 93
Quote:
Originally Posted by Sathya View Post
What would be the possibility of a read error after select returns > 0? How can that happen?
When the file was opened for reading succesfully, not many errors can occur when reading from the file. The only two possibilities: error from disk (or whatever) or the read() was interrupted by a signal. (just read the "ERRORS" section of the man page of read(2) to find this out)

Quote:
Originally Posted by Sathya View Post
How do u handle that error for blocking mode and nonblocking mode?
The same way as a normal blocking descriptor. One more error can occur when using non-blocking descriptor: when trying to read when there is nothing to read. Handle this by continueing the loop and call select() again. Better yet again: do not use non-blocking unless you are 100% sure you need it. This is hardly ever needed when using select().

Quote:
Originally Posted by Sathya View Post
Should we check the return of read/fread for EOF? Or should we check the errno value?
Check the return code to detect if there was an error. If so, check errno value to figure out the type of the error (if you do need handle different error conditions differently at all).

Last edited by Hko; 05-23-2008 at 11:20 AM.
 
Old 05-29-2008, 07:00 AM   #7
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
Hi,

I find one more strange problem.
I have single reader and multiple writers. If some 400 processes pump in data into the FIFO, Sometimes, i lose some data in the reader side. However the writer puts all the data successfully into the FIFO. There is no error in the writer side.

I found by experiments that, the more logic and there by more functions, i add to the reader process this problem happens. I observed if there are 400 sentences sent by 400 writers, i find that the reader reads 1 or 2 less. The reason being select returning 0 even when there is data in FIFO

what would be the reason ?

Thanks,
Sathya
 
Old 05-29-2008, 07:39 AM   #8
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: ubuntu
Posts: 2,524

Rep: Reputation: 93
Pipes and fifo's are one-to-one connections. As long as the writer write in turn to the fifo and close it before the next one opens it for writing. But since the writing processes run independently you have no control over when they write. I wonder why there is no error from the writing processes.. Do you have full and correct error checking on opening and writing calls?

Two possible solutions:
  • Use locking, so writers will wait for eachother (IMHO not the best option in this case)
  • Use a (filesystem) socket, since then you can have multiple writing processes and read them in turn by using select().

Now I start wondering why you are using select(), as that would only make sense if you have more than one reading descriptor (e.g. socket or multiple pipes/files)... However, if you choose to use filesystem sockets, you could make good use of select().

Last edited by Hko; 05-29-2008 at 07:40 AM.
 
Old 05-29-2008, 10:05 AM   #9
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
I thought it could be flushing problem. So i did a flush of the writer side file descriptor. But there is no effect. I started 1 reader, and multiple instance of writer.

Please clarify. Pasting code for reference

READER SIDE:

int main()
{
int res,length,count,pipe1_fd;
FILE *pipedummy;
int pipe1_dummy;

int pid;

int read_res=0,retries=3,attempt=1;
int open_mode = O_RDONLY|O_NONBLOCK;
char temp[10];

char arr[4096+1];
memset(arr,'\0',4096+1);
char c;
int idx=0;

if (access(FIFO_NAME,F_OK) == 0)
{
unlink(FIFO_NAME);
}
res = mkfifo(FIFO_NAME,0777);
if (res != 0)
{
fprintf(stderr,"could not create fifo");
exit(-1);
}
pipe1_fd = open(FIFO_NAME, open_mode);
printf("File descriptor = %d\n",pipe1_fd);
pipe_fd= fdopen(pipe1_fd,"r");
printf("Before dummy write \n");
pipedummy= fopen(FIFO_NAME,"w");// so that select blocks when no writers are available
printf("After dummy write \n");

if (pipe_fd != NULL)
{
printf("After open\n");

while(1)
{
if(1 == isready(pipe1_fd))
{
idx++;
read_res = fscanf(pipe_fd,"%d%c",&length,&c);
if (read_res <= 0)
{
memset(arr,'\0',4096);
length=0;
printf("No data\n");

}
else
{
read_res = fread((void *)arr,sizeof(char),length,pipe_fd);
if (read_res == length)
{
printf("bytes read =%d\n",read_res);
printf("Result = %s %d\n", arr,idx);
}
else
perror("read error");
}
memset(arr,'\0',4096);
}
else
{
printf("INSIDE ELSE\n");
}

}
}
fclose(pipe_fd);
unlink(FIFO_NAME);
}


int isready(int fd)
{
int rc,rc1;
fd_set fds,err_fds;
int firstChar;
char x;
struct timeval tv;

tv.tv_sec = 10 ;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd,&fds);
printf("Before select %d\n",fd);
rc = select(fd+1, &fds, NULL, &err_fds, &tv);
printf("Return type = %d\n",rc);
if (rc < 0)
return -1;
rc = FD_ISSET(fd,&fds) ? 1 : 0;
FD_ZERO(&fds);
printf("After select %d\n",rc);
return rc;
}


WRITER SIDE:


int main()
{
int i,write_res,length,pipe2_fd,return1;
int open_mode = O_WRONLY|O_NONBLOCK;
printf("Before open\n");
pipe2_fd=open(FIFO_NAME, open_mode);
if (pipe2_fd < 0 )
{
perror("FIFO open: ");
sleep(10);
exit(0);
}
perror("Open error : ");
printf("Fild descriptor = %d\n",pipe2_fd);
FILE *server_fifo = fdopen(pipe2_fd, "w");

//signal(SIGPIPE,SIG_IGN);

perror("Return of fopen : ");
printf("After open\n");

char arr[4096+1];
char temp[4096+1];
char *x=arr;
length=strlen("1000,CR,[04/16/08 13:28:45] [9238] [cobmaknk] [cobm_iProcessParseErrorPayment], M.14: ,Installing converter failed,START processing Payment, 0 pending\n");
strcpy(arr,"1000,CR,[04/16/08 13:28:45] [9238] [cobmaknk] [cobm_iProcessParseErrorPayment], M.14: ,Installing converter failed,START processing Payment, 0 pending\n");

sprintf(temp,"%d,%s",length,arr);
printf("Sending data twice \n");
write_res=fprintf(server_fifo,"%d,%s",length,arr);
printf("Written: %d\n", write_res);
write_res=fprintf(server_fifo,"%d,%s",length,arr);
printf("Written: %d\n", write_res);

fclose (server_fifo);
}
 
Old 05-29-2008, 10:11 AM   #10
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
Since i am writing only characters less than PIPE_BUF, why should i need locking? It is atomic write.

Also, i use select only for 1 reason. Although there is only 1 fd, i dont want the process to always read fifo continuously. It will consuming CPU. Also i dont want the process to sleep for x seconds, when there is no data in FIFO. If data comes when it sleeps, there may be a chance that FIFO gets full by the time the writer wakes up. My requirement is reader should monitor FIFO for x seconds, and then if no data, should print a message and then once again monitor for x seconds.
 
Old 05-29-2008, 10:56 AM   #11
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
If you see in this program i pasted, run 1 reader instance and 1 writer instance,

There are two fprintf statment in writer. So reader should read both. But for the first time, you can see only 1 sentence being printed in the reader side after select returns. I am sure that the writer has sent both the data to the FIFO. because i am printing the return of fprintf.

If you start the writer instance once again, this problem gets rectified.

When this happens in multiple writer mode, i see randomness. But no data loss. I observe some flushing problem or delay in reading the data that comes last.
 
Old 05-29-2008, 01:45 PM   #12
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: ubuntu
Posts: 2,524

Rep: Reputation: 93
Quote:
Originally Posted by Sathya View Post
Since i am writing only characters less than PIPE_BUF, why should i need locking? It is atomic write.
Yes, I was probably wrong about that.
Sorry

Last edited by Hko; 05-29-2008 at 01:51 PM. Reason: I was wrong
 
Old 05-30-2008, 09:33 AM   #13
Sathya
Member
 
Registered: Sep 2007
Posts: 33

Original Poster
Rep: Reputation: 15
Hi

Actually i am opening fifo using open call and associating the file descriptor it returns to a stream using fdopen. I went for this logic because, select works on file descriptor and fscanf/fread etc works on file stream. Since i dont know how many bytes of characters are going to come in, the logic i use is
writer sends in format: "length,string"
reader reads length and comma character using fscanf and then "length" bytes using fread.

So i found that sometimes select returns 0, but getc of that file stream has a valid character and vice versa.

This is strange to me. This is why i lose the data towards the end. So the fix i have put was,

First read data using getc(), if it is not EOF, read the next set of character otherwise use select to wait for the next 10 secs for incoming data

Why is this behaviour?

I feel that the data passes from the file descriptor to the stream or something like that. So when it is not available here, it should be available there ..

Is there any way of opening a FIFO using fopen() call, but with nonblocking mode?

I am unable to use fcntl also to set NONBLOCK behaviour, because it also works on file stream ...
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
question about select sys call xatzipol Programming 1 10-30-2005 09:22 AM
C sockets Select call when to use? cranium2004 Programming 1 03-14-2005 05:56 AM
IPC in socket using select system call Gomathy Linux - Networking 0 01-28-2005 06:37 AM
python call function in same file(very newbie question) rmanocha Programming 2 11-21-2004 12:04 AM
select function as timeout? frostmagic Programming 2 02-09-2004 11:56 AM


All times are GMT -5. The time now is 02:59 PM.

Main Menu
 
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: @linuxquestions
Open Source Consulting | Domain Registration