[SERVER-4949] SIGPIPE causing process termination on accept()ed connections (OSX) Created: 13/Feb/12 Updated: 11/Jul/16 Resolved: 02/Mar/12 |
|
| Status: | Closed |
| Project: | Core Server |
| Component/s: | Networking |
| Affects Version/s: | 2.0.2 |
| Fix Version/s: | 2.1.1 |
| Type: | Bug | Priority: | Minor - P4 |
| Reporter: | Ben Becker | Assignee: | Eric Milkie |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
Mac OS X 10.7.3 |
||
| Attachments: |
|
| Operating System: | OS X |
| Participants: |
| Description |
|
It seems that inbound connections that terminate due to a broken pipe are not invoking the signal handler nor returning EPIPE on send() or recv(). This causes the entire process to die. Socket::connect() sets the SO_NOSIGPIPE socket option, however Listener::initAndListen() does not appear to set this option on the accept()ed socket. The following is reproducible (from gdb mongos) with a simple PHP script that queries for all results and severing the connection while exhausting the cursor:
See the full backtrace of thread #20 for details. Although I'm not sure why signal(SIGPIPE, pipeSigHandler) does not cause the handler to be invoked, a work-around may be to set SO_NOSIGPIPE on the accept()ed socket in Listener::initAndListen(). Socket::connect() already does this:
|
| Comments |
| Comment by auto [ 02/Mar/12 ] |
|
Author: {u'login': u'milkie', u'name': u'Eric Milkie', u'email': u'milkie@10gen.com'}Message: |
| Comment by Ben Becker [ 16/Feb/12 ] |
|
Attaching the script I used to reproduce. Simply killing this script while running would cause the unhandled SIGPIPE for me at least 50% of the time. |
| Comment by Eric Milkie [ 16/Feb/12 ] |
|
Ben, can you send me your PHP script? The python script that I wrote isn't able to reproduce the issue on my Mac, even with mongos; I just get the "got pipe signal:" message. |
| Comment by Eric Milkie [ 16/Feb/12 ] |
|
SIGPIPE appears to be a thread-directed signal (on Darwin). I think that means you have to call signal() on every thread for which you want masking. Setting the NOSIGPIPE socket option seems like a decent way to fix this; I'll add it to the incoming sockets. |