[mew-dist 25586] Re: non-blocking connect()

Kazu Yamamoto ( 山本和彦 ) kazu at example.com
2004年 10月 26日 (火) 18:38:11 JST


>   1) connectがエラーを返さなかった場合に備えて
> 
>    if (! (ret < 0)) {
>      break;
>    } else if (errno != EINPROGRESS) {
>      goto next;
>    }

そうですね。

>   2) forでまわさずに timeoutを tv_sec=2

そうかもしれない。でも immediate_quit との関係がよく分っていません。

>   3) selectは wsetだけ
> 
>  という感じじゃないでしょうか。3)は BSD以外のシステムで読み出し
>  のみが可能になるものがあるかもしれないので、自信はありません。

UNIX Network Programming Vol 1 3rd には両方で待てと書いてあります。

--かず

Index: process.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/process.c,v
retrieving revision 1.442
diff -c -r1.442 process.c
*** process.c	29 Sep 2004 23:43:08 -0000	1.442
--- process.c	26 Oct 2004 09:40:16 -0000
***************
*** 2727,2732 ****
--- 2727,2735 ----
    int is_server = 0, backlog = 5;
    int socktype;
    int family = -1;
+   int flags, len;
+   fd_set rset, wset;
+   struct timeval timeout;
  
    if (nargs == 0)
      return Qnil;
***************
*** 3095,3155 ****
  	  break;
  	}
  
!     retry_connect:
! 
!       immediate_quit = 1;
!       QUIT;
! 
!       /* This turns off all alarm-based interrupts; the
! 	 bind_polling_period call above doesn't always turn all the
! 	 short-interval ones off, especially if interrupt_input is
! 	 set.
! 
! 	 It'd be nice to be able to control the connect timeout
! 	 though.  Would non-blocking connect calls be portable?
! 
! 	 This used to be conditioned by HAVE_GETADDRINFO.  Why?  */
! 
!       turn_on_atimers (0);
  
        ret = connect (s, lres->ai_addr, lres->ai_addrlen);
!       xerrno = errno;
  
!       turn_on_atimers (1);
  
!       if (ret == 0 || xerrno == EISCONN)
! 	{
! 	  /* The unwind-protect will be discarded afterwards.
! 	     Likewise for immediate_quit.  */
! 	  break;
! 	}
  
! #ifdef NON_BLOCKING_CONNECT
! #ifdef EINPROGRESS
!       if (is_non_blocking_client && xerrno == EINPROGRESS)
! 	break;
! #else
! #ifdef EWOULDBLOCK
!       if (is_non_blocking_client && xerrno == EWOULDBLOCK)
! 	break;
! #endif
! #endif
! #endif
  
        immediate_quit = 0;
  
-       if (xerrno == EINTR)
- 	goto retry_connect;
-       if (xerrno == EADDRINUSE && retry < 20)
- 	{
- 	  /* A delay here is needed on some FreeBSD systems,
- 	     and it is harmless, since this retrying takes time anyway
- 	     and should be infrequent.  */
- 	  Fsleep_for (make_number (1), Qnil);
- 	  retry++;
- 	  goto retry_connect;
- 	}
- 
        /* Discard the unwind protect closing S.  */
        specpdl_ptr = specpdl + count1;
        emacs_close (s);
--- 3098,3143 ----
  	  break;
  	}
  
!       flags = fcntl(s, F_GETFL, 0);
!       ret = fcntl(s, F_SETFL, flags | O_NONBLOCK);
!       if (ret < 0) goto next;
  
        ret = connect (s, lres->ai_addr, lres->ai_addrlen);
!       if (ret == 0) {
! 	      if (fcntl(s, F_SETFL, flags) < 0)
! 		      goto next;
! 	      break;
!       }
!       if ((ret < 0) && (errno != EINPROGRESS)) goto next;
  
!       FD_ZERO(&rset);
!       FD_SET(s,&rset);
!       wset = rset;
!       timeout.tv_sec=2;
!       timeout.tv_usec=0;
  
!       immediate_quit = 1;
!       QUIT;
!       select(s+1, &rset, &wset, NULL, &timeout);
!       immediate_quit = 0;
  
!       if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) {
! 	      len = sizeof(xerrno);
! 	      if (getsockopt(s, SOL_SOCKET, SO_ERROR, &xerrno, &len) < 0)
! 		      goto next;
! 	      if (xerrno != 0) {
! 		      errno = xerrno;
! 		      goto next;
! 	      }
! 	      if (fcntl(s, F_SETFL, flags) < 0)
! 		      goto next;
! 	      break;
!       }
  
+     next:
+       xerrno = errno;
        immediate_quit = 0;
  
        /* Discard the unwind protect closing S.  */
        specpdl_ptr = specpdl + count1;
        emacs_close (s);



Mew-dist メーリングリストの案内