diff --git a/ext/socket/socket-selector.incl b/ext/socket/socket-selector.incl index fb098bfdc..cd44bedd9 100644 --- a/ext/socket/socket-selector.incl +++ b/ext/socket/socket-selector.incl @@ -204,12 +204,11 @@ static SgObject earliest_timeout(SgObject sockets, SgTime *start, static struct timespec * update_timeout(SgObject sockets, SgTime *start, - struct timespec *global, struct timespec *out, SgObject *timedout) { SgObject to = earliest_timeout(sockets, start, timedout); - struct timespec *r = global; + struct timespec *r = NULL; if (!SG_FALSEP(to)) { long sec = SG_TIME(to)->sec - start->sec; @@ -218,15 +217,7 @@ static struct timespec * update_timeout(SgObject sockets, if (sec > 0 || (sec == 0 && nsec > 0)) { out->tv_sec = (sec > 0) ? sec : 0; out->tv_nsec = (nsec > 0) ? nsec : 0; - - if (global) { - if (global->tv_sec > out->tv_sec || - (global->tv_sec = out->tv_sec && global->tv_nsec > out->tv_nsec)) { - r = out; - } - } else { - r = out; - } + r = out; } } return r; @@ -238,7 +229,7 @@ SgObject Sg_SocketSelectorWait(SgSocketSelector *selector, SgObject timeout) SgTime start; int n; unsigned long sec, usec; - struct timespec spec, *sp, sock_to; + struct timespec spec, *sp, sock_to, *sto; if (Sg_SocketSelectorClosedP(selector)) { Sg_Error(UC("Socket selector is closed: %A"), selector); @@ -256,7 +247,12 @@ SgObject Sg_SocketSelectorWait(SgSocketSelector *selector, SgObject timeout) start.nsec = usec * 1000; Sg_LockMutex(&selector->lock); - sp = update_timeout(selector->sockets, &start, sp, &sock_to, &timedout); + /* compute socket timeout */ + sto = update_timeout(selector->sockets, &start, &sock_to, &timedout); + /* replace if exists */ + if (sto) { + sp = sto; + } strip_sockets(selector, timedout); n = selector_sockets(selector); @@ -293,7 +289,10 @@ SgObject Sg_SocketSelectorWait(SgSocketSelector *selector, SgObject timeout) start.sec = sec; start.nsec = nsec; } - sp = update_timeout(selector->sockets, &start, sp, &sock_to, &timedout); + sto = update_timeout(selector->sockets, &start, &sock_to, &timedout); + if (sto) { + sp = sto; + } strip_sockets(selector, timedout); n = selector_sockets(selector); diff --git a/src/os/win/win_util.c b/src/os/win/win_util.c index 13fa9de51..4425fa391 100644 --- a/src/os/win/win_util.c +++ b/src/os/win/win_util.c @@ -117,14 +117,17 @@ static SgString* utf16ToUtf32WithRegion(wchar_t *s, wchar_t *e) static SgObject get_last_error(DWORD e) { #define MSG_SIZE 128 - wchar_t msg[MSG_SIZE]; - int size = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + wchar_t msg[MSG_SIZE] = {0,}; + int size = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, 0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - msg, MSG_SIZE, + 0, NULL); + if (size == 0) return SG_STRING("*no error message available*"); + if (size > 2 && msg[size - 2] == '\r') { msg[size - 2] = 0; size -= 2; diff --git a/test/tests/net/socket.scm b/test/tests/net/socket.scm index 654a4884e..73f08e29c 100644 --- a/test/tests/net/socket.scm +++ b/test/tests/net/socket.scm @@ -6,6 +6,7 @@ (srfi :18) (srfi :19) (srfi :64) + (sagittarius atomic) (sagittarius threads) (util concurrent) (rename (sagittarius crypto keys) @@ -202,6 +203,7 @@ (let () (define count 100) (define (run-socket-selector hard-timeout soft-timeout) + (define ready-sockets (make-atomic-fixnum 0)) (define server-sock (make-server-socket "0")) (define mark #vu8(0)) (define (echo sock e reuse-invoker) @@ -225,6 +227,7 @@ (let loop () (let ((sock (socket-accept server-sock))) (when sock + (atomic-fixnum-inc! ready-sockets) (socket-selector sock echo soft-timeout) (loop)))) (terminater))))))) @@ -241,7 +244,6 @@ (msg (string->utf8 (string-append "Hello world " (number->string i))))) (guard (e (else #;(print e) s)) - (thread-sleep! 0.1) (socket-send s msg) (let ((v (socket-recv s 255))) (cond ((bytevector=? v mark) (shared-queue-put! result #f)) @@ -258,18 +260,24 @@ (define (safe-close s) (cond ((socket? s) (socket-close s)) ((condition? s) (report-error s)))) - - (for-each safe-close (map safe-join! (map caller (iota count)))) + + (let ((t* (map caller (iota count)))) + (do () ((= count (atomic-fixnum-load ready-sockets)))) + (for-each safe-close (map safe-join! t*))) (socket-shutdown server-sock SHUT_RDWR) (socket-close server-sock) (guard (e (else #t)) (thread-join! server-thread)) + (shared-queue->list result)) - (test-equal count (length (filter string? (run-socket-selector 1000 #f)))) - (test-assert (not (= count (length - (filter string? (run-socket-selector 10 #f)))))) - (test-equal count (length (filter string? (run-socket-selector 10 1000)))) + (let ((r (run-socket-selector 1000 #f))) + (test-equal "no soft, hard = 1000ms" count (length (filter string? r)))) + (let ((r (run-socket-selector 10 #f))) + (test-assert "no soft, hard = 10ms" + (not (= count (length (filter string? r)))))) + (let ((r (run-socket-selector 10 1000))) + (test-equal "soft = 1000ms, hard = 10ms" count (length (filter string? r)))) ) (let () @@ -313,18 +321,20 @@ (string-append "Hello world " (number->string i)))) (selector s push-result soft-timeout))) (define (collect-thread) - (do ((i 0 (+ i 1)) (r '() (cons (shared-queue-get! result) r))) + ;; should wait 1s but if we do, it'd be max 100s per test + ;; in theory, 300ms should be enough per socket + (do ((i 0 (+ i 1)) (r '() (cons (shared-queue-get! result 0.5 #f) r))) ((= i count) r))) (let-values (((selector terminator) (make-socket-selector hard-timeout))) (for-each (caller selector) (iota count)) - (let ((r (map thread-join! (collect-thread)))) + (let ((r (map (lambda (t?) (and t? (thread-join! t?))) (collect-thread)))) (terminator) r))) (test-equal "hard 1000ms soft #f" count (length (filter string? (run-socket-selector 1000 #f)))) - (test-equal "hard 0ms soft #f" + (test-equal "hard 100ms soft #f" 0 (length (filter string? (run-socket-selector 100 #f)))) (test-equal "hard 10ms soft 1000ms" count (length (filter string? (run-socket-selector 10 1000))))