[zeromq-dev] PATCH: zmq::signaler_t should not assert on EINTR

Martin Lucina mato at kotelna.sk
Thu Aug 5 17:51:50 CEST 2010


Hi,

I've encountered a situation where zmq::signaler_t asserts due to the
recv() or send() returning with EINTR. This happens for example when I use
^C to exit some test programs.

The following patch fixes this by restarting the system calls when EINTR is
received. Martin, are you ok with the patch and behaviour? I cover both the
AIX/HPUX and default case, Win32 is not relevant since WSAEINTR does not
occur according to the docs in what seems to be a situation where we would
want to restart the call:

WSAEINTR: Interrupted function call.

    A blocking operation was interrupted by a call to WSACancelBlockingCall.

Now there is one thing left which is that when my application handles
SIGINT and attempts to correctly close all sockets and do a zmq_term(), I
occasionally get the following assertion during the close():

Assertion failed: !more || pipes [current] != pipe_ (lb.cpp:48)

I'm assuming that this happens becase the socket that is being closed had
been left by the application in a bogus state where it started sending a
multipart message but did not finish it. Martin, is this correct?

-mato

diff --git a/src/signaler.cpp b/src/signaler.cpp
index 592688b..b2055bf 100644
--- a/src/signaler.cpp
+++ b/src/signaler.cpp
@@ -176,7 +176,10 @@ zmq::signaler_t::~signaler_t ()
 
 void zmq::signaler_t::send (const command_t &cmd_)
 {
-    ssize_t nbytes = send (w, &cmd_, sizeof (command_t), 0);
+    ssize_t nbytes;
+    do {
+        ::send (w, &cmd_, sizeof (command_t), 0);
+    } while (nbytes == -1 && errno == EINTR);
     errno_assert (nbytes != -1);
     zmq_assert (nbytes == sizeof (command_t));
 }
@@ -194,7 +197,10 @@ bool zmq::signaler_t::recv (command_t &cmd_, bool block_)
     }
 
     bool result;
-    ssize_t nbytes = recv (r, buffer, sizeof (command_t), 0);
+    ssize_t nbytes;
+    do {
+        nbytes = ::recv (r, buffer, sizeof (command_t), 0);
+    } while (nbytes == -1 && errno == EINTR);
     if (nbytes == -1 && errno == EAGAIN) {
         result = false;
     }
@@ -249,7 +255,10 @@ void zmq::signaler_t::send (const command_t &cmd_)
 {
     //  TODO: Note that send is a blocking operation.
     //  How should we behave if the command cannot be written to the signaler?
-    ssize_t nbytes = ::send (w, &cmd_, sizeof (command_t), 0);
+    ssize_t nbytes;
+    do {
+        nbytes = ::send (w, &cmd_, sizeof (command_t), 0);
+    } while (nbytes == -1 && errno == EINTR);
     errno_assert (nbytes != -1);
 
     //  This should never happen as we've already checked that command size is
@@ -259,8 +268,11 @@ void zmq::signaler_t::send (const command_t &cmd_)
 
 bool zmq::signaler_t::recv (command_t *cmd_, bool block_)
 {
-    ssize_t nbytes = ::recv (r, cmd_, sizeof (command_t),
-        block_ ? 0 : MSG_DONTWAIT);
+    ssize_t nbytes;
+    do {
+        nbytes = ::recv (r, cmd_, sizeof (command_t),
+            block_ ? 0 : MSG_DONTWAIT);
+    } while (nbytes == -1 && errno == EINTR);
 
     //  If there's no signal available return false.
     if (nbytes == -1 && errno == EAGAIN)



More information about the zeromq-dev mailing list