[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 メーリングリストの案内