aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJack Mordaunt <jackmordaunt.dev@gmail.com>2025-06-12 15:41:48 -0300
committerJack Mordaunt <jackmordaunt.dev@gmail.com>2025-06-12 17:35:49 -0300
commit760d8c1cdd870aa3f48aceb6c6a9de0e9b57b001 (patch)
treeb9385021863860e00dbb29ea8bf3e9ac4c4b2aa6 /tests
parent2d12e265ccb51ce6385f56a53e2ea261eb92ac82 (diff)
core/sync/chan.send: return false if channel is closed while blocked
This commit makes send behave the same as recv: that the call will return false if the channel is closed while a thread is waiting on the blocking operation. Prior logic would have send return true even if the channel was actually closed rather than read from. Docs adjusted to make this clear. Tests added to lock in this behaviour.
Diffstat (limited to 'tests')
-rw-r--r--tests/core/sync/chan/test_core_sync_chan.odin44
1 files changed, 44 insertions, 0 deletions
diff --git a/tests/core/sync/chan/test_core_sync_chan.odin b/tests/core/sync/chan/test_core_sync_chan.odin
index ae7456d99..8267d6bef 100644
--- a/tests/core/sync/chan/test_core_sync_chan.odin
+++ b/tests/core/sync/chan/test_core_sync_chan.odin
@@ -228,6 +228,50 @@ test_full_buffered_closed_chan_deadlock :: proc(t: ^testing.T) {
testing.expect(t, !chan.send(ch, 32))
}
+// Ensures that if a thread is doing a blocking send and the channel
+// is closed, it will report false to indicate a failure to complete.
+@test
+test_fail_blocking_send_on_close :: proc(t: ^testing.T) {
+ ch, ch_alloc_err := chan.create(chan.Chan(int), context.allocator)
+ assert(ch_alloc_err == nil, "allocation failed")
+ defer chan.destroy(ch)
+
+ sender := thread.create_and_start_with_poly_data(ch, proc(ch: chan.Chan(int)) {
+ assert(!chan.send(ch, 42))
+ })
+
+ for !chan.can_recv(ch) {
+ thread.yield()
+ }
+
+ testing.expect(t, chan.close(ch))
+ thread.join(sender)
+ thread.destroy(sender)
+}
+
+// Ensures that if a thread is doing a blocking read and the channel
+// is closed, it will report false to indicate a failure to complete.
+@test
+test_fail_blocking_recv_on_close :: proc(t: ^testing.T) {
+ ch, ch_alloc_err := chan.create(chan.Chan(int), context.allocator)
+ assert(ch_alloc_err == nil, "allocation failed")
+ defer chan.destroy(ch)
+
+ reader := thread.create_and_start_with_poly_data(ch, proc(ch: chan.Chan(int)) {
+ v, ok := chan.recv(ch)
+ assert(!ok)
+ assert(v == 0)
+ })
+
+ for !chan.can_send(ch) {
+ thread.yield()
+ }
+
+ testing.expect(t, chan.close(ch))
+ thread.join(reader)
+ thread.destroy(reader)
+}
+
// Ensures that try_send for unbuffered channels works as expected.
// If 1 reader of a channel, and 3 try_senders, only one of the senders
// will succeed and none of them will block.