4

I'm programming with socket which is in blocking mode, I have a question about send method.

In the man page of send method, it says:

[EINTR] A signal interrupts the system call before any data is transmitted.

It means if a signal interrupts the system call before any data is transmitted, the send would return -1 and errno would be set to EINTR.

My question is that if a part of data has been transmitted when a signal interrupts the system call, what will return. It seems that it shouldn't return -1 because it has send some data. I think it will return the number of data has been transmitted which means send method in the blocking mode may return less number of data than you passed as third parameter.

ssize_t send(int socket, const void *buffer, size_t length, int flags);

KudoCC
  • 6,912
  • 1
  • 24
  • 53
  • This [question](http://stackoverflow.com/questions/2618736/why-is-it-assumed-that-send-may-return-with-less-than-requested-data-transmitted) is similar to my questions and it's more useful. – KudoCC Jul 30 '16 at 10:32

3 Answers3

2

The documentation is clear.

RETURN VALUE

On success, these calls return the number of bytes sent. On error, -1 is returned, and errno is set appropriately.

[...]

EINTR A signal occurred before any data was transmitted;

send() either returns

  • the number of bytes sent
  • or -1

If -1 is returned the reason is indicated via the value of errno.

If errno equals EINTR a signal interupted send() while no data had been received so far.

From this info above one can safely conclude that if data had been received the send() function would not return -1, not matter whether a signal was received or not.

alk
  • 69,737
  • 10
  • 105
  • 255
  • I have the same idea with you but I'm not sure about that. That's because I don't understand why it is an error when "A signal occurred before any data was transmitted", if "a signal occurred" causes the error, why "a signal occurred after some data was transmitted" is a succuss. – KudoCC Jul 01 '15 at 11:11
  • @KudoCC: If you face a different bahaviour, either your program or `send()`'s implementation is buggy. – alk Jul 01 '15 at 11:24
  • @KudoCC: Getting interrupted by a signal is not to be considered an error. At least on Linux you also can switch off this behaviour on a signal base using the signal attribute `SA_RESTART`. – alk Jul 01 '15 at 11:25
  • Thanks, what I want is that you make sure about that :) – KudoCC Jul 01 '15 at 11:34
  • @KudoCC: Isn't this "*From this info above one can safely conclude that ...*" sure enough? – alk Jul 01 '15 at 12:03
  • @KudoCC: You might want to accept this great answer http://stackoverflow.com/a/31160284/694576, but mine. – alk Jul 01 '15 at 12:07
  • Thanks for your advice :D It's generous of you. – KudoCC Jul 01 '15 at 12:11
2

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.

Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • Thanks for taking the burden of giving a significant amount of background info on this! :-) 1+ btw – alk Jul 01 '15 at 12:06
  • Thanks for your answer, I have noticed it for a while and tried to understand it, but I find it's hard to understand unless having some background knowledage about the kernel/signal and so on. – KudoCC Jul 01 '15 at 12:07
  • @KudoCC Glad I could help! Thanks for the great question too :) – Filipe Gonçalves Jul 01 '15 at 12:09
-1

[EINTR] A signal interrupts the system call before any data is transmitted.

This means that if send() start transmitting data, it won't be interrupted by any signals. So, transmission will block the receiving of signal until it finishes. The situation that send() may return less bytes of data than you passed as third parameter is usually due to the network problems, such as packets lost.

Douglas Su
  • 3,214
  • 7
  • 29
  • 58
  • 1
    Do you have some reference to support your answer ? I'm sure that TCP will handle the packets lost without make the `send` method return. – KudoCC Jul 01 '15 at 09:58
  • You can check out how device drivers implement their `write()` functions. `send()` does a lot familiar to `write()` but the network relevant parts. In the implement of `write()`, you will find something like this: `if (signal_pending(current)) return -ERESTARTSYS; ` which will interrupt the transmission if some signals is pending. http://www.makelinux.net/ldd3/chp-6-sect-2 maybe can help you. – Douglas Su Jul 01 '15 at 10:12
  • Thanks, but we are talking about socket, the implementation seems to be the file system IO, not the network. Though they have the same interface but they are implemented differently. – KudoCC Jul 01 '15 at 11:08
  • socket is a special I/O, the `read()` and `send()` are nearly no different. You can check http://stackoverflow.com/questions/1790750/what-is-the-difference-between-read-and-recv-and-between-send-and-write for this. Also, if you actually know the bottom of Linux OS, all of these operations are based on the Virtual Filesystem layer, no matter network socket or files on spin disk. – Douglas Su Jul 01 '15 at 11:18
  • Virtual File system offers the same interface to users, but the implementation below is different from each other. – KudoCC Jul 01 '15 at 11:37
  • Of course! `write()` or `send()` are high lever functions based on virtual filesystem not only for userspace, but also parts of kernel space. – Douglas Su Jul 01 '15 at 11:46
  • I'm not sure if it will be interrupted by a signal after `send` start to transmitting data, but I think your statement about the returned less bytes is wrong. – KudoCC Jul 01 '15 at 12:00
  • 1
    What do feel it wrong with "*... [the] statement about the returned less bytes ...*"? – alk Jul 01 '15 at 12:29
  • I think you need to learn more about kernel. I can explain this in hundreds of words. VFS actually hides the most hardware related details and provides a common interface above. Filipe Gonçalves' answer shows the fact that no matter `write()` or `send()`, before they actually operate datas, they give you a chance to handle the signals which still pending, it is implemented via something like `if (signal_pending(current)) return -ERESTARTSYS;`. – Douglas Su Jul 01 '15 at 12:37
  • @alk I thinks it is one of all cases which could cause this. Can you show me some clues about this? – Douglas Su Jul 01 '15 at 12:48
  • @DouglasSu I will learn it :) send method in blocking mode returns when a)the peer close the socket b) it finish sending the data c) signal raise . But it won't returns when some packets are lost, tcp will resend them when it receive a repeat ack or timer is time out. – KudoCC Jul 01 '15 at 13:28
  • @alk Actually I have the book. By the way what do you think of this answer ? – KudoCC Jul 01 '15 at 13:30
  • @KudoCC You stand in userspace, I stand at the bottom of OS, So, from your view packets loss can never happen. – Douglas Su Jul 01 '15 at 14:11
  • I didn't say packets loss wouldn't happen, but it won't cause `send` method return. But if the receiver never response to the sender, after a period of time, tcp will give up and `send` method will return. – KudoCC Jul 01 '15 at 14:14
  • what will happen if parts of packets are successfully transmitted and they are sent by a single call to send syscall – Douglas Su Jul 01 '15 at 15:56