title: recv() is not interrupted by a signal in multithreaded environment
body: <p>I have a thread that sits in a blocking <code>recv()</code> loop and I want to terminate (assume this can't be changed to <code>select()</code> or any other asynchronous approach).</p>
  
  <p>I also have a signal handler that catches <code>SIGINT</code> and theoretically it should make <code>recv()</code> return with error and <code>errno</code> set to <code>EINTR</code>.</p>
  
  <p>But it doesn't, which I assume has something to do with the fact that the application is multi-threaded. There is also another thread, which is meanwhile waiting on a <code>pthread_join()</code> call.</p>
  
  <p>What's happening here?</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>OK, now I explicitly deliver the signal to all blocking <code>recv()</code> threads via <code>pthread_kill()</code> from the main thread (which results in the same global <code>SIGINT</code> signal handler installed, though multiple invocations are benign). But <code>recv()</code> call is still not unblocked.</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>I've written a code sample that reproduces the problem.</p>
  
  <ol>
  <li>Main thread connects a socket to a misbehaving remote host that won't let the connection go.</li>
  <li>All signals blocked.</li>
  <li>Read thread thread is started.</li>
  <li>Main unblocks and installs handler for <code>SIGINT</code>.</li>
  <li>Read thread unblocks and installs handler for <code>SIGUSR1</code>.</li>
  <li>Main thread's signal handler sends a <code>SIGUSR1</code> to the read thread.</li>
  </ol>
  
  <p>Interestingly, if I replace <code>recv()</code> with <code>sleep()</code> it is interrupted just fine.</p>
  
  <p>PS</p>
  
  <p>Alternatively you can just open a UDP socket instead of using a server.</p>
  
  <h2>client</h2>
  
  <pre><code>#include &lt;pthread.h&gt;
  #include &lt;signal.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;memory.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;netinet/in.h&gt;
  #include &lt;netinet/tcp.h&gt;
  #include &lt;arpa/inet.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;errno.h&gt;
  
  static void
  err(const char *msg)
  {
      perror(msg);
      abort();
  }
  
  static void
  blockall()
  {
      sigset_t ss;
      sigfillset(&amp;ss);
      if (pthread_sigmask(SIG_BLOCK, &amp;ss, NULL))
          err("pthread_sigmask");
  }
  
  static void
  unblock(int signum)
  {
      sigset_t ss;
      sigemptyset(&amp;ss);
      sigaddset(&amp;ss, signum);
      if (pthread_sigmask(SIG_UNBLOCK, &amp;ss, NULL))
          err("pthread_sigmask");
  }
  
  void
  sigusr1(int signum)
  {
      (void)signum;
      printf("%lu: SIGUSR1\n", pthread_self());
  }
  
  void*
  read_thread(void *arg)
  {
      int sock, r;
      char buf[100];
  
      unblock(SIGUSR1);
      signal(SIGUSR1, &amp;sigusr1);
      sock = *(int*)arg;
      printf("Thread (self=%lu, sock=%d)\n", pthread_self(), sock);
      r = 1;
      while (r &gt; 0)
      {
          r = recv(sock, buf, sizeof buf, 0);
          printf("recv=%d\n", r);
      }
      if (r &lt; 0)
          perror("recv");
      return NULL;
  }
  
  int sock;
  pthread_t t;
  
  void
  sigint(int signum)
  {
      int r;
      (void)signum;
      printf("%lu: SIGINT\n", pthread_self());
      printf("Killing %lu\n", t);
      r = pthread_kill(t, SIGUSR1);
      if (r)
      {
          printf("%s\n", strerror(r));
          abort();
      }
  }
  
  int
  main()
  {
      pthread_attr_t attr;
      struct sockaddr_in addr;
  
      printf("main thread: %lu\n", pthread_self());
      memset(&amp;addr, 0, sizeof addr);
      sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (socket &lt; 0)
          err("socket");
      addr.sin_family = AF_INET;
      addr.sin_port = htons(8888);
      if (inet_pton(AF_INET, "127.0.0.1", &amp;addr.sin_addr) &lt;= 0)
          err("inet_pton");
      if (connect(sock, (struct sockaddr *)&amp;addr, sizeof addr))
          err("connect");
  
      blockall();
      pthread_attr_init(&amp;attr);
      pthread_attr_setdetachstate(&amp;attr, PTHREAD_CREATE_JOINABLE);
      if (pthread_create(&amp;t, &amp;attr, &amp;read_thread, &amp;sock))
          err("pthread_create");
      pthread_attr_destroy(&amp;attr);
      unblock(SIGINT);
      signal(SIGINT, &amp;sigint);
  
      if (sleep(1000))
          perror("sleep");
      if (pthread_join(t, NULL))
          err("pthread_join");
      if (close(sock))
          err("close");
  
      return 0;
  }
  </code></pre>
  
  <h2>server</h2>
  
  <pre><code>import socket
  import time
  
  s = socket.socket(socket.AF_INET)
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  s.bind(('127.0.0.1',8888))
  s.listen(1)
  c = []
  while True:
      (conn, addr) =  s.accept()
      c.append(conn)
  </code></pre>