diff --git a/pkgs/racket-test-core/tests/racket/file.rktl b/pkgs/racket-test-core/tests/racket/file.rktl index 0af4e74d6b..e113d4e1c8 100644 --- a/pkgs/racket-test-core/tests/racket/file.rktl +++ b/pkgs/racket-test-core/tests/racket/file.rktl @@ -1221,10 +1221,11 @@ (thread (lambda () (sync (system-idle-evt)) (if (or force-close? - ;; For Windows, we need a close that doesn't try + ;; For really old Windows, we need a close that doesn't try ;; to flush, because there's no way to avoid ;; buffering at the rktio level: - (eq? 'windows (system-type))) + (and (eq? 'windows (system-type)) + (not (regexp-match? "Windows NT" (system-type 'machine))))) (custodian-shutdown-all c) (close-output-port o)))) diff --git a/racket/src/io/port/fd-port.rkt b/racket/src/io/port/fd-port.rkt index c9d47d6841..fddd5171fb 100644 --- a/racket/src/io/port/fd-port.rkt +++ b/racket/src/io/port/fd-port.rkt @@ -213,11 +213,25 @@ #:break newline? (void)))] + ;; in atomic mode, but may leave it temporarily + [flush-rktio-buffer-fully + (lambda () + (unless (rktio-flushed?) + (end-atomic) + (sync (rktio-fd-flushed-evt this)) + (start-atomic) + (flush-rktio-buffer-fully)))] + #:static [flush-buffer/external (lambda () (flush-buffer-fully #f))] + [rktio-flushed? + (lambda () + (or (not bstr) + (rktio_poll_write_flushed rktio fd)))] + #:override ;; in atomic mode [write-out @@ -258,6 +272,7 @@ [close (lambda () (flush-buffer-fully #f) ; can temporarily leave atomic mode + (flush-rktio-buffer-fully) ; can temporarily leave atomic mode (when bstr ; <- in case a concurrent close succeeded (send fd-output-port this on-close) (when flush-handle @@ -457,6 +472,29 @@ (rktio_poll_add rktio (fd-evt-fd fde) ps mode))) (values #f fde)])])))) +;; ---------------------------------------- +;; Wait on rktio-level flushing. At the time of writing, this is +;; needed only for Windows so old that Racket CS doesn't run on it, +;; but here just in case rktio or something else changes. + +(struct rktio-fd-flushed-evt (p) + #:property + prop:evt + (poller + (lambda (ffe ctx) + (define p (rktio-fd-flushed-evt-p ffe)) + (cond + [(send fd-output-port p rktio-flushed?) + (values '(#t) #f)] + [else + (sandman-poll-ctx-add-poll-set-adder! + ctx + (lambda (ps) + (if (send fd-output-port p rktio-flushed?) + (rktio_poll_set_add_nosleep rktio ps) + (rktio_poll_add rktio (fd-output-port-fd p) ps RKTIO_POLL_FLUSH)))) + (values #f (list ffe))])))) + ;; ---------------------------------------- (define (register-fd-close custodian fd fd-refcount flush-handle port) diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index 22b4c5b696..61074fff91 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -278,9 +278,9 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, const char *buffer, intptr_ mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an error. Although `rktio_write` is intended to write only bytes that can be fully delivered to the OS, there may be OS limitations that - require buffering (e.g., on Windows). Use `rktio_poll_write_flushed` - to make sure the data is received by the destination before closing - `fd`. */ + require buffering (e.g., on ancient versions of Windows). Use + `rktio_poll_write_flushed` to make sure the data is received by the + destination before closing `fd`. */ #define RKTIO_WRITE_ERROR (-2) diff --git a/racket/src/rktio/rktio_fd.c b/racket/src/rktio/rktio_fd.c index 18d4061008..44c6a45b8f 100644 --- a/racket/src/rktio/rktio_fd.c +++ b/racket/src/rktio/rktio_fd.c @@ -732,6 +732,12 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush int retval; Win_FD_Output_Thread *oth = rfd->oth; + if (check_flushed && rfd->oth->nonblocking) { + /* Not Windows 95, so any written data really is in the pipe, as + good as flushed, and we don't really need to ask the thread. */ + return RKTIO_POLL_READY; + } + WaitForSingleObject(oth->lock_sema, INFINITE); if (oth->nonblocking) { if (oth->needflush) {