cs: avoid problem waking up on TCP connect completion

Maybe there's a problem in `rktio_poll_add_connect` that I just can't
see, or maybe it's a Mac OS bug, but `rktio_poll_add_connect` doesn't
seem to reliably wake up the process when the TCP connection becomes
ready. Traditional Racket happens to avoid the problem by registering
the connection file descriptor with the semaphore table; doing that
for Racket CS also avoids the problem there.
This commit is contained in:
Matthew Flatt 2019-12-17 07:06:49 -07:00
parent 61000a454e
commit 899aa24756
4 changed files with 38 additions and 17 deletions

View File

@ -416,7 +416,6 @@
(test (void) (file-position out 10))
(test #"hola!!\0\0\0\0" (get-output-bytes out)))
(log-error "start")
(let ()
(define-values (i o) (make-pipe))
(port-count-lines! i)
@ -444,7 +443,6 @@
(write-bytes #"!" o)
(test '(3 1 8) (next-location o))
(log-error "here")
(test #"x\r" (read-bytes 2 i))
(test '(3 0 7) (next-location i))
(test #"\n!" (read-bytes 2 i))

View File

@ -14,13 +14,6 @@
[((rktio-evt-poll self))
(values (list self) #f)]
[else
(define sched-info (poll-ctx-sched-info poll-ctx))
(when sched-info
;; Cooperate with the sandman by registering a function that
;; takes a poll set and adds to it:
(schedule-info-current-exts sched-info
(sandman-add-poll-set-adder
(schedule-info-current-exts sched-info)
(rktio-evt-add-to-poll-set self))))
(sandman-poll-ctx-add-poll-set-adder! poll-ctx (rktio-evt-add-to-poll-set self))
(values #f self)])))
#:authentic)

View File

@ -6,6 +6,7 @@
"../host/error.rkt"
"../security/main.rkt"
"../format/main.rkt"
"../sandman/ltps.rkt"
"tcp-port.rkt"
"port-number.rkt"
"address.rkt"
@ -15,6 +16,10 @@
(provide tcp-connect
tcp-connect/enable-break)
(struct connect-progress (conn trying-fd)
#:mutable
#:authentic)
(define/who (tcp-connect hostname port-no [local-hostname #f] [local-port-no #f])
(do-tcp-connect who hostname port-no local-hostname local-port-no))
@ -66,15 +71,17 @@
(raise-connect-error local-addr "local host not found" local-hostname local-port-no)]
[else
(call-with-resource
(box (rktio_start_connect rktio remote-addr local-addr))
(connect-progress (rktio_start_connect rktio remote-addr local-addr)
#f)
;; in atomic mode
(lambda (conn-box)
(define conn (unbox conn-box))
(lambda (conn-prog)
(remove-trying-fd! conn-prog)
(define conn (connect-progress-conn conn-prog))
(when conn
(rktio_connect_stop rktio conn)))
;; in atomic mode
(lambda (conn-box)
(define conn (unbox conn-box))
(lambda (conn-prog)
(define conn (connect-progress-conn conn-prog))
(cond
[(rktio-error? conn)
(raise-connect-error conn)]
@ -83,6 +90,7 @@
(cond
[(eqv? (rktio_poll_connect_ready rktio conn)
RKTIO_POLL_NOT_READY)
(init-trying-fd! conn-prog)
(end-atomic)
((if enable-break? sync/enable-break sync)
(rktio-evt (lambda ()
@ -93,6 +101,7 @@
(start-atomic)
(loop)]
[else
(remove-trying-fd! conn-prog)
(check-current-custodian who)
(define fd (rktio_connect_finish rktio conn))
(cond
@ -102,8 +111,25 @@
(loop)]
[else
;; other errors imply that `conn` is destroyed
(set-box! conn-box #f)
(set-connect-progress-conn! conn-prog #f)
(raise-connect-error fd)])]
[else
(define name (string->immutable-string hostname))
(open-input-output-tcp fd name)])]))])))])))])))))
;; in atomic mode
(define (init-trying-fd! conn-prog)
(unless (connect-progress-trying-fd conn-prog)
;; Even though we don't use the semaphore for the registered file
;; descriptor, registering it seems to avoid a problem where
;; `rktio_poll_add_connect` doesn't work, at least on Mac OS.
(define fd (rktio_connect_trying rktio (connect-progress-conn conn-prog)))
(set-connect-progress-trying-fd! conn-prog fd)
(void (fd-semaphore-update! fd 'write))))
;; in atomic mode
(define (remove-trying-fd! conn-prog)
(define fd (connect-progress-trying-fd conn-prog))
(when fd
(fd-semaphore-update! fd 'remove)
(set-connect-progress-trying-fd! conn-prog #f)))

View File

@ -893,8 +893,12 @@ static int tcp_check_connect(Connect_Progress_Data *pd, Scheme_Schedule_Info *si
if (rktio_poll_connect_ready(scheme_rktio, pd->connect))
return 1;
if (pd->trying_s)
if (pd->trying_s) {
/* Even though we don't currently use the semaphore for blocking,
registering with the semaphore table seems to avoid a problem
with `rktio_poll_add_connect` not working, at least on Mac OS. */
check_fd_sema(pd->trying_s, MZFD_CREATE_WRITE, sinfo, NULL);
}
return 0;
}