Improve company productivity with a Business Account.Sign Up

  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 388
  • Last Modified:

How do I handle EINTR status

Hi guys, gals and any others :-) out there, I have a 'C' based routine writing records to a pipe. This routine is part of a dynalink library linked in at run time to a "host utility program". The "host utility program" reads records from a data base and passes each record to my routine one at a time for some processing (i.e. writing them to the pipe). I have no access to the internals or the source code of the "host utility". The host utility is a database export utility (called fastexport) for the Teradata RDBMS my dynalink library is refered to as an OUTMOD in Teradata parlance.

My problem is that every now and then (maybe once in a million records processed) I get the EINTR result back from the write system call. The call fails (because of the EINTR) but if i simply retry the call then no problem for another million records or so (figures are highly variable it could go 10 million records or more without error smallest # of records was about 100K before EINTR). The record format is always the same.  For what it is worth the pipe is a named pipe opened with the open system call and the O_WRONLY flag. The reader process opens the pipe with the O_RDONLY flag set on the open system call.

I have some basic understanding of what an EINTR means from my University days but can't find any doco on it in any of the unix man pages (other than the really helpful :-) #define statement in errno.h). So, my questions are:
* when I get the EITNR, how do i handle it (I assume it is unwise to simply ignore it without at least understanding why it is occuring)?
* Is it possible to determine what the interrupt was that occured during the system call (to help understand why it is happening)?
* Is the interrupt it is referring to a signal (again can you determine which one)?
* If i determine that the interrupt is something that the host utility is trying to handle is there a way to "raise" the signal from my dynalink routine back to the host utility?
* If none of the above questions hints at this one, what is Unix trying to tell me? i.e. is it trying to tell me that a system wide interrupt occured (eg a timer tick) during my system call and Unix is trying to tell me that it dealt with it - i find this unlikely? Or is unix trying to tell me that a signal i (or the host utility) has requested to handle had fired whilst stuck in the system call and as a result, Unix couldn't invoke my handler because it was in the middle of the system call?

  • 2
  • 2
  • 2
  • +3
1 Solution
My write man-page says:

  EINTR  The call was interrupted by a signal before any
         data was written.

So it just tells you that somthing with a higher priority happend *and* rejected to continue in write().
If you do get EINTR, there's little you can do except retrying.
The signal is probably one of those that the host utility handles. If you find out which one, you can specify the SA_RESTART option in a sigaction call. Or, you can mask signal(s)
before write and unmask afterwards.
This is interesting...I have an app that forks, and the sibling processes communicate through a pipe created by socketpair() before the fork().  Very occasionally, one end gets an EINTR while reading the pipe.  I've written a signal collector that I hope will tell me what signal is causing the EINTR, but I haven't put it in place yet.  (Although, as mlev points out, in your case it may be a signal that has meaning only to the host application, but that happens to strike when you're read()ing or write()ing.)
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

If a process caught a signal while process was blocked in a slow system call, the system call is interrupted and return an error and the error number is set to EINTR. The places where it may happen are

1. Reads from and writes to pipes, terminal and N/W devices
2. IPC
3. some ioctl calls,
4. pause etc.

 In your case, as the signal is for the host application and not for you. But as a result of which your system call (read?) failed.

There are two ways to tackle it.

1. An example code is given below.

loop: if ((n = read(pipeid,buf, BUFSIZE)) < 0) {
            if (errno == EINTR)
                  goto loop;

Change the code to something without the goto ;-)

2. Some of the Unix systems offer the option of restarting the system call. Please note that all systems do not support this. In SVR4 systems, you have to specify SA_RESTART in the sigaction call.Once this is specified, kernel will restart the interrupted system call.
firefox032697Author Commented:
We already retry the system call and as stated in the question if we retry it is fine for another million records or so.

The other, important, questions for which we need the answers are:
* how do we tell what the signal was that occured during the system call?
* Can we raise the signal (eg. with the kill system call) that did occur so that we can notify the host program?

If we can figure out what the signal was then we could certainly raise it to the parent process. This means that the most important thing is how can i determine what the signal was?
You don't need to raise the signal, the host program has already handled it at that point.
As a rule, if a process receives a signal while in kernel mode,
the signal is processed right after the system call.
It works like this:
1. You call write.
2. Before it is completed, the kernel decides (for whatever reason)
that your process should get SIGXXXX.
3. write is aborted with errno=EINTR
4. The signal handler for SIGXXXX is called.
5. Execution resumes after the call to write.
Since the host program has already caught the signal, there is no need to catch the signal(I don't know if you can catch this, since the signal may not even be delivered to you).

And you have pointed out that you have no control ovet the server process & program.
if you read the man page of sigaction, you will notice that for each interrupt you can either enable or disable it, and if you enabled it, you can write write your own catch routine. (you even can handle SEGV or BUS signals).

Inside your own catch routine you can determine which signal/interrupt occured. (It is passed as a parameter)

You can find an example (one of many) at:

If you want to raise signals , use the kill command, or the sigsend function.

Need more info? reject the answer and wait for better/more info

firefox032697Author Commented:
Thanks to all those who contributed (especially mlev)
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 2
  • 2
  • 2
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now