diff --git a/collects/mzlib/port.rkt b/collects/mzlib/port.rkt index e373aafe76..98dbebb03b 100644 --- a/collects/mzlib/port.rkt +++ b/collects/mzlib/port.rkt @@ -1032,13 +1032,15 @@ (-read-bytes!-evt bstr input-port peek-offset prog-evt)) (define (-read-bytes-evt len input-port peek-offset prog-evt) - (let ([bstr (make-bytes len)]) - (wrap-evt - (-read-bytes!-evt bstr input-port peek-offset prog-evt) - (lambda (v) - (if (number? v) - (if (= v len) bstr (subbytes bstr 0 v)) - v))))) + (guard-evt + (lambda () + (let ([bstr (make-bytes len)]) + (wrap-evt + (-read-bytes!-evt bstr input-port peek-offset prog-evt) + (lambda (v) + (if (number? v) + (if (= v len) bstr (subbytes bstr 0 v)) + v))))))) (define (read-bytes-evt len input-port) (-read-bytes-evt len input-port #f #f)) @@ -1049,44 +1051,46 @@ (define (-read-string-evt goal input-port peek-offset prog-evt) (if (zero? goal) (wrap-evt always-evt (lambda (x) "")) - (let ([bstr (make-bytes goal)] - [c (bytes-open-converter "UTF-8-permissive" "UTF-8")]) - (wrap-evt - (read-at-least-bytes!-evt - bstr input-port - (lambda (bstr v) - (if (= v (bytes-length bstr)) - ;; We can't easily use bytes-utf-8-length here, - ;; because we may need more bytes to figure out - ;; the true role of the last byte. The - ;; `bytes-convert' function lets us deal with - ;; the last byte properly. - (let-values ([(bstr2 used status) - (bytes-convert c bstr 0 v)]) - (let ([got (bytes-utf-8-length bstr2)]) - (if (= got goal) - ;; Done: - #f - ;; Need more bytes: - (let ([bstr2 (make-bytes (+ v (- goal got)))]) - (bytes-copy! bstr2 0 bstr) - bstr2)))) - ;; Need more bytes in bstr: - bstr)) - (lambda (bstr v) - ;; We may need one less than v, - ;; because we may have had to peek - ;; an extra byte to discover an - ;; error in the stream. - (if ((bytes-utf-8-length bstr #\? 0 v) . > . goal) (sub1 v) v)) - cons - peek-offset prog-evt) - (lambda (bstr+v) - (let ([bstr (car bstr+v)] - [v (cdr bstr+v)]) - (if (number? v) - (bytes->string/utf-8 bstr #\? 0 v) - v))))))) + (guard-evt + (lambda () + (let ([bstr (make-bytes goal)] + [c (bytes-open-converter "UTF-8-permissive" "UTF-8")]) + (wrap-evt + (read-at-least-bytes!-evt + bstr input-port + (lambda (bstr v) + (if (= v (bytes-length bstr)) + ;; We can't easily use bytes-utf-8-length here, + ;; because we may need more bytes to figure out + ;; the true role of the last byte. The + ;; `bytes-convert' function lets us deal with + ;; the last byte properly. + (let-values ([(bstr2 used status) + (bytes-convert c bstr 0 v)]) + (let ([got (bytes-utf-8-length bstr2)]) + (if (= got goal) + ;; Done: + #f + ;; Need more bytes: + (let ([bstr2 (make-bytes (+ v (- goal got)))]) + (bytes-copy! bstr2 0 bstr) + bstr2)))) + ;; Need more bytes in bstr: + bstr)) + (lambda (bstr v) + ;; We may need one less than v, + ;; because we may have had to peek + ;; an extra byte to discover an + ;; error in the stream. + (if ((bytes-utf-8-length bstr #\? 0 v) . > . goal) (sub1 v) v)) + cons + peek-offset prog-evt) + (lambda (bstr+v) + (let ([bstr (car bstr+v)] + [v (cdr bstr+v)]) + (if (number? v) + (bytes->string/utf-8 bstr #\? 0 v) + v))))))))) (define (read-string-evt goal input-port) (-read-string-evt goal input-port #f #f)) diff --git a/collects/tests/racket/portlib.rktl b/collects/tests/racket/portlib.rktl index 3694437cc8..8a35eba5e7 100644 --- a/collects/tests/racket/portlib.rktl +++ b/collects/tests/racket/portlib.rktl @@ -893,6 +893,59 @@ (flush-output out) (test "hello world" read in)) +;; -------------------------------------------------- +;; check that string and byte-string evts can be reused + +(let () + (define (check-can-reuse read-bytes-evt read-bytes write-bytes integer->byte list->bytes bytes?) + (define N 10) + (define M 160) + (define PORT 5999) + + (define (make-alarm-e) + (alarm-evt (+ (current-inexact-milliseconds) 5))) + + (define ((connection-handler in out with-alarm?)) + (let loop ((alarm-e (make-alarm-e)) + (read-e (read-bytes-evt 16 in))) + (sync (if with-alarm? + (wrap-evt alarm-e (lambda (_) (loop (make-alarm-e) read-e))) + never-evt) + (wrap-evt read-e + (lambda (bs) + (when (bytes? bs) + (sleep 0.01) + (write-bytes bs out) + (flush-output out)) + (loop alarm-e read-e))) + (wrap-evt (eof-evt in) + (lambda (_) + (close-input-port in) + (close-output-port out)))))) + + (define listener (tcp-listen PORT 4 #t)) + (define server + (thread + (lambda () + (for ([i N]) + (define-values (in out) (tcp-accept listener)) + ((connection-handler in out #t)))))) + + (let ([s (list->bytes + (for/list ([i M]) + (integer->byte (random 512))))]) + (for ([i N]) + (define-values (i o) (tcp-connect "localhost" PORT)) + (write-bytes s o) + (close-output-port o) + (test s read-bytes M i))) + + (sync server) + (tcp-close listener)) + + (let ([integer->byte (lambda (s) (bitwise-and s #xFF))]) + (check-can-reuse read-bytes-evt read-bytes write-bytes integer->byte list->bytes bytes?)) + (check-can-reuse read-string-evt read-string write-string integer->char list->string string?)) ;; --------------------------------------------------