darbehdar
darbehdar

Reputation: 111

Interruption of system calls when a signal is caught

From reading the man pages on the 'read()' and 'write()' calls it appears that these calls get interrupted by signals regardless of whether they have to block or not.

In particular, assume

Reading the man pages and the appropriate sections in SUSv3 'System Interfaces volume (XSH)' one finds that:

i. If a read() is interrupted by a signal before it reads any data ( i.e. it had to block because no data was available ), it returns -1 with 'errno' set to [EINTR].

ii. If a read() is interrupted by a signal after it has successfully read some data ( i.e. it was possible to start servicing the request immediately ), it returns the number of bytes read

Question A):

Am I correct to assume that in either case (block/no block) the delivery and handling of the signal is not entirely transparent to the 'read()'?

Case i. seems understandable since the blocking 'read()' would normally place the process in the 'TASK_INTERRUPTIBLE' state so that when a signal is delivered, the kernel places the process into 'TASK_RUNNING' state.

However when the 'read()' doesn't need to block ( case ii. ) and is processing the request in kernel-space, I would have thought that the arrival of a signal and its handling would be transparent much like the arrival and proper handling of a HW interrupt would be. In particular I would have assumed that upon delivery of the signal, the process would be temporarily placed into USER-MODE to execute its signal handler from which it would return eventually to finish off processing the interrupted 'read()' ( in kernel-space ) so that the 'read()' runs its course to completion after which the process returns back to the point just after the call to 'read()' ( in user-space ), with all of the available bytes read as a result.

But ii. seems to imply that the 'read()' is interrupted, since data is available immediately BUT it returns returns 'some' of the data ( instead of all ).

This brings me to my second ( and final ) question

Question B):

If my assumption under A) is correct, why does the 'read()' get interrupted, even though it does not need to block because there is data available to satisfy the request immediately? In other words, why is the 'read()' not resumed after executing the signal handler, eventually resulting in all of the available data ( which was avialable after all ) to be returned?

Upvotes: 0

Views: 1852

Answers (2)

caf
caf

Reputation: 239041

When a signal is sent to a process, all the kernel does is set a flag in the process's task struct to indicate that the signal is pending, and wake it up if it is in an interruptible sleep (TASK_INTERRUPTIBLE).

This means that from the point of view of the blocking syscall kernel code, it sees itself wake up from a sleep, just as it would if the device had signalled that more data was ready. It is the responsibility of the syscall code to check for a waiting signal and return to userspace (so that the signal may be handled).

(Note that another implication of this is that if an asychronous signal is raised while the process is in userspace, necessarily by a process running on another CPU, the signal usually won't be handled until the next timer tick or syscall).

Upvotes: 1

Dipstick
Dipstick

Reputation: 10129

The device driver may require to grab a mutex before processing the read - if the wait on mutex is interrupted by a signal then the driver is likely to return EINTR in both blocking and non-blocking modes as it doesn't know yet whether there is data available. It obviously cannot return any data and should not return EAGAIN which would lead the caller to falsely imply that there was no data available so that - for instance - the caller might sleep for a while.

Upvotes: 0

Related Questions