Bug 97921 - [socket] close() socket deadlocks blocked threads
Summary: [socket] close() socket deadlocks blocked threads
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Robert Watson
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-05-25 18:40 UTC by Kurt Miller
Modified: 2018-05-28 19:41 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kurt Miller 2006-05-25 18:40:17 UTC
When a thread is blocked waiting for data on a socket and another thread closes the socket, the blocked thread remains blocked indefinitely. Both kse and thr have this issue. c_r returns with -1 errno==EBADF. Solaris
returns with -1 errno==0.

I originally posted this on the freebsd-threads list. Daniel Eischen replied indicating this is not a thread library issue.

How-To-Repeat: #include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/param.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>

static void *
start_routine(void *arg)
{
  int sock1 = (int)arg;
  struct sockaddr remote_addr;
  char readBuf;
  int n, remote_addr_len = sizeof(struct sockaddr);

  n = recvfrom(sock1, &readBuf, 1, 0, &remote_addr, &remote_addr_len);

  if (n == -1) {
    printf("unblocked with errno = %d\n", errno);
  }

  return (0);
}

void
buildAddr4(struct sockaddr_in *addr4, int address, short port) {
  memset((char *) addr4, 0, sizeof(struct sockaddr_in));
  addr4->sin_port = htons(port);
  addr4->sin_addr.s_addr = (uint32_t) htonl(address);
  addr4->sin_family = AF_INET;
}

int
main() {
  int sock1;
  struct sockaddr addr;
  pthread_t thread1;
  void *value_ptr;

  buildAddr4((struct sockaddr_in *)&addr, 0, 0);

  if ((sock1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    exit(1);
  if (bind(sock1, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
    exit(1);

  pthread_create(&thread1, NULL, start_routine, (void *)sock1);
  sleep(1);

  close(sock1);
  pthread_join(thread1, &value_ptr);

  return (0);
}
Comment 1 Gleb Smirnoff freebsd_committer 2006-06-07 11:40:55 UTC
  I have run this testcase on Linux 2.6.16.19. The program blocks,
but if suspended/resumed it returns. recvfrom() returns -1, errno
is EBADF.

  I think that we should not block (like Solaris), and return EBADF
(like Linux).

-- 
Totus tuus, Glebius.
GLEBIUS-RIPN GLEB-RIPE
Comment 2 Robert Watson freebsd_committer 2006-06-07 15:30:14 UTC
Responsible Changed
From-To: freebsd-bugs->rwatson

Grab ownership of this PR.  This is a somewhat complicated issue 
to address, as socket shutdown occurs only once the last user 
space reference to the socket is released.  This occurs when the 
last outstanding system call after close() takes place.  To 
change this, we will need to change the socket state engine some 
to issue a cancellation on last close rather than last reference, 
which is a notion we sort of (but not entirely) support.  Are 
there any standards that specify this or related behavior that 
we should be aware of?
Comment 3 arnej 2006-12-11 16:09:31 UTC
Actually, a cancellation on last close() could still be wrong (too late), 
there might be other file descriptors referring to the same underlying 
socket.  The issue here is that the file descriptor used in the read() 
requests is invalidated because it's closed (or overwritten with something 
else, with dup2()).  This means the read() must be interrupted somehow; 
then after that the normal reference counting should be used to trigger 
socket shutdown.

I also don't quite understand the comment that this isn't thread related, 
as there's no way for a process to both be in a blocking read() on a 
file descriptor and close() the same file descriptor at the same time 
without using threads.

   -  Arne H. J.
Comment 4 Kurt Miller 2006-12-11 23:08:08 UTC
Daniel Eischen's comment "not a thread library issue" was
to indicate the problem is located in the kernel not the
kse or thr threading libraries.

This issue may also apply to shutdown() in addition to
close() and dup2().
Comment 5 Robert Watson freebsd_committer 2008-01-13 18:19:44 UTC
State Changed
From-To: open->analyzed

We seem to have an understanding of the way it does behave (close() doesn't 
start a disconnect when two threads are using the same fd), so mark 
analyzed. 

Could you confirm that shutdown() really doesn't dislodge the thread in 
read()?
Comment 6 Kurt Miller 2008-01-14 04:18:25 UTC
I just checked on 6.1-release amd64 with both libpthread and libthr and
shutdown() *does* dislodge the thread in read(). Both close() and dup2() 
don't. I don't have a more current system to test on at the moment.
Comment 7 Eitan Adler freebsd_committer freebsd_triage 2018-05-28 19:41:18 UTC
batch change:

For bugs that match the following
-  Status Is In progress 
AND
- Untouched since 2018-01-01.
AND
- Affects Base System OR Documentation

DO:

Reset to open status.


Note:
I did a quick pass but if you are getting this email it might be worthwhile to double check to see if this bug ought to be closed.