From 3853f1d89ffadb477e3a19c74943ec2d263060c8 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 7 Aug 2023 12:11:54 -0700 Subject: streams: close-stream only caches non-nil result. This is motivated by trying to implement a struct delegate stream which performs reference counting in close, in order to close the real stream when the count hits zero. The caching behavior of close-stream is a problem. * stream.c (strm_base_init): Initialize close_result to nil, rather than nao. (strm_base_mark): Don't check close_result for nao. (close_stream): Suppress the call to op->close if close_result has a non-nil value, rather than a value other than nao. * tests/018/close-delegate.tl, * tests/018/close-delegate.expected: New files. * txr.1: Document that only a non-nil return is cached by close-stream. --- stream.c | 6 +++--- tests/018/close-delegate.expected | 3 +++ tests/018/close-delegate.tl | 20 ++++++++++++++++++++ txr.1 | 2 ++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 tests/018/close-delegate.expected create mode 100644 tests/018/close-delegate.tl diff --git a/stream.c b/stream.c index c088fe58..f25de90c 100644 --- a/stream.c +++ b/stream.c @@ -119,7 +119,7 @@ static val shell, shell_arg; void strm_base_init(struct strm_base *s) { - static struct strm_base init = { indent_off, 60, 10, 0, 0, 0, 0, 0, nao, 0 }; + static struct strm_base init = { indent_off, 60, 10, 0, 0, 0, 0, 0, nil, 0 }; *s = init; } @@ -130,7 +130,7 @@ void strm_base_cleanup(struct strm_base *s) void strm_base_mark(struct strm_base *s) { - if (s->close_result != nao) + if (s->close_result) gc_mark(s->close_result); } @@ -2989,7 +2989,7 @@ val close_stream(val stream, val throw_on_error) cobj_handle(self, stream, stream_cls)); struct strm_ops *ops = coerce(struct strm_ops *, stream->co.ops); - if (s->close_result == nao) + if (!s->close_result) s->close_result = ops->close(stream, throw_on_error); return s->close_result; diff --git a/tests/018/close-delegate.expected b/tests/018/close-delegate.expected new file mode 100644 index 00000000..227f9f67 --- /dev/null +++ b/tests/018/close-delegate.expected @@ -0,0 +1,3 @@ +close called, count 2 +close called, count 1 +20 diff --git a/tests/018/close-delegate.tl b/tests/018/close-delegate.tl new file mode 100644 index 00000000..4cf1d650 --- /dev/null +++ b/tests/018/close-delegate.tl @@ -0,0 +1,20 @@ +(load "../common") + +(defstruct refcount-close stream-wrap + stream + (count 1) + + (:method close (me throw-on-error-p) + (put-line `close called, count @{me.count}`) + (when (plusp me.count) + (if (zerop (dec me.count)) + (close-stream me.stream throw-on-error-p))))) + +(flow + (with-stream (s (make-struct-delegate-stream + (new refcount-close + count 2 + stream (open-file *load-path*)))) + (get-lines s)) + len + prinl) diff --git a/txr.1 b/txr.1 index dfe64a08..fb409b16 100644 --- a/txr.1 +++ b/txr.1 @@ -62097,6 +62097,8 @@ instead of returning If .code close-stream is called in such a way that it returns a value, without throwing an exception, +and that value isn't +.codn nil , that value is retained. Additional calls to the function with the same .meta stream object return that same value without having any effect on the stream. -- cgit v1.2.3