diff options
45 files changed, 389 insertions, 332 deletions
diff --git a/.editorconfig b/.editorconfig index f907b33..23d17cc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,8 @@ indent_style = tab insert_final_newline = true trim_trailing_whitespace = true +# By well-known name ########################################################### + [*.{c,h}] _mode = c @@ -27,20 +29,6 @@ _mode = cmake [*.md] _mode = markdown -[*.9p{,.wip}] -_mode = 9p - -[{lib9p/tests/test_server/static.h.gen,build-aux/embed-sources.h.gen,build-aux/lint-{generic,unknown},lib9p/tests/test_compile.c.gen}] -_mode = sh - -[{build-aux/lint-h,build-aux/lint-bin,build-aux/get-dscname,build-aux/linux-errno.txt.gen,libusb/include/libusb/tusb_helpers.h.gen,lib9p/tests/runtest}] -_mode = bash - -[{lib9p/proto.gen,lib9p/include/lib9p/linux-errno.h.gen,build-aux/stack.c.gen}] -_mode = python3 -indent_style = space -indent_size = 4 - [*.py] _mode = python3 indent_style = space @@ -49,11 +37,40 @@ indent_size = 4 [requirements.txt] _mode = pip -[**/Documentation/**.txt] -_mode = man-cat - [{.editorconfig,.gitmodules,.pylintrc}] _mode = ini [.gitignore] _mode = gitignore + +# By specific filename (non-lib9p) ############################################# + +[{build-aux/lint-{generic,unknown},build-aux/embed-sources.h.gen}] +_mode = sh + +[{build-aux/lint-{bin,h},build-aux/get-dscname,build-aux/valgrind,libusb/include/libusb/tusb_helpers.h.gen}] +_mode = bash + +[build-aux/stack.c.gen] +_mode = python3 +indent_style = space +indent_size = 4 + +[**/Documentation/**.txt] +_mode = man-cat + +# By specific filename (lib9p) ################################################# + +[lib9p/idl/*.9p{,.wip}] +_mode = 9p-idl + +[{lib9p/tests/test_server/static.h.gen,lib9p/tests/test_compile.c.gen}] +_mode = sh + +[{lib9p/linux-errno.txt.gen,lib9p/tests/runtest}] +_mode = bash + +[{lib9p/proto.gen,lib9p/include/lib9p/linux-errno.h.gen}] +_mode = python3 +indent_style = space +indent_size = 4 diff --git a/3rd-party/linux-errno.txt b/3rd-party/linux-errno.txt index 839efc2..5b450f0 100644 --- a/3rd-party/linux-errno.txt +++ b/3rd-party/linux-errno.txt @@ -1,4 +1,4 @@ -# 3rd-party/linux-errno.txt - Generated from build-aux/linux-errno.txt.gen and linux.git v6.7. DO NOT EDIT! +# 3rd-party/linux-errno.txt - Generated from lib9p/linux-errno.txt.gen and linux.git v6.14. DO NOT EDIT! 1 EPERM Operation not permitted 2 ENOENT No such file or directory 3 ESRCH No such process diff --git a/CMakeLists.txt b/CMakeLists.txt index 22756c1..9fa048f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,7 @@ function(add_lib_test arg_libname arg_testname) target_include_directories("${arg_testname}" PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests) add_test( NAME "${arg_libname}/${arg_testname}" - COMMAND valgrind --error-exitcode=2 "./${arg_testname}" + COMMAND "${CMAKE_SOURCE_DIR}/build-aux/valgrind" "./${arg_testname}" ) endif() endfunction() diff --git a/GNUmakefile b/GNUmakefile index f6ff6c3..4183e37 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -34,7 +34,7 @@ generate/files += 3rd-party/COPYING.newlib.txt cp $< $@ generate/files += 3rd-party/linux-errno.txt -3rd-party/linux-errno.txt: build-aux/linux-errno.txt.gen +3rd-party/linux-errno.txt: lib9p/linux-errno.txt.gen $< $(linux.git) $@ generate/files += lib9p/include/lib9p/linux-errno.h @@ -78,9 +78,6 @@ generate-clean: platforms := rp2040 host # $(shell sed -nE 's/if *\(PICO_PLATFORM STREQUAL "(.*)"\)/\1/p' cmd/*/CMakeLists.txt) build_types = Debug Release RelWithDebInfo MinSizeRel -export CTEST_PARALLEL_LEVEL = 0 -export CTEST_OUTPUT_ON_FAILURE = 1 - build: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) .PHONY: build @@ -91,12 +88,12 @@ $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)): build/% $(MAKE) -C $(<D) .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) -check: build - $(MAKE) -j1 -k INNER=t $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) +check: + $(MAKE) -k INNER=t $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) .PHONY: check -$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/Makefile - $(MAKE) -C $(<D) test +$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/build + +cd $(@D) && ctest --output-on-failure $(if $(filter --jobserver-auth=%,$(MAKEFLAGS)),--parallel) .PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/check)) # `lint` and `format` ########################################################## @@ -109,15 +106,25 @@ build-aux/venv: build-aux/requirements.txt $@/bin/pip install -r $< touch --no-create $@ -# `lint` ########### +# `lint` ############################### +# generic ########## lint: $(MAKE) -k INNER=t $(patsubst sources_%,lint/%,$(filter sources_%,$(.VARIABLES))) # Only lint binaries if the build scripts pass lint. $(MAKE) INNER=t lint/bin lint/bin: build build-aux/lint-bin ./build-aux/lint-bin $(foreach t,$(build_types),build/rp2040-$t/cmd/sbc_harness/sbc_harness.elf) +lint/all: lint/%: build-aux/lint-generic build-aux/get-dscname + ./build-aux/lint-generic '%s\n' $(sources_$*) +lint/unknown: lint/%: build-aux/lint-unknown + ./build-aux/lint-unknown $(sources_$*) +.PHONY: lint lint/% +# specific ######### +lint/c: lint/%: build-aux/lint-h build-aux/get-dscname + ./build-aux/lint-h $(filter %.h,$(sources_$*)) lint/sh lint/bash: lint/%: shellcheck $(sources_$*) + shfmt --diff --case-indent --simplify $(sources_$*) lint/python3: lint/%: build-aux/venv ./build-aux/venv/bin/mypy --strict --scripts-are-modules $(sources_$*) ./build-aux/venv/bin/black --check $(sources_$*) @@ -125,28 +132,21 @@ lint/python3: lint/%: build-aux/venv ./build-aux/venv/bin/pylint $(sources_$*) ! grep -nh 'SPECIAL$$' -- lib9p/proto.gen lib9p/protogen/*.py ./build-aux/venv/bin/pytest $(foreach f,$(sources_python3),$(if $(filter test_%.py,$(notdir $f)),$f)) -lint/c: lint/%: build-aux/lint-h build-aux/get-dscname - ./build-aux/lint-h $(filter %.h,$(sources_$*)) -lint/make lint/cmake lint/gitignore lint/ini lint/9p lint/markdown lint/pip lint/man-cat: lint/%: - @: -lint/unknown: lint/%: build-aux/lint-unknown - ./build-aux/lint-unknown $(sources_$*) -lint/all: lint/%: build-aux/lint-generic build-aux/get-dscname - ./build-aux/lint-generic '%s\n' $(sources_$*) -.PHONY: lint lint/% +lint/make lint/cmake lint/gitignore lint/ini lint/9p-idl lint/markdown lint/pip lint/man-cat: lint/%: + @: TODO: Write/adopt linters for these file types -# `format` ######### +# `format` ############################# +# generic ########## format: - $(MAKE) -k INNER=t $(patsubst sources_%,format/%,$(filter-out sources_all,$(filter sources_%,$(.VARIABLES)))) + $(MAKE) -k INNER=t $(patsubst sources_%,format/%,$(filter-out sources_all sources_unknown,$(filter sources_%,$(.VARIABLES)))) +.PHONY: format format/% +# specific ######### +format/c: format/%: + @: TODO: Adopt a C code-formatter +format/sh format/bash: format/%: + shfmt --write --case-indent --simplify $(sources_$*) format/python3: format/%: ./build-aux/venv ./build-aux/venv/bin/black $(sources_$*) ./build-aux/venv/bin/isort $(sources_$*) -format/sh format/bash: format/% - @: -format/c: format/%: - @: TODO: Adopt a C code-formatter -format/make format/cmake format/gitignore format/ini format/9p format/markdown format/pip format/man-cat: format/%: - @: -format/unknown: format/%: - @: -.PHONY: format format/% +format/make format/cmake format/gitignore format/ini format/9p-idl format/markdown format/pip format/man-cat: format/%: + @: TODO: Write/adopt formatters for these file types @@ -1,10 +1,20 @@ <!-- PLAN.md - Misc planning notes - Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> SPDX-License-Identifier: AGPL-3.0-or-later --> +- [ ] syslog on 9p +- [ ] better 9p-shutdown +- [ ] PIO-based USB +- [ ] wire the USB keyboard to 9P +- [ ] wire uart to 9p + +- SDcard to 9p +- PicoDVI +- solder up the bus switch + - with hardware I have: 1. [X] type "hello world" as a USB keyboard 2. [ ] get networking up (ping) @@ -19,5 +29,3 @@ 1. [ ] PicoDVI hello-world 2. [ ] "PiciDVI" to network 3. [ ] reverse the flow of PicoDVI - -https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/ diff --git a/build-aux/embed-sources.h.gen b/build-aux/embed-sources.h.gen index 0329496..ee9eb42 100755 --- a/build-aux/embed-sources.h.gen +++ b/build-aux/embed-sources.h.gen @@ -6,5 +6,5 @@ nm --format=posix "$@" | sed -n -E \ - -e 's/(.*_(end|start)) [DR] .*/extern char \1[];/p' \ - -e 's/(.*_size) A .*/extern size_t \1;/p' + -e 's/(.*_(end|start)) [DR] .*/extern char \1[];/p' \ + -e 's/(.*_size) A .*/extern size_t \1;/p' diff --git a/build-aux/lint-bin b/build-aux/lint-bin index 78ed19f..91f1612 100755 --- a/build-aux/lint-bin +++ b/build-aux/lint-bin @@ -62,7 +62,7 @@ lint_globals() { cd "$rel_base" total=0 while read -r symbol addr size source; do - if (( addr == 0 )); then + if ((addr == 0)); then continue fi case "$source" in @@ -103,8 +103,9 @@ lint_stack() { fi done < <( comm -3 \ - <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \ - <(readelf_funcs "$in_elffile" | sed -E -e 's/\.part\.[0-9]*$//' -e 's/^__(.*)_veneer$/\1/' | sort -u)) + <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \ + <(readelf_funcs "$in_elffile" | sed -E -e 's/\.part\.[0-9]*$//' -e 's/^__(.*)_veneer$/\1/' | sort -u) + ) } lint_func_blocklist() { @@ -118,8 +119,8 @@ lint_func_blocklist() { while read -r func; do err "$in_elffile" "Contains blocklisted function: ${func}" done < <(readelf --syms --wide -- "$in_elffile" | - awk '$4 == "FUNC" { print $8 }' | - grep -Fx "${blocklist[@]/#/-e}") + awk '$4 == "FUNC" { print $8 }' | + grep -Fx "${blocklist[@]/#/-e}") } main() { @@ -130,8 +131,8 @@ main() { { echo 'Global variables:' lint_globals "${elf}.map" | sed 's/^/ /' - } > "${elf%.elf}.lint.globals" - (lint_stack "$elf") &> "${elf%.elf}.lint.stack" + } >"${elf%.elf}.lint.globals" + (lint_stack "$elf") &>"${elf%.elf}.lint.stack" lint_func_blocklist "$elf" done diff --git a/build-aux/lint-generic b/build-aux/lint-generic index 290988c..70e814a 100755 --- a/build-aux/lint-generic +++ b/build-aux/lint-generic @@ -25,7 +25,7 @@ for filename in "$@"; do if [ -x "$filename" ] && [ -z "$shebang" ]; then err "$filename" 'is executable but does not have a shebang' elif [ -n "$shebang" ] && ! [ -x "$filename" ]; then - err "$filename" 'has a shebang but is executable' + err "$filename" 'has a shebang but is not executable' fi if ! grep -E -q 'Copyright \(C\) 202[4-9]((-|, )202[5-9])* Luke T. Shumaker' "$filename"; then diff --git a/build-aux/lint-h b/build-aux/lint-h index 26ac13d..7459032 100755 --- a/build-aux/lint-h +++ b/build-aux/lint-h @@ -18,9 +18,9 @@ for filename in "$@"; do guard=${dscname//'/'/'_'} guard=${guard//'.'/'_'} guard="_${guard^^}_" - if ! { grep -Fxq "#ifndef ${guard}" "$filename" && - grep -Fxq "#define ${guard}" "$filename" && - grep -Fxq "#endif /* ${guard} */" "$filename"; }; then + if ! { grep -Fxq "#ifndef ${guard}" "$filename" && + grep -Fxq "#define ${guard}" "$filename" && + grep -Fxq "#endif /* ${guard} */" "$filename"; }; then err "$filename" "does not have ${guard} guard" fi done diff --git a/build-aux/valgrind b/build-aux/valgrind new file mode 100755 index 0000000..728faca --- /dev/null +++ b/build-aux/valgrind @@ -0,0 +1,15 @@ +#!/bin/env bash +# build-aux/valgrind - Wrapper around valgrind to keep flags consistent +# +# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-License-Identifier: AGPL-3.0-or-later + +exec \ + valgrind \ + --error-exitcode=2 \ + --leak-check=full \ + --show-leak-kinds=all \ + --errors-for-leak-kinds=all \ + --show-error-list=all \ + -- \ + "$@" diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c index 25b122c..7765ca8 100644 --- a/cmd/sbc_harness/main.c +++ b/cmd/sbc_harness/main.c @@ -234,4 +234,5 @@ int main() { infof("==================================================================="); coroutine_add("init", init_cr, NULL); coroutine_main(); + assert_notreached("all coroutines exited"); } diff --git a/lib9p/include/lib9p/9p.generated.h b/lib9p/include/lib9p/9p.generated.h index 7e901a3..afd89ed 100644 --- a/lib9p/include/lib9p/9p.generated.h +++ b/lib9p/include/lib9p/9p.generated.h @@ -7,7 +7,7 @@ #include <stdint.h> /* for uint{n}_t types */ #include <libfmt/fmt.h> /* for fmt_formatter */ -#include <libhw/generic/net.h> /* for struct iovec */ +#include <libhw/generic/io.h> /* for struct iovec */ /* config *********************************************************************/ diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h index 5919260..42381cf 100644 --- a/lib9p/include/lib9p/9p.h +++ b/lib9p/include/lib9p/9p.h @@ -166,7 +166,7 @@ static inline void lib9p_stat_assert(struct lib9p_stat stat) { * @return whether there was an error */ bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, - uint32_t *ret_net_size, ssize_t *ret_host_size); + uint32_t *ret_net_size, size_t *ret_host_size); /** * Unmarshal the 9P `net_bytes` into the C struct `ret_obj`. diff --git a/lib9p/include/lib9p/linux-errno.h b/lib9p/include/lib9p/linux-errno.h index e7c74f5..e864fb6 100644 --- a/lib9p/include/lib9p/linux-errno.h +++ b/lib9p/include/lib9p/linux-errno.h @@ -1,5 +1,5 @@ /* lib9p/linux-errno.h - Generated by `lib9p/include/lib9p/linux-errno.h.gen 3rd-party/linux-errno.txt`. DO NOT EDIT! */ -/* 3rd-party/linux-errno.txt - Generated from build-aux/linux-errno.txt.gen and linux.git v6.7. DO NOT EDIT! */ +/* 3rd-party/linux-errno.txt - Generated from lib9p/linux-errno.txt.gen and linux.git v6.14. DO NOT EDIT! */ #ifndef _LIB9P_LINUX_ERRNO_H_ #define _LIB9P_LINUX_ERRNO_H_ diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h index ec47142..7ad1b19 100644 --- a/lib9p/include/lib9p/srv.h +++ b/lib9p/include/lib9p/srv.h @@ -33,7 +33,7 @@ struct lib9p_srv_ctx { bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx); -int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx); +void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx); /* interface definitions ******************************************************/ diff --git a/build-aux/linux-errno.txt.gen b/lib9p/linux-errno.txt.gen index f94178f..687e58b 100755 --- a/build-aux/linux-errno.txt.gen +++ b/lib9p/linux-errno.txt.gen @@ -1,7 +1,7 @@ #!/usr/bin/env bash -# build-aux/linux-errno.txt.gen - Generate a listing of Linux kernel errnos +# lib9p/linux-errno.txt.gen - Generate a listing of Linux kernel errnos # -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-License-Identifier: AGPL-3.0-or-later set -e diff --git a/lib9p/protogen/h.py b/lib9p/protogen/h.py index 3b33419..8f7fba2 100644 --- a/lib9p/protogen/h.py +++ b/lib9p/protogen/h.py @@ -166,7 +166,7 @@ def gen_h(versions: set[str], typs: list[idl.UserType]) -> str: #include <stdint.h> /* for uint{{n}}_t types */ #include <libfmt/fmt.h> /* for fmt_formatter */ -#include <libhw/generic/net.h> /* for struct iovec */ +#include <libhw/generic/io.h> /* for struct iovec */ """ id2typ: dict[int, idl.Message] = {} diff --git a/lib9p/srv.c b/lib9p/srv.c index 60a1bb0..b3b9c4c 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -57,12 +57,11 @@ bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) { return _lib9p_srv_flushch_can_send(&ctx->_flushch); } -int lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { +void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { assert(ctx); assert(_lib9p_srv_flushch_can_send(&ctx->_flushch)); lib9p_error(&ctx->basectx, LINUX_ECANCELED, "request canceled by flush"); _lib9p_srv_flushch_send(&ctx->_flushch, true); - return -1; } /* structs ********************************************************************/ diff --git a/lib9p/tables.c b/lib9p/tables.c index 271b17b..86e3298 100644 --- a/lib9p/tables.c +++ b/lib9p/tables.c @@ -96,6 +96,7 @@ void _lib9p_unmarshal(const struct _lib9p_recv_tentry xxx_table[LIB9P_VER_NUM][0 enum lib9p_msg_type typ = net_bytes[4]; *ret_typ = typ; struct _lib9p_recv_tentry tentry = xxx_table[ctx->version][typ/2]; + assert(tentry.unmarshal); tentry.unmarshal(ctx, net_bytes, ret_body); } @@ -124,8 +125,9 @@ bool _lib9p_marshal(const struct _lib9p_send_tentry xxx_table[LIB9P_VER_NUM][0x8 .net_copied_size = 0, .net_copied = ret_copied, }; - struct _lib9p_send_tentry tentry = xxx_table[ctx->version][typ/2]; + assert(tentry.marshal); + bool ret_erred = tentry.marshal(ctx, body, &ret); if (ret_iov[ret.net_iov_cnt-1].iov_len == 0) ret.net_iov_cnt--; @@ -154,12 +156,12 @@ bool lib9p_Rmsg_marshal(struct lib9p_ctx *ctx, enum lib9p_msg_type typ, void *bo /* `struct lib9p_stat` helpers ************************************************/ bool lib9p_stat_validate(struct lib9p_ctx *ctx, uint32_t net_size, uint8_t *net_bytes, - uint32_t *ret_net_size, ssize_t *ret_host_size) { + uint32_t *ret_net_size, size_t *ret_host_size) { ssize_t host_size = _lib9p_stat_validate(ctx, net_size, net_bytes, ret_net_size); if (host_size < 0) return true; if (ret_host_size) - *ret_host_size = host_size; + *ret_host_size = (size_t)host_size; return false; } diff --git a/lib9p/tests/runtest b/lib9p/tests/runtest index 379ea6d..fb66a43 100755 --- a/lib9p/tests/runtest +++ b/lib9p/tests/runtest @@ -7,8 +7,10 @@ set -euE -o pipefail set -x +build_aux=$(realpath --canonicalize-missing -- "${BASH_SOURCE[0]}/../../../build-aux") + port=$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1]); s.close()') -valgrind --error-exitcode=2 ./tests/test_server/test_server "$port" & +"${build_aux}/valgrind" ./tests/test_server/test_server "$port" & server_pid=$! # shellcheck disable=SC2064 trap "kill $server_pid || true; wait $server_pid || true" EXIT @@ -22,7 +24,7 @@ expect_lines() ( diff -u <(printf '%s\n' "$@") <(printf '%s\n' "$out") ) -while [[ -d /proc/$server_pid && "$(readlink /proc/$server_pid/fd/4 2>/dev/null)" != socket:* ]]; do sleep 0.1; done +while [[ -d /proc/$server_pid ]] && ! (readlink /proc/$server_pid/fd/* 2>/dev/null | grep -q ^socket:); do sleep 0.1; done out=$("${client[@]}" ls -l '') expect_lines \ diff --git a/lib9p/tests/test_server/CMakeLists.txt b/lib9p/tests/test_server/CMakeLists.txt index 5313917..19c8edb 100644 --- a/lib9p/tests/test_server/CMakeLists.txt +++ b/lib9p/tests/test_server/CMakeLists.txt @@ -9,6 +9,7 @@ if (PICO_PLATFORM STREQUAL "host") add_library(test_server_objs OBJECT main.c + fs_shutdown.c ) target_include_directories(test_server_objs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) target_include_directories(test_server_objs PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/lib9p/tests/test_server/fs_shutdown.c b/lib9p/tests/test_server/fs_shutdown.c new file mode 100644 index 0000000..3f88985 --- /dev/null +++ b/lib9p/tests/test_server/fs_shutdown.c @@ -0,0 +1,93 @@ +/* lib9p/tests/test_server/fs_shutdown.c - /shutdown API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include "fs_shutdown.h" + +LO_IMPLEMENTATION_C(lib9p_srv_file, struct shutdown_file, shutdown_file, static); + +LO_IMPLEMENTATION_H(lib9p_srv_fio, struct shutdown_file, shutdown_file); +LO_IMPLEMENTATION_C(lib9p_srv_fio, struct shutdown_file, shutdown_file, static); + +/* srv_file *******************************************************************/ + +static void shutdown_file_free(struct shutdown_file *self) { + assert(self); +} +static struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) { + assert(self); + return (struct lib9p_qid){ + .type = LIB9P_QT_FILE, + .vers = 1, + .path = self->pathnum, + }; +} + +static struct lib9p_stat shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + return (struct lib9p_stat){ + .kern_type = 0, + .kern_dev = 0, + .file_qid = shutdown_file_qid(self), + .file_mode = 0222, + .file_atime = UTIL9P_ATIME, + .file_mtime = UTIL9P_MTIME, + .file_size = 0, + .file_name = lib9p_str(self->name), + .file_owner_uid = lib9p_str("root"), + .file_owner_gid = lib9p_str("root"), + .file_last_modified_uid = lib9p_str("root"), + .file_extension = lib9p_str(NULL), + .file_owner_n_uid = 0, + .file_owner_n_gid = 0, + .file_last_modified_n_uid = 0, + }; +} +static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file"); +} +static void shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) { + assert(self); + assert(ctx); + lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file"); +} + +LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_file) + +static lo_interface lib9p_srv_fio shutdown_file_fopen(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { + assert(self); + assert(ctx); + return lo_box_shutdown_file_as_lib9p_srv_fio(self); +} + +/* srv_fio ********************************************************************/ + +static void shutdown_file_iofree(struct shutdown_file *self) { + assert(self); +} + +static uint32_t shutdown_file_iounit(struct shutdown_file *self) { + assert(self); + return 0; +} + +static uint32_t shutdown_file_pwrite(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t LM_UNUSED(offset)) { + assert(self); + assert(ctx); + assert(buf); + if (byte_count == 0) + return 0; + for (size_t i = 0; i < self->nlisteners; i++) + LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&self->listeners[i]), close); + return byte_count; +} +static void shutdown_file_pread(struct shutdown_file *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx), + uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset), + struct iovec *LM_UNUSED(ret)) { + assert_notreached("not readable"); +} diff --git a/lib9p/tests/test_server/fs_shutdown.h b/lib9p/tests/test_server/fs_shutdown.h new file mode 100644 index 0000000..65956db --- /dev/null +++ b/lib9p/tests/test_server/fs_shutdown.h @@ -0,0 +1,23 @@ +/* lib9p/tests/test_server/fs_shutdown.h - /shutdown API endpoint + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ +#define _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ + +#include <util9p/static.h> +#include <libhw/host_net.h> + +struct shutdown_file { + char *name; + uint64_t pathnum; + + struct hostnet_tcp_listener *listeners; + size_t nlisteners; +}; +LO_IMPLEMENTATION_H(lib9p_srv_file, struct shutdown_file, shutdown_file); +#define lo_box_shutdown_file_as_lib9p_srv_file(obj) util9p_box(shutdown_file, obj) + +#endif /* _LIB9P_TESTS_TEST_SERVER_FS_SHUTDOWN_H_ */ diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c index a31c083..8d22a04 100644 --- a/lib9p/tests/test_server/main.c +++ b/lib9p/tests/test_server/main.c @@ -17,6 +17,7 @@ #include <util9p/static.h> #include "static.h" +#include "fs_shutdown.h" /* configuration **************************************************************/ @@ -42,96 +43,6 @@ struct { }, }; -/* api ************************************************************************/ - -struct api_file { - uint64_t pathnum; -}; -LO_IMPLEMENTATION_H(lib9p_srv_file, struct api_file, api); -LO_IMPLEMENTATION_H(lib9p_srv_fio, struct api_file, api); - -LO_IMPLEMENTATION_C(lib9p_srv_file, struct api_file, api, static); -LO_IMPLEMENTATION_C(lib9p_srv_fio, struct api_file, api, static); - -static void api_free(struct api_file *self) { - assert(self); -} -static struct lib9p_qid api_qid(struct api_file *self) { - assert(self); - return (struct lib9p_qid){ - .type = LIB9P_QT_FILE, - .vers = 1, - .path = self->pathnum, - }; -} - -static struct lib9p_stat api_stat(struct api_file *self, struct lib9p_srv_ctx *ctx) { - assert(self); - assert(ctx); - return (struct lib9p_stat){ - .kern_type = 0, - .kern_dev = 0, - .file_qid = api_qid(self), - .file_mode = 0222, - .file_atime = UTIL9P_ATIME, - .file_mtime = UTIL9P_MTIME, - .file_size = 0, - .file_name = lib9p_str("shutdown"), - .file_owner_uid = lib9p_str("root"), - .file_owner_gid = lib9p_str("root"), - .file_last_modified_uid = lib9p_str("root"), - .file_extension = lib9p_str(NULL), - .file_owner_n_uid = 0, - .file_owner_n_gid = 0, - .file_last_modified_n_uid = 0, - }; -} -static void api_wstat(struct api_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_stat) { - assert(self); - assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot wstat API file"); -} -static void api_remove(struct api_file *self, struct lib9p_srv_ctx *ctx) { - assert(self); - assert(ctx); - lib9p_error(&ctx->basectx, LINUX_EROFS, "cannot remove API file"); -} - -LIB9P_SRV_NOTDIR(struct api_file, api) - -static lo_interface lib9p_srv_fio api_fopen(struct api_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) { - assert(self); - assert(ctx); - return lo_box_api_as_lib9p_srv_fio(self); -} - -static void api_iofree(struct api_file *self) { - assert(self); -} - -static uint32_t api_iounit(struct api_file *self) { - assert(self); - return 0; -} - -static uint32_t api_pwrite(struct api_file *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t LM_UNUSED(offset)) { - assert(self); - assert(ctx); - assert(buf); - if (byte_count == 0) - return 0; - for (int i = 0; i < CONFIG_SRV9P_NUM_CONNS; i++) - LO_CALL(lo_box_hostnet_tcplist_as_net_stream_listener(&globals.listeners[i]), close); - return byte_count; -} -static void api_pread(struct api_file *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx), - uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset), - struct iovec *LM_UNUSED(ret)) { - assert_notreached("not readable"); -} - -#define lo_box_api_as_lib9p_srv_file(obj) util9p_box(api, obj) - /* file tree ******************************************************************/ enum { PATH_BASE = __COUNTER__ }; @@ -144,13 +55,22 @@ enum { PATH_BASE = __COUNTER__ }; #define STATIC_DIR(STRNAME, ...) \ UTIL9P_STATIC_DIR(PATH_COUNTER, STRNAME, __VA_ARGS__) +#define API_FILE(STRNAME, SYMNAME, ...) \ + lo_box_##SYMNAME##_file_as_lib9p_srv_file(&((struct SYMNAME##_file){ \ + .name = STRNAME, \ + .pathnum = PATH_COUNTER \ + __VA_OPT__(,) __VA_ARGS__ \ + })) + struct lib9p_srv_file root = STATIC_DIR("", STATIC_DIR("Documentation", STATIC_FILE("x", Documentation_x_txt), ), STATIC_FILE("README.md", README_md), - lo_box_api_as_lib9p_srv_file(&(struct api_file){.pathnum = PATH_COUNTER}), + API_FILE("shutdown", shutdown, + .listeners = globals.listeners, + .nlisteners = LM_ARRAY_LEN(globals.listeners)), ); static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) { diff --git a/libcr/CMakeLists.txt b/libcr/CMakeLists.txt index 80a4ece..2e66020 100644 --- a/libcr/CMakeLists.txt +++ b/libcr/CMakeLists.txt @@ -30,7 +30,7 @@ function(add_libcr_matrix_test n defs) if ("CONFIG_COROUTINE_VALGRIND=1" IN_LIST defs) add_test( NAME "libcr/test_matrix${n}" - COMMAND valgrind --error-exitcode=2 "./test_matrix${n}" + COMMAND "${CMAKE_SOURCE_DIR}/build-aux/valgrind" "./test_matrix${n}" ) else() add_test( diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt index bd72f54..60d3f2d 100644 --- a/libcr_ipc/CMakeLists.txt +++ b/libcr_ipc/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(libcr_ipc INTERFACE) target_include_directories(libcr_ipc PUBLIC INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) target_sources(libcr_ipc INTERFACE - _linkedlist.c chan.c mutex.c rpc.c diff --git a/libcr_ipc/_linkedlist.h b/libcr_ipc/_linkedlist.h deleted file mode 100644 index ab6d89e..0000000 --- a/libcr_ipc/_linkedlist.h +++ /dev/null @@ -1,51 +0,0 @@ -/* libcr_ipc/_linkedlist.h - Common low-level linked lists for use in libcr_ipc - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBCR_IPC__LINKEDLIST_H_ -#define _LIBCR_IPC__LINKEDLIST_H_ - -#include <libmisc/assert.h> - -#include <libcr_ipc/_linkedlist_pub.h> - -/* singly linked list *********************************************************/ - -typedef struct _cr_ipc_sll_node { - struct _cr_ipc_sll_node *rear; -} cr_ipc_sll_node; - -#define cr_ipc_sll_node_cast(node_typ, node_ptr) \ - ({ \ - static_assert(_Generic(node_ptr, cr_ipc_sll_node *: 1, default: 0), \ - "typeof("#node_ptr") != cr_ipc_sll_node *"); \ - assert(node_ptr); \ - static_assert(offsetof(node_typ, cr_ipc_sll_node) == 0); \ - ((node_typ*)(node_ptr)); \ - }) - -void cr_ipc_sll_push_to_rear(_cr_ipc_sll_root *root, cr_ipc_sll_node *node); -void cr_ipc_sll_pop_from_front(_cr_ipc_sll_root *root); - -/* doubly linked list *********************************************************/ - -typedef struct _cr_ipc_dll_node { - struct _cr_ipc_dll_node *front, *rear; -} cr_ipc_dll_node; - -#define cr_ipc_dll_node_cast(node_typ, node_ptr) \ - ({ \ - static_assert(_Generic(node_ptr, cr_ipc_dll_node *: 1, default: 0), \ - "typeof("#node_ptr") != cr_ipc_dll_node *"); \ - assert(node_ptr); \ - static_assert(offsetof(node_typ, cr_ipc_dll_node) == 0); \ - ((node_typ*)(node_ptr)); \ - }) - -void cr_ipc_dll_push_to_rear(_cr_ipc_dll_root *root, cr_ipc_dll_node *node); -void cr_ipc_dll_remove(_cr_ipc_dll_root *root, cr_ipc_dll_node *node); -void cr_ipc_dll_pop_from_front(_cr_ipc_dll_root *root); - -#endif /* _LIBCR_IPC__LINKEDLIST_H_ */ diff --git a/libcr_ipc/chan.c b/libcr_ipc/chan.c index 12d2ec2..6ccfa44 100644 --- a/libcr_ipc/chan.c +++ b/libcr_ipc/chan.c @@ -13,12 +13,10 @@ #include <libcr_ipc/chan.h> -#include "_linkedlist.h" - /* base channels **************************************************************/ struct cr_chan_waiter { - cr_ipc_dll_node; + lm_dll_node; cid_t cid; void *val_ptr; void (*dequeue)(void *, size_t); @@ -28,7 +26,7 @@ struct cr_chan_waiter { void cr_chan_dequeue(void *_ch, size_t) { struct _cr_chan *ch = _ch; - cr_ipc_dll_pop_from_front(&ch->waiters); + lm_dll_pop_from_front(&ch->waiters); } void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size) { @@ -37,7 +35,7 @@ void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void if (ch->waiters.front && ch->waiter_typ != self_typ) { /* non-blocking fast-path */ /* Copy. */ - struct cr_chan_waiter *front = cr_ipc_dll_node_cast(struct cr_chan_waiter, ch->waiters.front); + struct cr_chan_waiter *front = lm_dll_node_cast(struct cr_chan_waiter, ch->waiters.front); if (self_typ == _CR_CHAN_SENDER) memcpy(front->val_ptr, val_ptr, val_size); else @@ -53,7 +51,7 @@ void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void .dequeue = cr_chan_dequeue, .dequeue_arg1 = ch, }; - cr_ipc_dll_push_to_rear(&ch->waiters, &self); + lm_dll_push_to_rear(&ch->waiters, &self); ch->waiter_typ = self_typ; cr_pause_and_yield(); } @@ -95,8 +93,8 @@ static inline enum cr_select_class cr_select_getclass(struct cr_select_arg arg) void cr_select_dequeue(void *_waiters, size_t idx) { struct cr_select_waiters *waiters = _waiters; for (size_t i = 0; i < waiters->cnt; i++) - cr_ipc_dll_remove(&(waiters->args[i].ch->waiters), - &(waiters->nodes[i])); + lm_dll_remove(&(waiters->args[i].ch->waiters), + &(waiters->nodes[i])); waiters->cnt = idx; } @@ -162,7 +160,7 @@ size_t cr_select_v(size_t arg_cnt, struct cr_select_arg arg_vec[]) { .dequeue_arg1 = &waiters, .dequeue_arg2 = i, }; - cr_ipc_dll_push_to_rear(&arg_vec[i].ch->waiters, &waiters.nodes[i]); + lm_dll_push_to_rear(&arg_vec[i].ch->waiters, &waiters.nodes[i]); } cr_pause_and_yield(); return waiters.cnt; diff --git a/libcr_ipc/include/libcr_ipc/_linkedlist_pub.h b/libcr_ipc/include/libcr_ipc/_linkedlist_pub.h deleted file mode 100644 index 6719ba4..0000000 --- a/libcr_ipc/include/libcr_ipc/_linkedlist_pub.h +++ /dev/null @@ -1,26 +0,0 @@ -/* libcr_ipc/_linkedlist_pub.h - Common low-level linked lists for use in libcr_ipc - * - * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -#ifndef _LIBCR_IPC__LINKEDLIST_PUB_H_ -#define _LIBCR_IPC__LINKEDLIST_PUB_H_ - -/* singly linked list *********************************************************/ - -struct _cr_ipc_sll_node; - -typedef struct { - struct _cr_ipc_sll_node *front, *rear; -} _cr_ipc_sll_root; - -/* doubly linked list *********************************************************/ - -struct _cr_ipc_dll_node; - -typedef struct { - struct _cr_ipc_dll_node *front, *rear; -} _cr_ipc_dll_root; - -#endif /* _LIBCR_IPC__LINKEDLIST_PUB_H_ */ diff --git a/libcr_ipc/include/libcr_ipc/chan.h b/libcr_ipc/include/libcr_ipc/chan.h index ad311a0..80acdb8 100644 --- a/libcr_ipc/include/libcr_ipc/chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h @@ -10,9 +10,8 @@ #include <stdbool.h> /* for bool */ #include <stddef.h> /* for size_t */ -#include <libmisc/macro.h> /* LM_CAT2_() */ - -#include <libcr_ipc/_linkedlist_pub.h> +#include <libmisc/linkedlist.h> /* for lm_dll_root */ +#include <libmisc/macro.h> /* for LM_CAT2_() */ /* base channels **************************************************************/ @@ -113,7 +112,7 @@ enum _cr_chan_waiter_typ { struct _cr_chan { enum _cr_chan_waiter_typ waiter_typ; - _cr_ipc_dll_root waiters; + lm_dll_root waiters; }; void _cr_chan_xfer(enum _cr_chan_waiter_typ self_typ, struct _cr_chan *ch, void *val_ptr, size_t val_size); diff --git a/libcr_ipc/include/libcr_ipc/mutex.h b/libcr_ipc/include/libcr_ipc/mutex.h index ec40f5c..0f3c9c2 100644 --- a/libcr_ipc/include/libcr_ipc/mutex.h +++ b/libcr_ipc/include/libcr_ipc/mutex.h @@ -9,10 +9,9 @@ #include <stdbool.h> /* for bool */ +#include <libmisc/linkedlist.h> #include <libmisc/private.h> -#include <libcr_ipc/_linkedlist_pub.h> - /** * A cr_mutex_t is a fair mutex. * @@ -24,7 +23,7 @@ typedef struct { BEGIN_PRIVATE(LIBCR_IPC_MUTEX_H); bool locked; - _cr_ipc_sll_root waiters; + lm_sll_root waiters; END_PRIVATE(LIBCR_IPC_MUTEX_H); } cr_mutex_t; diff --git a/libcr_ipc/include/libcr_ipc/rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 07ace95..f091685 100644 --- a/libcr_ipc/include/libcr_ipc/rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h @@ -9,10 +9,9 @@ #include <stdbool.h> /* for bool */ +#include <libmisc/linkedlist.h> /* for lm_sll_root */ #include <libmisc/macro.h> /* for LM_CAT2_() */ -#include <libcr_ipc/_linkedlist_pub.h> - /** * CR_RPC_DECLARE(NAME, REQ_T, RESP_T) declares the following types * and methods: @@ -146,7 +145,7 @@ enum _cr_rpc_waiter_typ { struct _cr_rpc { enum _cr_rpc_waiter_typ waiter_typ; - _cr_ipc_sll_root waiters; + lm_sll_root waiters; }; void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void *resp_ptr); diff --git a/libcr_ipc/include/libcr_ipc/rwmutex.h b/libcr_ipc/include/libcr_ipc/rwmutex.h index 924acce..d48abe9 100644 --- a/libcr_ipc/include/libcr_ipc/rwmutex.h +++ b/libcr_ipc/include/libcr_ipc/rwmutex.h @@ -9,10 +9,9 @@ #include <stdbool.h> +#include <libmisc/linkedlist.h> #include <libmisc/private.h> -#include <libcr_ipc/_linkedlist_pub.h> - /** * A cr_rwmutex_t is a fair read/write mutex. * @@ -29,7 +28,7 @@ typedef struct { unsigned nreaders; bool locked; bool unpausing; - _cr_ipc_sll_root waiters; + lm_sll_root waiters; END_PRIVATE(LIBCR_IPC_RWMUTEX_H); } cr_rwmutex_t; diff --git a/libcr_ipc/include/libcr_ipc/sema.h b/libcr_ipc/include/libcr_ipc/sema.h index ae8d93d..cc387f4 100644 --- a/libcr_ipc/include/libcr_ipc/sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h @@ -9,10 +9,9 @@ #include <stdbool.h> +#include <libmisc/linkedlist.h> #include <libmisc/private.h> -#include <libcr_ipc/_linkedlist_pub.h> - /** * A cr_sema_t is a fair unbounded[1] counting semaphore. * @@ -22,7 +21,7 @@ typedef struct { BEGIN_PRIVATE(LIBCR_IPC_SEMA_H); unsigned int cnt; bool unpausing; - _cr_ipc_sll_root waiters; + lm_sll_root waiters; END_PRIVATE(LIBCR_IPC_SEMA_H); } cr_sema_t; diff --git a/libcr_ipc/mutex.c b/libcr_ipc/mutex.c index 28debba..b0ebe05 100644 --- a/libcr_ipc/mutex.c +++ b/libcr_ipc/mutex.c @@ -9,10 +9,8 @@ #define IMPLEMENTATION_FOR_LIBCR_IPC_MUTEX_H YES #include <libcr_ipc/mutex.h> -#include "_linkedlist.h" - struct cr_mutex_waiter { - cr_ipc_sll_node; + lm_sll_node; cid_t cid; }; @@ -26,7 +24,7 @@ void cr_mutex_lock(cr_mutex_t *mu) { struct cr_mutex_waiter self = { .cid = cr_getcid(), }; - cr_ipc_sll_push_to_rear(&mu->waiters, &self); + lm_sll_push_to_rear(&mu->waiters, &self); cr_pause_and_yield(); } assert(mu->locked); @@ -38,8 +36,8 @@ void cr_mutex_unlock(cr_mutex_t *mu) { assert(mu->locked); if (mu->waiters.front) { - cr_unpause(cr_ipc_sll_node_cast(struct cr_mutex_waiter, mu->waiters.front)->cid); - cr_ipc_sll_pop_from_front(&mu->waiters); + cr_unpause(lm_sll_node_cast(struct cr_mutex_waiter, mu->waiters.front)->cid); + lm_sll_pop_from_front(&mu->waiters); } else mu->locked = false; } diff --git a/libcr_ipc/rpc.c b/libcr_ipc/rpc.c index a648fde..6d9422f 100644 --- a/libcr_ipc/rpc.c +++ b/libcr_ipc/rpc.c @@ -10,17 +10,15 @@ #include <libcr_ipc/rpc.h> -#include "_linkedlist.h" - struct cr_rpc_requester { - cr_ipc_sll_node; + lm_sll_node; cid_t cid; void *req_ptr; /* where to read req from */ void *resp_ptr; /* where to write resp to */ }; struct cr_rpc_responder { - cr_ipc_sll_node; + lm_sll_node; /* before enqueued | after dequeued */ /* -------------------+-------------------- */ cid_t cid; /* responder cid | requester cid */ @@ -34,8 +32,8 @@ void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * if (ch->waiters.front && ch->waiter_typ != _CR_RPC_REQUESTER) { /* fast-path (still blocks) */ struct cr_rpc_responder *responder = - cr_ipc_sll_node_cast(struct cr_rpc_responder, ch->waiters.front); - cr_ipc_sll_pop_from_front(&ch->waiters); + lm_sll_node_cast(struct cr_rpc_responder, ch->waiters.front); + lm_sll_pop_from_front(&ch->waiters); /* Copy the req to the responder's stack. */ memcpy(responder->ptr, req_ptr, req_size); /* Notify the responder that we have done so. */ @@ -50,7 +48,7 @@ void _cr_rpc_send_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * .req_ptr = req_ptr, .resp_ptr = resp_ptr, }; - cr_ipc_sll_push_to_rear(&ch->waiters, &self); + lm_sll_push_to_rear(&ch->waiters, &self); /* Wait for a responder to both copy our req and sed * `*resp_ptr`. */ cr_pause_and_yield(); @@ -65,8 +63,8 @@ void _cr_rpc_recv_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * if (ch->waiters.front && ch->waiter_typ != _CR_RPC_RESPONDER) { /* non-blocking fast-path */ struct cr_rpc_requester *requester = - cr_ipc_sll_node_cast(struct cr_rpc_requester, ch->waiters.front); - cr_ipc_sll_pop_from_front(&ch->waiters); + lm_sll_node_cast(struct cr_rpc_requester, ch->waiters.front); + lm_sll_pop_from_front(&ch->waiters); memcpy(req_ptr, requester->req_ptr, req_size); *ret_requester = requester->cid; @@ -76,7 +74,7 @@ void _cr_rpc_recv_req(struct _cr_rpc *ch, void *req_ptr, size_t req_size, void * .cid = cr_getcid(), .ptr = req_ptr, }; - cr_ipc_sll_push_to_rear(&ch->waiters, &self); + lm_sll_push_to_rear(&ch->waiters, &self); ch->waiter_typ = _CR_RPC_RESPONDER; cr_pause_and_yield(); *ret_requester = self.cid; diff --git a/libcr_ipc/rwmutex.c b/libcr_ipc/rwmutex.c index 04016d6..4c5da81 100644 --- a/libcr_ipc/rwmutex.c +++ b/libcr_ipc/rwmutex.c @@ -9,10 +9,8 @@ #define IMPLEMENTATION_FOR_LIBCR_IPC_RWMUTEX_H YES #include <libcr_ipc/rwmutex.h> -#include "_linkedlist.h" - struct cr_rwmutex_waiter { - cr_ipc_sll_node; + lm_sll_node; bool is_reader; cid_t cid; }; @@ -25,13 +23,13 @@ void cr_rwmutex_lock(cr_rwmutex_t *mu) { .is_reader = false, .cid = cr_getcid(), }; - cr_ipc_sll_push_to_rear(&mu->waiters, &self); - if (mu->waiters.front != &self.cr_ipc_sll_node || mu->locked) + lm_sll_push_to_rear(&mu->waiters, &self); + if (mu->waiters.front != &self.lm_sll_node || mu->locked) cr_pause_and_yield(); - assert(mu->waiters.front == &self.cr_ipc_sll_node); + assert(mu->waiters.front == &self.lm_sll_node); /* We now hold the lock (and are mu->waiters.front). */ - cr_ipc_sll_pop_from_front(&mu->waiters); + lm_sll_pop_from_front(&mu->waiters); assert(mu->nreaders == 0); mu->locked = true; mu->unpausing = false; @@ -45,18 +43,17 @@ void cr_rwmutex_rlock(cr_rwmutex_t *mu) { .is_reader = true, .cid = cr_getcid(), }; - cr_ipc_sll_push_to_rear(&mu->waiters, &self); - if (mu->waiters.front != &self.cr_ipc_sll_node || (mu->locked && mu->nreaders == 0)) + lm_sll_push_to_rear(&mu->waiters, &self); + if (mu->waiters.front != &self.lm_sll_node || (mu->locked && mu->nreaders == 0)) cr_pause_and_yield(); - assert(mu->waiters.front == &self.cr_ipc_sll_node); + assert(mu->waiters.front == &self.lm_sll_node); /* We now hold the lock (and are mu->waiters.front). */ - cr_ipc_sll_pop_from_front(&mu->waiters); + lm_sll_pop_from_front(&mu->waiters); mu->nreaders++; mu->locked = true; - struct cr_rwmutex_waiter *waiter = mu->waiters.front - ? cr_ipc_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front) - : NULL; + struct cr_rwmutex_waiter *waiter = + lm_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); if (waiter && waiter->is_reader) { assert(mu->unpausing); cr_unpause(waiter->cid); @@ -74,7 +71,7 @@ void cr_rwmutex_unlock(cr_rwmutex_t *mu) { assert(!mu->unpausing); if (mu->waiters.front) { struct cr_rwmutex_waiter *waiter = - cr_ipc_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); + lm_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); mu->unpausing = true; cr_unpause(waiter->cid); } else { @@ -92,7 +89,7 @@ void cr_rwmutex_runlock(cr_rwmutex_t *mu) { if (mu->nreaders == 0 && !mu->unpausing) { if (mu->waiters.front) { struct cr_rwmutex_waiter *waiter = - cr_ipc_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); + lm_sll_node_cast(struct cr_rwmutex_waiter, mu->waiters.front); assert(!waiter->is_reader); mu->unpausing = true; cr_unpause(waiter->cid); diff --git a/libcr_ipc/sema.c b/libcr_ipc/sema.c index 85add6c..cb984b6 100644 --- a/libcr_ipc/sema.c +++ b/libcr_ipc/sema.c @@ -9,10 +9,8 @@ #define IMPLEMENTATION_FOR_LIBCR_IPC_SEMA_H YES #include <libcr_ipc/sema.h> -#include "_linkedlist.h" - struct cr_sema_waiter { - cr_ipc_sll_node; + lm_sll_node; cid_t cid; }; @@ -24,7 +22,7 @@ void cr_sema_signal(cr_sema_t *sema) { sema->cnt++; if (sema->waiters.front && !sema->unpausing) { cr_unpause( - cr_ipc_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); + lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); sema->unpausing = true; } cr_restore_interrupts(saved); @@ -37,7 +35,7 @@ void cr_sema_signal_from_intrhandler(cr_sema_t *sema) { sema->cnt++; if (sema->waiters.front && !sema->unpausing) { cr_unpause_from_intrhandler( - cr_ipc_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); + lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); sema->unpausing = true; } } @@ -51,15 +49,15 @@ void cr_sema_wait(cr_sema_t *sema) { struct cr_sema_waiter self = { .cid = cr_getcid(), }; - cr_ipc_sll_push_to_rear(&sema->waiters, &self); - if (sema->waiters.front != &self.cr_ipc_sll_node || !sema->cnt) + lm_sll_push_to_rear(&sema->waiters, &self); + if (sema->waiters.front != &self.lm_sll_node || !sema->cnt) cr_pause_and_yield(); - assert(sema->waiters.front == &self.cr_ipc_sll_node && sema->cnt); - cr_ipc_sll_pop_from_front(&sema->waiters); + assert(sema->waiters.front == &self.lm_sll_node && sema->cnt); + lm_sll_pop_from_front(&sema->waiters); sema->cnt--; if (sema->cnt && sema->waiters.front) cr_unpause( - cr_ipc_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); + lm_sll_node_cast(struct cr_sema_waiter, sema->waiters.front)->cid); else sema->unpausing = false; cr_restore_interrupts(saved); diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt index 4599ead..c80e060 100644 --- a/libmisc/CMakeLists.txt +++ b/libmisc/CMakeLists.txt @@ -8,6 +8,7 @@ target_include_directories(libmisc PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/ target_sources(libmisc INTERFACE assert.c intercept.c + linkedlist.c log.c ) target_compile_options(libmisc INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>") diff --git a/libmisc/include/libmisc/linkedlist.h b/libmisc/include/libmisc/linkedlist.h new file mode 100644 index 0000000..8adef66 --- /dev/null +++ b/libmisc/include/libmisc/linkedlist.h @@ -0,0 +1,46 @@ +/* libmisc/linkedlist.h - Singly- and doubly- linked lists + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC_LINKEDLIST_H_ +#define _LIBMISC_LINKEDLIST_H_ + +#include <libmisc/assert.h> +#include <libmisc/macro.h> + +/* singly linked list *********************************************************/ + +typedef struct _lm_sll_node { + struct _lm_sll_node *rear; +} lm_sll_node; + +typedef struct { + lm_sll_node *front, *rear; +} lm_sll_root; + +#define lm_sll_node_cast(node_typ, node_ptr) \ + LM_CAST_FIELD_TO_STRUCT(node_typ, lm_sll_node, node_ptr) + +void lm_sll_push_to_rear(lm_sll_root *root, lm_sll_node *node); +void lm_sll_pop_from_front(lm_sll_root *root); + +/* doubly linked list *********************************************************/ + +typedef struct _lm_dll_node { + struct _lm_dll_node *front, *rear; +} lm_dll_node; + +typedef struct { + lm_dll_node *front, *rear; +} lm_dll_root; + +#define lm_dll_node_cast(node_typ, node_ptr) \ + LM_CAST_FIELD_TO_STRUCT(node_typ, lm_dll_node, node_ptr) + +void lm_dll_push_to_rear(lm_dll_root *root, lm_dll_node *node); +void lm_dll_remove(lm_dll_root *root, lm_dll_node *node); +void lm_dll_pop_from_front(lm_dll_root *root); + +#endif /* _LIBMISC_LINKEDLIST_H_ */ diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index b3e235c..6cb15fb 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -14,9 +14,20 @@ #define LM_NEVER_INLINE [[gnu::noinline]] #define LM_FLATTEN [[gnu::flatten]] -/* numeric */ +/* types */ #define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0])) + +#define LM_CAST_FIELD_TO_STRUCT(STRUCT_TYP, FIELD_NAME, PTR_TO_FIELD) ({ \ + /* The _fptr assignment is to get the compiler to do type checking. */ \ + typeof(((STRUCT_TYP *)NULL)->FIELD_NAME) *_fptr = (PTR_TO_FIELD); \ + _fptr \ + ? ((STRUCT_TYP*)( ((void*)_fptr) - offsetof(STRUCT_TYP, FIELD_NAME))) \ + : NULL; \ +}) + +/* numeric */ + #define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */ #define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */ #define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */ diff --git a/libcr_ipc/_linkedlist.c b/libmisc/linkedlist.c index b27dba8..5fe0977 100644 --- a/libcr_ipc/_linkedlist.c +++ b/libmisc/linkedlist.c @@ -1,4 +1,4 @@ -/* libcr_ipc/_linkedlist.c - Common low-level linked lists for use in libcr_ipc +/* libmisc/linkedlist.c - Singly- and doubly- linked lists * * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later @@ -6,11 +6,11 @@ #include <stddef.h> /* for NULL */ -#include "_linkedlist.h" +#include <libmisc/linkedlist.h> /* singly linked list *********************************************************/ -void cr_ipc_sll_push_to_rear(_cr_ipc_sll_root *root, cr_ipc_sll_node *node) { +void lm_sll_push_to_rear(lm_sll_root *root, lm_sll_node *node) { assert(root); node->rear = NULL; if (root->rear) @@ -20,7 +20,7 @@ void cr_ipc_sll_push_to_rear(_cr_ipc_sll_root *root, cr_ipc_sll_node *node) { root->rear = node; } -void cr_ipc_sll_pop_from_front(_cr_ipc_sll_root *root) { +void lm_sll_pop_from_front(lm_sll_root *root) { assert(root); assert(root->front); root->front = root->front->rear; @@ -30,7 +30,7 @@ void cr_ipc_sll_pop_from_front(_cr_ipc_sll_root *root) { /* doubly linked list *********************************************************/ -void cr_ipc_dll_push_to_rear(_cr_ipc_dll_root *root, cr_ipc_dll_node *node) { +void lm_dll_push_to_rear(lm_dll_root *root, lm_dll_node *node) { assert(root); assert(node); node->front = root->rear; @@ -42,7 +42,7 @@ void cr_ipc_dll_push_to_rear(_cr_ipc_dll_root *root, cr_ipc_dll_node *node) { root->rear = node; } -void cr_ipc_dll_remove(_cr_ipc_dll_root *root, cr_ipc_dll_node *node) { +void lm_dll_remove(lm_dll_root *root, lm_dll_node *node) { assert(root); assert(node); if (node->front) @@ -55,8 +55,8 @@ void cr_ipc_dll_remove(_cr_ipc_dll_root *root, cr_ipc_dll_node *node) { root->rear = node->front; } -void cr_ipc_dll_pop_from_front(_cr_ipc_dll_root *root) { +void lm_dll_pop_from_front(lm_dll_root *root) { assert(root); assert(root->front); - cr_ipc_dll_remove(root, root->front); + lm_dll_remove(root, root->front); } diff --git a/libusb/include/libusb/tusb_helpers.h b/libusb/include/libusb/tusb_helpers.h index 1b4e48e..0c35f62 100644 --- a/libusb/include/libusb/tusb_helpers.h +++ b/libusb/include/libusb/tusb_helpers.h @@ -1,7 +1,7 @@ /* Generated by `libusb/include/libusb/tusb_helpers.h.gen `. DO NOT EDIT! */ /* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * * SPDX-License-Identifier: MIT * diff --git a/libusb/include/libusb/tusb_helpers.h.gen b/libusb/include/libusb/tusb_helpers.h.gen index 5a5d1ac..1de1d09 100755 --- a/libusb/include/libusb/tusb_helpers.h.gen +++ b/libusb/include/libusb/tusb_helpers.h.gen @@ -7,7 +7,7 @@ echo "/* Generated by \`$0 $*\`. DO NOT EDIT! */" cat <<'EOT' /* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * * SPDX-License-Identifier: MIT * @@ -70,12 +70,19 @@ fi if [[ ! -f 3rd-party/MS-LCID.txt || 3rd-party/MS-LCID.txt -ot 3rd-party/MS-LCID.pdf ]]; then pdftotext -layout 3rd-party/MS-LCID.pdf fi -<3rd-party/MS-LCID.txt \ - grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved | # find the lines we're interested in - sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' | # format them as 'PRIhex SUBhex UPPER_STR' - sort | - sed -E 's/(..) (..) (.*)/#define LANGID_\3 0x\2\1/' | # format them as '#define LANGID_UPPER_STR 0xSUBPRI' - column --table --output-separator=' ' +{ + { + # find the lines we're interested in + grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved + } | { + # format them as 'PRIhex SUBhex UPPER_STR' + sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' + } | sort | { + # format them as '#define LANGID_UPPER_STR 0xSUBPRI' + sed -E 's/(..) (..) (.*)/#define LANGID_\3 0x\2\1/' | + column --table --output-separator=' ' + } +} <3rd-party/MS-LCID.txt cat <<'EOT' /** USB 2.0 ยง9.6.6 "Endpoint", field bEndpointAddress, bit 7 */ @@ -187,3 +187,7 @@ OpenBMC - Sipeed NanoKVM - https://github.com/stefanklug/picoKVM (~$20 Arduino, ~$5 HDMI capture), non-IP + +---- + +https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/ |