diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2024-02-28 12:31:11 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2024-02-28 22:11:55 -0500 |
commit | f0418655db6a344afd5c26efd04a4e4d87128233 (patch) | |
tree | fb171b019ebc95d3f71466476f4f10703cd582b2 /tests/ioq.c | |
parent | 39ce13d45c5881d84e2de98243052811e3648224 (diff) | |
download | bfs-f0418655db6a344afd5c26efd04a4e4d87128233.tar.xz |
tests/ioq: New unit test
Diffstat (limited to 'tests/ioq.c')
-rw-r--r-- | tests/ioq.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/tests/ioq.c b/tests/ioq.c new file mode 100644 index 0000000..3d35650 --- /dev/null +++ b/tests/ioq.c @@ -0,0 +1,73 @@ +// Copyright © Tavian Barnes <tavianator@tavianator.com> +// SPDX-License-Identifier: 0BSD + +#include "tests.h" +#include "../src/ioq.h" +#include "../src/bfstd.h" +#include "../src/diag.h" +#include "../src/dir.h" +#include <errno.h> +#include <fcntl.h> + +/** + * Test for blocking within ioq_slot_push(). + * + * struct ioqq only supports non-blocking reads; if a write encounters a full + * slot, it must block until someone pops from that slot: + * + * Reader Writer + * ────────────────────────── ───────────────────────── + * tail: 0 → 1 + * slots[0]: empty → full + * tail: 1 → 0 + * slots[1]: empty → full + * tail: 0 → 1 + * slots[0]: full → full* (IOQ_BLOCKED) + * ioq_slot_wait() ... + * head: 0 → 1 + * slots[0]: full* → empty + * ioq_slot_wake() + * ... + * slots[0]: empty → full + * + * To reproduce this unlikely scenario, we must fill up the ready queue, then + * call ioq_cancel() which pushes an additional sentinel IOQ_STOP operation. + */ +static void check_ioq_push_block(void) { + // Must be a power of two to fill the entire queue + const size_t depth = 2; + + struct ioq *ioq = ioq_create(depth, 1); + bfs_verify(ioq, "ioq_create(): %s", xstrerror(errno)); + + // Push enough operations to fill the queue + for (size_t i = 0; i < depth; ++i) { + struct bfs_dir *dir = bfs_allocdir(); + bfs_verify(dir, "bfs_allocdir(): %s", xstrerror(errno)); + + int ret = ioq_opendir(ioq, dir, AT_FDCWD, ".", 0, NULL); + bfs_verify(ret == 0, "ioq_opendir(): %s", xstrerror(errno)); + } + bfs_verify(ioq_capacity(ioq) == 0); + + // Now cancel the queue, pushing an additional IOQ_STOP message + ioq_cancel(ioq); + + // Drain the queue + struct ioq_ent *ent; + while ((ent = ioq_pop(ioq, true))) { + bfs_verify(ent->op == IOQ_OPENDIR); + if (ent->result >= 0) { + bfs_closedir(ent->opendir.dir); + } + free(ent->opendir.dir); + ioq_free(ioq, ent); + } + + ioq_destroy(ioq); +} + +bool check_ioq(void) { + check_ioq_push_block(); + return true; +} |