The other answers are pretty clear, but after reading some of your comments, I would like to add some further information.
First of all, you got the idea behind EINTR
wrong. Getting interrupted by a signal in a syscall is not to be perceived as an error. The rationale behind EINTR
in slow syscalls (slow syscalls are those that can block forever, like open(2)
on some file types - terminal devices for example - accept(2)
, read(2)
and write(2)
on some devices - sockets included - etc.) is that if your program was blocked in a syscall and a signal was caught (while still blocked), then it is very likely (but not mandatory) that the signal handler changed state in your program and things are different, so the call returns prematurely with EINTR
to give you a chance of doing anything that you might want to do. It is not an error like EINVAL
or EBADF
or other "real" errors - it's just the way the kernel tells you that a signal was caught.
If you don't want to do anything, then either set the SA_RESTART
flag on the sa_flags
field of struct sigaction
when setting up the signal handler (which causes the syscall to be automatically restarted), or explicitly call send(2)
again when it returns -1 with errno
set to EINTR
.
The bottom line is, there isn't an inherent limitation on the kernel that forces it to return to userspace when signals are caught. Instead, EINTR
is just a convenient behavior that developers might find useful.
If the kernel was in the midst of transmitting data and a signal was raised, it's no big deal: if data is being transmitted, the syscall is doing progress. The kernel is in process context executing a syscall in behalf of the program that called it, so technically the process is not sleeping anymore. If a signal arrives, it will be pending until the kernel decides that it's time to deliver it to the process - most likely, this happens once send(2)
returns.