Make liburing optional; rewrite CMakeLists.txt and enable LTO

This commit is contained in:
Luke Street 2025-10-07 14:12:07 -06:00
parent df36de18bf
commit 061228c971
37 changed files with 601 additions and 1100 deletions

View File

@ -46,7 +46,7 @@ jobs:
run: >-
docker build
-f ${{ matrix.dockerfile }}
--build-arg build_type=${{ matrix.build_type }}
--build-arg BUILD_TYPE=${{ matrix.build_type }}
--target build
-t ${{ matrix.image }}
.
@ -59,7 +59,7 @@ jobs:
rm -rf dist
docker build \
-f ${{ matrix.dockerfile }} \
--build-arg build_type=${{ matrix.build_type }} \
--build-arg BUILD_TYPE=${{ matrix.build_type }} \
--target export \
--output dist \
.

View File

@ -6,7 +6,7 @@
- Sample fixtures for exercising the loader live in `test/`.
## Build, Test, and Development Commands
- `cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTING=ON` configures a 32-bit toolchain; ensure multilib packages are present.
- `cmake -B build -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` configures a 32-bit toolchain; ensure multilib packages are present.
- `cmake --build build --target wibo` compiles the program and tests.
- `./build/wibo /path/to/program.exe` runs a Windows binary. Use `WIBO_DEBUG=1` (or `--debug`/`-D`) for verbose logging. Use `--chdir`/`-C` to set the working directory.
- `cmake -B build -DBUILD_TESTING=ON` + `ctest --test-dir build --output-on-failure` runs the self-checking WinAPI fixtures (requires `i686-w64-mingw32-gcc` and `i686-w64-mingw32-windres`).
@ -25,7 +25,7 @@
- Add `DEBUG_LOG` calls to trace execution and parameter values; these are invaluable when diagnosing issues with real-world binaries.
## Testing Guidelines
- Fixture tests live in `test/` and are compiled automatically with `i686-w64-mingw32-gcc` when `BUILD_TESTING` is enabled.
- Fixture tests live in `test/` and are compiled automatically with `i686-w64-mingw32-gcc`.
- Keep new repros small and self-contained (`test_<feature>.c`).
- All fixtures must self-assert; use `test_assert.h` helpers so `ctest` fails on mismatched WinAPI behaviour.
- Update `CMakeLists.txt` to add new fixture sources.

View File

@ -1,10 +1,5 @@
cmake_minimum_required(VERSION 3.13)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
"Build type options: Debug Release RelWithDebInfo MinSizeRel" FORCE)
endif()
set(CMAKE_C_FLAGS_INIT "-m32")
set(CMAKE_CXX_FLAGS_INIT "-m32")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-m32")
@ -12,15 +7,35 @@ set(CMAKE_SHARED_LINKER_FLAGS_INIT "-m32")
project(wibo LANGUAGES C CXX)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
option(WIBO_ENABLE_FIXTURE_TESTS "Enable Win32 fixture tests (requires i686-w64-mingw32)" ON)
option(WIBO_ENABLE_LIBURING "Enable liburing for asynchronous I/O" OFF)
set(WIBO_ENABLE_LTO "AUTO" CACHE STRING "Enable link-time optimization (LTO)")
set_property(CACHE WIBO_ENABLE_LTO PROPERTY STRINGS "AUTO" "ON" "OFF")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-pie -no-pie -D_LARGEFILE64_SOURCE")
if (WIBO_ENABLE_LTO STREQUAL "AUTO")
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
include(CheckIPOSupported)
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
if (ipo_supported)
message(STATUS "Enabling LTO")
set(WIBO_ENABLE_LTO ON)
else()
message(STATUS "LTO not supported: ${ipo_error}")
set(WIBO_ENABLE_LTO OFF)
endif()
else()
message(STATUS "Disabling LTO")
set(WIBO_ENABLE_LTO OFF)
endif()
elseif (NOT (WIBO_ENABLE_LTO STREQUAL "ON" OR WIBO_ENABLE_LTO STREQUAL "OFF"))
message(FATAL_ERROR "WIBO_ENABLE_LTO must be ON, OFF, or AUTO")
endif()
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${WIBO_ENABLE_LTO})
find_package(Filesystem REQUIRED)
# Disable mimalloc tests
# Fetch and configure mimalloc
set(MI_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE)
set(MI_BUILD_STATIC OFF CACHE BOOL "Build static library" FORCE)
set(MI_BUILD_OBJECT ON CACHE BOOL "Build object library" FORCE)
set(MI_BUILD_TESTS OFF CACHE BOOL "Build test executables" FORCE)
include(FetchContent)
@ -31,35 +46,43 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(mimalloc)
FetchContent_Declare(
liburing
GIT_REPOSITORY https://github.com/axboe/liburing.git
GIT_TAG liburing-2.4
)
FetchContent_MakeAvailable(liburing)
# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1`
target_compile_options(mimalloc-obj PRIVATE -Wno-psabi)
set(LIBURING_COMPAT ${liburing_SOURCE_DIR}/src/include/liburing/compat.h)
add_custom_command(
OUTPUT ${LIBURING_COMPAT}
COMMAND ${CMAKE_COMMAND} -E env
CC=${CMAKE_C_COMPILER}
AR=${CMAKE_AR}
RANLIB=${CMAKE_RANLIB}
./configure --cc=${CMAKE_C_COMPILER}
WORKING_DIRECTORY ${liburing_SOURCE_DIR}
COMMENT "Running liburing configure"
VERBATIM
)
add_custom_target(liburing_configure DEPENDS ${LIBURING_COMPAT})
add_library(liburing STATIC
${liburing_SOURCE_DIR}/src/queue.c
${liburing_SOURCE_DIR}/src/register.c
${liburing_SOURCE_DIR}/src/setup.c
${liburing_SOURCE_DIR}/src/syscall.c
${liburing_SOURCE_DIR}/src/version.c)
add_dependencies(liburing liburing_configure)
target_include_directories(liburing PUBLIC ${liburing_SOURCE_DIR}/src/include)
target_compile_definitions(liburing PRIVATE _GNU_SOURCE)
if (WIBO_ENABLE_LIBURING)
FetchContent_Declare(
liburing
GIT_REPOSITORY https://github.com/axboe/liburing.git
GIT_TAG e907d6a342e80b70874f93abd440b92b8a40b7bc # liburing-2.12
)
FetchContent_MakeAvailable(liburing)
add_custom_command(
OUTPUT ${liburing_SOURCE_DIR}/config-host.h
${liburing_SOURCE_DIR}/src/include/liburing/compat.h
COMMAND ${CMAKE_COMMAND} -E env
CC=${CMAKE_C_COMPILER}
CXX=${CMAKE_CXX_COMPILER}
./configure --prefix=${liburing_BINARY_DIR}
WORKING_DIRECTORY ${liburing_SOURCE_DIR}
DEPENDS ${liburing_SOURCE_DIR}/configure
COMMENT "Running liburing configure"
VERBATIM
)
add_library(liburing STATIC
${liburing_SOURCE_DIR}/config-host.h
${liburing_SOURCE_DIR}/src/nolibc.c
${liburing_SOURCE_DIR}/src/queue.c
${liburing_SOURCE_DIR}/src/register.c
${liburing_SOURCE_DIR}/src/setup.c
${liburing_SOURCE_DIR}/src/syscall.c
${liburing_SOURCE_DIR}/src/version.c
${liburing_SOURCE_DIR}/src/include/liburing/compat.h)
target_compile_definitions(liburing PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64)
target_compile_options(liburing PRIVATE -include config-host.h)
target_include_directories(liburing PUBLIC ${liburing_SOURCE_DIR}/src/include)
target_include_directories(liburing PRIVATE ${liburing_SOURCE_DIR})
endif()
add_executable(wibo
dll/advapi32.cpp
@ -116,14 +139,24 @@ add_executable(wibo
src/resources.cpp
src/strutil.cpp
)
target_include_directories(wibo PRIVATE dll src)
target_compile_definitions(wibo PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64)
target_compile_features(wibo PRIVATE cxx_std_20)
target_link_libraries(wibo PRIVATE std::filesystem mimalloc-static liburing)
target_compile_options(wibo PRIVATE -Wall -Wextra -fno-pie -maccumulate-outgoing-args)
target_include_directories(wibo PRIVATE dll src)
target_link_libraries(wibo PRIVATE mimalloc-obj)
target_link_options(wibo PRIVATE -no-pie)
if (WIBO_ENABLE_LIBURING)
target_compile_definitions(wibo PRIVATE WIBO_ENABLE_LIBURING=1)
target_link_libraries(wibo PRIVATE liburing)
target_sources(wibo PRIVATE src/async_io_uring.cpp)
else()
target_compile_definitions(wibo PRIVATE WIBO_ENABLE_LIBURING=0)
endif()
install(TARGETS wibo DESTINATION bin)
include(CTest)
if (WIBO_ENABLE_FIXTURE_TESTS)
include(CTest)
if(BUILD_TESTING)
find_program(WIBO_MINGW_CC i686-w64-mingw32-gcc)
find_program(WIBO_MINGW_WINDRES i686-w64-mingw32-windres)
@ -132,443 +165,105 @@ if(BUILD_TESTING)
set(WIBO_HAVE_MINGW_TOOLCHAIN TRUE)
endif()
option(WIBO_ENABLE_FIXTURE_TESTS "Build and run Windows fixture binaries through wibo" ${WIBO_HAVE_MINGW_TOOLCHAIN})
if(NOT WIBO_HAVE_MINGW_TOOLCHAIN)
message(WARNING "MinGW toolchain not found; skipping fixture tests")
else()
set(WIBO_TEST_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/test)
file(MAKE_DIRECTORY ${WIBO_TEST_BIN_DIR})
if(WIBO_ENABLE_FIXTURE_TESTS)
if(NOT WIBO_HAVE_MINGW_TOOLCHAIN)
message(WARNING "MinGW toolchain not found; skipping fixture tests")
function(wibo_add_fixture_dll)
set(options)
set(oneValueArgs NAME)
set(multiValueArgs SOURCES COMPILE_OPTIONS DEPENDS)
cmake_parse_arguments(PARSE_ARGV 0 fixture "${options}" "${oneValueArgs}" "${multiValueArgs}")
set(fixture_OUTPUT ${WIBO_TEST_BIN_DIR}/${fixture_NAME}.dll)
add_custom_command(
OUTPUT ${fixture_OUTPUT}
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o ${fixture_OUTPUT}
${fixture_SOURCES}
${fixture_COMPILE_OPTIONS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${fixture_SOURCES} ${fixture_DEPENDS})
list(APPEND WIBO_TEST_FIXTURES ${fixture_OUTPUT})
set(WIBO_TEST_FIXTURES ${WIBO_TEST_FIXTURES} PARENT_SCOPE)
endfunction(wibo_add_fixture_dll)
function(wibo_add_fixture_bin)
set(options)
set(oneValueArgs NAME)
set(multiValueArgs SOURCES COMPILE_OPTIONS DEPENDS)
cmake_parse_arguments(PARSE_ARGV 0 fixture "${options}" "${oneValueArgs}" "${multiValueArgs}")
set(fixture_OUTPUT ${WIBO_TEST_BIN_DIR}/${fixture_NAME}.exe)
add_custom_command(
OUTPUT ${fixture_OUTPUT}
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o ${fixture_OUTPUT}
${fixture_SOURCES}
${fixture_COMPILE_OPTIONS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${fixture_SOURCES} ${fixture_DEPENDS})
list(APPEND WIBO_TEST_FIXTURES ${fixture_OUTPUT})
set(WIBO_TEST_FIXTURES ${WIBO_TEST_FIXTURES} PARENT_SCOPE)
add_test(NAME wibo.${fixture_NAME}
COMMAND $<TARGET_FILE:wibo> ${fixture_OUTPUT})
set_tests_properties(wibo.${fixture_NAME} PROPERTIES
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
DEPENDS wibo.build_fixtures)
endfunction(wibo_add_fixture_bin)
# Define fixture tests
wibo_add_fixture_bin(NAME test_external_dll SOURCES test/test_external_dll.c)
wibo_add_fixture_bin(NAME test_dll_attach_failure SOURCES test/test_dll_attach_failure.c)
wibo_add_fixture_bin(NAME test_thread_notifications SOURCES test/test_thread_notifications.c)
wibo_add_fixture_bin(NAME test_bcrypt SOURCES test/test_bcrypt.c COMPILE_OPTIONS -lbcrypt)
wibo_add_fixture_bin(NAME test_resources SOURCES test/test_resources.c ${WIBO_TEST_BIN_DIR}/test_resources_res.o COMPILE_OPTIONS -lversion)
wibo_add_fixture_bin(NAME test_threading SOURCES test/test_threading.c)
wibo_add_fixture_bin(NAME test_handleapi SOURCES test/test_handleapi.c)
wibo_add_fixture_bin(NAME test_findfile SOURCES test/test_findfile.c)
wibo_add_fixture_bin(NAME test_synchapi SOURCES test/test_synchapi.c)
wibo_add_fixture_bin(NAME test_processes SOURCES test/test_processes.c)
wibo_add_fixture_bin(NAME test_heap SOURCES test/test_heap.c)
wibo_add_fixture_bin(NAME test_actctx SOURCES test/test_actctx.c)
wibo_add_fixture_bin(NAME test_overlapped_io SOURCES test/test_overlapped_io.c)
wibo_add_fixture_bin(NAME test_time SOURCES test/test_time.c)
wibo_add_fixture_bin(NAME test_virtualalloc SOURCES test/test_virtualalloc.c)
wibo_add_fixture_bin(NAME test_virtualquery SOURCES test/test_virtualquery.c)
wibo_add_fixture_bin(NAME test_rtl SOURCES test/test_rtl.c)
wibo_add_fixture_bin(NAME test_ntquery SOURCES test/test_ntquery.c)
wibo_add_fixture_bin(NAME test_ntreadfile SOURCES test/test_ntreadfile.c)
wibo_add_fixture_bin(NAME test_pipe_io SOURCES test/test_pipe_io.c)
wibo_add_fixture_bin(NAME test_sysdir SOURCES test/test_sysdir.c)
# DLLs for fixture tests
wibo_add_fixture_dll(NAME external_exports SOURCES test/external_exports.c)
wibo_add_fixture_dll(NAME dll_attach_failure SOURCES test/dll_attach_failure.c)
wibo_add_fixture_dll(NAME thread_notifications SOURCES test/thread_notifications.c)
# Resources for test_resources
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o
COMMAND ${WIBO_MINGW_WINDRES}
${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc
-O coff -o test_resources_res.o
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc)
add_custom_target(wibo_test_fixtures DEPENDS ${WIBO_TEST_FIXTURES})
if(CMAKE_CONFIGURATION_TYPES)
set(_wibo_fixture_build_command
${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config $<CONFIG> --target wibo_test_fixtures)
else()
set(WIBO_TEST_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/test)
file(MAKE_DIRECTORY ${WIBO_TEST_BIN_DIR})
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/external_exports.dll
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
-o external_exports.dll
${CMAKE_CURRENT_SOURCE_DIR}/test/external_exports.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/external_exports.c)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/dll_attach_failure.dll
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
-o dll_attach_failure.dll
${CMAKE_CURRENT_SOURCE_DIR}/test/dll_attach_failure.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/dll_attach_failure.c)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/thread_notifications.dll
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
-o thread_notifications.dll
${CMAKE_CURRENT_SOURCE_DIR}/test/thread_notifications.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/thread_notifications.c)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_external_dll.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_external_dll.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_dll_attach_failure.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_dll_attach_failure.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_dll_attach_failure.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_thread_notifications.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_thread_notifications.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_thread_notifications.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_bcrypt.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_bcrypt.c
-lbcrypt
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_bcrypt.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o
COMMAND ${WIBO_MINGW_WINDRES}
${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc
-O coff -o test_resources_res.o
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_resources.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.c
test_resources_res.o -lversion
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h
${WIBO_TEST_BIN_DIR}/test_resources_res.o)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_threading.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_threading.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_threading.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_threading.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_handleapi.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_handleapi.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_handleapi.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_handleapi.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_findfile.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_findfile.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_findfile.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_findfile.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_synchapi.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_synchapi.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_synchapi.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_synchapi.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_processes.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_processes.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_processes.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_processes.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_heap.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_heap.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_heap.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_heap.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_actctx.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_actctx.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_actctx.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_actctx.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_overlapped_io.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_overlapped_io.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_overlapped_io.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_time.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_time.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_time.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_time.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_virtualalloc.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualalloc.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualalloc.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_virtualquery.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_virtualquery.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualquery.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_virtualquery.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_rtl.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_rtl.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_rtl.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_rtl.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_ntquery.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_ntquery.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntquery.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntquery.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_ntreadfile.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_ntreadfile.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntreadfile.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_ntreadfile.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_pipe_io.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_pipe_io.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_pipe_io.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_pipe_io.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_command(
OUTPUT ${WIBO_TEST_BIN_DIR}/test_sysdir.exe
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
-I${CMAKE_CURRENT_SOURCE_DIR}/test
-o test_sysdir.exe
${CMAKE_CURRENT_SOURCE_DIR}/test/test_sysdir.c
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/test/test_sysdir.c
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
add_custom_target(wibo_test_fixtures
DEPENDS
${WIBO_TEST_BIN_DIR}/external_exports.dll
${WIBO_TEST_BIN_DIR}/dll_attach_failure.dll
${WIBO_TEST_BIN_DIR}/thread_notifications.dll
${WIBO_TEST_BIN_DIR}/test_external_dll.exe
${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe
${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe
${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
${WIBO_TEST_BIN_DIR}/test_resources.exe
${WIBO_TEST_BIN_DIR}/test_threading.exe
${WIBO_TEST_BIN_DIR}/test_handleapi.exe
${WIBO_TEST_BIN_DIR}/test_findfile.exe
${WIBO_TEST_BIN_DIR}/test_synchapi.exe
${WIBO_TEST_BIN_DIR}/test_processes.exe
${WIBO_TEST_BIN_DIR}/test_heap.exe
${WIBO_TEST_BIN_DIR}/test_actctx.exe
${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe
${WIBO_TEST_BIN_DIR}/test_time.exe
${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe
${WIBO_TEST_BIN_DIR}/test_virtualquery.exe
${WIBO_TEST_BIN_DIR}/test_rtl.exe
${WIBO_TEST_BIN_DIR}/test_ntquery.exe
${WIBO_TEST_BIN_DIR}/test_ntreadfile.exe
${WIBO_TEST_BIN_DIR}/test_pipe_io.exe
${WIBO_TEST_BIN_DIR}/test_sysdir.exe)
if(CMAKE_CONFIGURATION_TYPES)
set(_wibo_fixture_build_command
${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --config $<CONFIG> --target wibo_test_fixtures)
else()
set(_wibo_fixture_build_command
${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target wibo_test_fixtures)
endif()
add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command})
add_test(NAME wibo.test_external_dll
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_external_dll.exe)
set_tests_properties(wibo.test_external_dll PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_bcrypt
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe)
set_tests_properties(wibo.test_bcrypt PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_resources
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_resources.exe)
set_tests_properties(wibo.test_resources PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_threading
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_threading.exe)
set_tests_properties(wibo.test_threading PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_handleapi
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_handleapi.exe)
set_tests_properties(wibo.test_handleapi PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_findfile
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_findfile.exe)
set_tests_properties(wibo.test_findfile PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_synchapi
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_synchapi.exe)
set_tests_properties(wibo.test_synchapi PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_processes
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_processes.exe)
set_tests_properties(wibo.test_processes PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_heap
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_heap.exe)
set_tests_properties(wibo.test_heap PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_actctx
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_actctx.exe)
set_tests_properties(wibo.test_actctx PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_overlapped_io
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe)
set_tests_properties(wibo.test_overlapped_io PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_time
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_time.exe)
set_tests_properties(wibo.test_time PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_virtualalloc
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_virtualalloc.exe)
set_tests_properties(wibo.test_virtualalloc PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_virtualquery
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_virtualquery.exe)
set_tests_properties(wibo.test_virtualquery PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_rtl
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_rtl.exe)
set_tests_properties(wibo.test_rtl PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_ntquery
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_ntquery.exe)
set_tests_properties(wibo.test_ntquery PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_ntreadfile
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_ntreadfile.exe)
set_tests_properties(wibo.test_ntreadfile PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_pipe_io
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_pipe_io.exe)
set_tests_properties(wibo.test_pipe_io PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_sysdir
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_sysdir.exe)
set_tests_properties(wibo.test_sysdir PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_dll_attach_failure
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe)
set_tests_properties(wibo.test_dll_attach_failure PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
add_test(NAME wibo.test_thread_notifications
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe)
set_tests_properties(wibo.test_thread_notifications PROPERTIES
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
DEPENDS wibo.build_fixtures)
set(_wibo_fixture_build_command
${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target wibo_test_fixtures)
endif()
add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command})
endif()
endif()

View File

@ -6,6 +6,7 @@ RUN apk add --no-cache \
bash \
binutils \
cmake \
coreutils \
g++ \
git \
linux-headers \
@ -19,18 +20,21 @@ WORKDIR /wibo
COPY . /wibo
# Build type (Release, Debug, RelWithDebInfo, MinSizeRel)
ARG build_type=Release
ARG BUILD_TYPE=Release
# Enable link-time optimization (LTO) (AUTO, ON, OFF)
ARG ENABLE_LTO=AUTO
# Build static binary
RUN cmake -S /wibo -B /wibo/build -G Ninja \
-DCMAKE_BUILD_TYPE="$build_type" \
-DCMAKE_C_FLAGS="-static" \
-DCMAKE_CXX_FLAGS="-static" \
-DBUILD_TESTING=ON \
-DWIBO_ENABLE_FIXTURE_TESTS=ON \
-DMI_LIBC_MUSL=ON \
&& cmake --build /wibo/build \
&& ( [ "$build_type" != "Release" ] || strip -g /wibo/build/wibo )
-DCMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \
-DCMAKE_C_FLAGS:STRING="-static" \
-DCMAKE_CXX_FLAGS:STRING="-static" \
-DMI_LIBC_MUSL:BOOL=ON \
-DWIBO_ENABLE_LIBURING:BOOL=ON \
-DWIBO_ENABLE_LTO:STRING="$ENABLE_LTO" \
&& cmake --build /wibo/build --verbose \
&& ( [ "$BUILD_TYPE" != "Release" ] || strip -g /wibo/build/wibo )
# Export binary (usage: docker build --target export --output build .)
FROM scratch AS export

View File

@ -25,14 +25,17 @@ WORKDIR /wibo
COPY . /wibo
# Build type (Release, Debug, RelWithDebInfo, MinSizeRel)
ARG build_type=Release
ARG BUILD_TYPE=Release
# Enable link-time optimization (LTO) (AUTO, ON, OFF)
ARG ENABLE_LTO=AUTO
RUN cmake -S /wibo -B /wibo/build -G Ninja \
-DCMAKE_BUILD_TYPE="$build_type" \
-DBUILD_TESTING=ON \
-DWIBO_ENABLE_FIXTURE_TESTS=ON \
&& cmake --build /wibo/build \
&& ( [ "$build_type" != "Release" ] || strip -g /wibo/build/wibo )
-DCMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \
-DWIBO_ENABLE_LIBURING:BOOL=ON \
-DWIBO_ENABLE_LTO:STRING="$ENABLE_LTO" \
&& cmake --build /wibo/build --verbose \
&& ( [ "$BUILD_TYPE" != "Release" ] || strip -g /wibo/build/wibo )
# Export binary (usage: docker build -f Dockerfile.ubuntu --target export --output dist .)
FROM scratch AS export

View File

@ -5,7 +5,7 @@ A minimal, low-fuss wrapper that can run simple command-line 32-bit Windows bina
## Building
```sh
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_TESTING=ON
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build
```

View File

@ -1,247 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindFilesystem
##############
This module supports the C++17 standard library's filesystem utilities. Use the
:imp-target:`std::filesystem` imported target to
Options
*******
The ``COMPONENTS`` argument to this module supports the following values:
.. find-component:: Experimental
:name: fs.Experimental
Allows the module to find the "experimental" Filesystem TS version of the
Filesystem library. This is the library that should be used with the
``std::experimental::filesystem`` namespace.
.. find-component:: Final
:name: fs.Final
Finds the final C++17 standard version of the filesystem library.
If no components are provided, behaves as if the
:find-component:`fs.Final` component was specified.
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
Imported Targets
****************
.. imp-target:: std::filesystem
The ``std::filesystem`` imported target is defined when any requested
version of the C++ filesystem library has been found, whether it is
*Experimental* or *Final*.
If no version of the filesystem library is available, this target will not
be defined.
.. note::
This target has ``cxx_std_17`` as an ``INTERFACE``
:ref:`compile language standard feature <req-lang-standards>`. Linking
to this target will automatically enable C++17 if no later standard
version is already required on the linking target.
.. _fs.variables:
Variables
*********
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
filesystem library was found, otherwise ``FALSE``.
.. variable:: CXX_FILESYSTEM_HAVE_FS
Set to ``TRUE`` when a filesystem header was found.
.. variable:: CXX_FILESYSTEM_HEADER
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
found.
.. variable:: CXX_FILESYSTEM_NAMESPACE
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
depending on whether :find-component:`fs.Final` or
:find-component:`fs.Experimental` was found.
Examples
********
Using `find_package(Filesystem)` with no component arguments:
.. code-block:: cmake
find_package(Filesystem REQUIRED)
add_executable(my-program main.cpp)
target_link_libraries(my-program PRIVATE std::filesystem)
#]=======================================================================]
if(TARGET std::filesystem)
# This module has already been processed. Don't do it again.
return()
endif()
cmake_minimum_required(VERSION 3.10)
include(CMakePushCheckState)
include(CheckIncludeFileCXX)
# If we're not cross-compiling, try to run test executables.
# Otherwise, assume that compile + link is a sufficient check.
if(CMAKE_CROSSCOMPILING)
include(CheckCXXSourceCompiles)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_compiles("${code}" ${var})
endmacro()
else()
include(CheckCXXSourceRuns)
macro(_cmcm_check_cxx_source code var)
check_cxx_source_runs("${code}" ${var})
endmacro()
endif()
cmake_push_check_state()
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
# All of our tests required C++17 or later
set(CMAKE_CXX_STANDARD 17)
# Normalize and check the component list we were given
set(want_components ${Filesystem_FIND_COMPONENTS})
if(Filesystem_FIND_COMPONENTS STREQUAL "")
set(want_components Final)
endif()
# Warn on any unrecognized components
set(extra_components ${want_components})
list(REMOVE_ITEM extra_components Final Experimental)
foreach(component IN LISTS extra_components)
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
endforeach()
# Detect which of Experimental and Final we should look for
set(find_experimental TRUE)
set(find_final TRUE)
if(NOT "Final" IN_LIST want_components)
set(find_final FALSE)
endif()
if(NOT "Experimental" IN_LIST want_components)
set(find_experimental FALSE)
endif()
if(find_final)
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
if(_CXX_FILESYSTEM_HAVE_HEADER)
# We found the non-experimental header. Don't bother looking for the
# experimental one.
set(find_experimental FALSE)
endif()
else()
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
endif()
if(find_experimental)
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
else()
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
endif()
if(_CXX_FILESYSTEM_HAVE_HEADER)
set(_have_fs TRUE)
set(_fs_header filesystem)
set(_fs_namespace std::filesystem)
set(_is_experimental FALSE)
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
set(_have_fs TRUE)
set(_fs_header experimental/filesystem)
set(_fs_namespace std::experimental::filesystem)
set(_is_experimental TRUE)
else()
set(_have_fs FALSE)
endif()
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
set(_found FALSE)
if(CXX_FILESYSTEM_HAVE_FS)
# We have some filesystem library available. Do link checks
string(CONFIGURE [[
#include <cstdlib>
#include <@CXX_FILESYSTEM_HEADER@>
int main() {
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
printf("%s", cwd.c_str());
return EXIT_SUCCESS;
}
]] code @ONLY)
# Check a simple filesystem program without any linker flags
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
# Add the libstdc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
# Try the libc++ flag
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
endif()
endif()
if(can_link)
add_library(std::filesystem INTERFACE IMPORTED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
set(_found TRUE)
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
# Nothing to add...
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
endif()
endif()
endif()
cmake_pop_check_state()
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
message(FATAL_ERROR "Cannot run simple program using std::filesystem")
endif()

View File

@ -106,7 +106,7 @@ void *resolveByName(const char *name) {
} // namespace
wibo::ModuleStub lib_advapi32 = {
extern const wibo::ModuleStub lib_advapi32 = {
(const char *[]){
"advapi32",
nullptr,

View File

@ -74,7 +74,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_bcrypt = {
extern const wibo::ModuleStub lib_bcrypt = {
(const char *[]){
"bcrypt",
nullptr,

View File

@ -463,7 +463,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_crt = {
extern const wibo::ModuleStub lib_crt = {
(const char *[]){
"api-ms-win-crt-heap-l1-1-0",
"api-ms-win-crt-locale-l1-1-0",

View File

@ -9,8 +9,8 @@
#include "kernel32/interlockedapi.h"
#include "kernel32/ioapiset.h"
#include "kernel32/libloaderapi.h"
#include "kernel32/namedpipeapi.h"
#include "kernel32/memoryapi.h"
#include "kernel32/namedpipeapi.h"
#include "kernel32/processenv.h"
#include "kernel32/processthreadsapi.h"
#include "kernel32/profileapi.h"
@ -602,7 +602,7 @@ void *resolveByName(const char *name) {
} // namespace
wibo::ModuleStub lib_kernel32 = {
extern const wibo::ModuleStub lib_kernel32 = {
(const char *[]){
"kernel32",
nullptr,

View File

@ -34,7 +34,7 @@ DWORD WIN_FUNC FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback) {
BOOL WIN_FUNC FlsFree(DWORD dwFlsIndex) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("FlsFree(%u)\n", dwFlsIndex);
if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
g_flsValuesUsed[dwFlsIndex] = false;
return TRUE;
} else {
@ -47,7 +47,7 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("FlsGetValue(%u)\n", dwFlsIndex);
PVOID result = nullptr;
if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
result = g_flsValues[dwFlsIndex];
// See https://learn.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-flsgetvalue
wibo::lastError = ERROR_SUCCESS;
@ -61,7 +61,7 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) {
BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("FlsSetValue(%u, %p)\n", dwFlsIndex, lpFlsData);
if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
g_flsValues[dwFlsIndex] = lpFlsData;
return TRUE;
} else {

View File

@ -717,11 +717,11 @@ BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr
return FALSE;
}
std::optional<off64_t> offset;
std::optional<off_t> offset;
bool updateFilePointer = true;
if (lpOverlapped != nullptr) {
offset = static_cast<off64_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
offset = static_cast<off_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
lpOverlapped->Internal = STATUS_PENDING;
lpOverlapped->InternalHigh = 0;
updateFilePointer = !file->overlapped;
@ -736,9 +736,8 @@ BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr
}
return TRUE;
}
auto asyncFile = file.clone();
if (async_io::queueWrite(std::move(asyncFile), lpOverlapped, lpBuffer, nNumberOfBytesToWrite, offset,
file->isPipe)) {
if (wibo::asyncIO().queueWrite(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToWrite, offset,
file->isPipe)) {
if (lpNumberOfBytesWritten) {
*lpNumberOfBytesWritten = 0;
}
@ -814,11 +813,11 @@ BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead
*lpNumberOfBytesRead = 0;
}
std::optional<off64_t> offset;
std::optional<off_t> offset;
bool updateFilePointer = true;
if (lpOverlapped != nullptr) {
offset = static_cast<off64_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
offset = static_cast<off_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
lpOverlapped->Internal = STATUS_PENDING;
lpOverlapped->InternalHigh = 0;
updateFilePointer = !file->overlapped;
@ -833,7 +832,8 @@ BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead
}
return TRUE;
}
if (async_io::queueRead(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToRead, offset, file->isPipe)) {
if (wibo::asyncIO().queueRead(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToRead, offset,
file->isPipe)) {
if (lpNumberOfBytesRead) {
*lpNumberOfBytesRead = 0;
}
@ -1193,14 +1193,14 @@ DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistan
}
// TODO access check
std::lock_guard lk(file->m);
off64_t position = 0;
off64_t offset = static_cast<off64_t>(lDistanceToMove);
off_t position = 0;
off_t offset = static_cast<off_t>(lDistanceToMove);
if (dwMoveMethod == FILE_BEGIN) {
position = offset;
} else if (dwMoveMethod == FILE_CURRENT) {
position = file->filePos + offset;
} else if (dwMoveMethod == FILE_END) {
position = lseek64(file->fd, offset, SEEK_END);
position = lseek(file->fd, offset, SEEK_END);
}
if (position < 0) {
if (errno == EINVAL) {
@ -1232,14 +1232,14 @@ BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLA
}
// TODO access check
std::lock_guard lk(file->m);
off64_t position = 0;
off64_t offset = static_cast<off64_t>(liDistanceToMove);
off_t position = 0;
off_t offset = static_cast<off_t>(liDistanceToMove);
if (dwMoveMethod == FILE_BEGIN) {
position = offset;
} else if (dwMoveMethod == FILE_CURRENT) {
position = file->filePos + offset;
} else if (dwMoveMethod == FILE_END) {
position = lseek64(file->fd, offset, SEEK_END);
position = lseek(file->fd, offset, SEEK_END);
}
if (position < 0) {
if (errno == EINVAL) {
@ -1279,7 +1279,7 @@ BOOL WIN_FUNC SetEndOfFile(HANDLE hFile) {
setLastErrorFromErrno();
return FALSE;
}
if (ftruncate64(file->fd, file->filePos) != 0) {
if (ftruncate(file->fd, file->filePos) != 0) {
setLastErrorFromErrno();
return FALSE;
}
@ -1338,7 +1338,7 @@ DWORD WIN_FUNC GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) {
DEBUG_LOG("-> INVALID_FILE_SIZE (ERROR_INVALID_HANDLE)\n");
return INVALID_FILE_SIZE;
}
const auto size = lseek64(file->fd, 0, SEEK_END);
const auto size = lseek(file->fd, 0, SEEK_END);
if (size < 0) {
if (lpFileSizeHigh) {
*lpFileSizeHigh = 0;
@ -1480,8 +1480,8 @@ BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMAT
return FALSE;
}
// TODO access check
struct stat64 st{};
if (fstat64(file->fd, &st) != 0) {
struct stat st{};
if (fstat(file->fd, &st) != 0) {
setLastErrorFromErrno();
return FALSE;
}

View File

@ -3,6 +3,7 @@
#include "common.h"
#include "context.h"
#include <atomic>
#include <cstring>
namespace kernel32 {
@ -10,32 +11,33 @@ namespace kernel32 {
LONG WIN_FUNC InterlockedIncrement(LONG volatile *Addend) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("InterlockedIncrement(%p)\n", Addend);
return ++(*Addend);
std::atomic_ref<LONG> a(*const_cast<LONG *>(Addend));
return a.fetch_add(1, std::memory_order_seq_cst) + 1;
}
LONG WIN_FUNC InterlockedDecrement(LONG volatile *Addend) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("InterlockedDecrement(%p)\n", Addend);
return --(*Addend);
std::atomic_ref<LONG> a(*const_cast<LONG *>(Addend));
return a.fetch_sub(1, std::memory_order_seq_cst) - 1;
}
LONG WIN_FUNC InterlockedExchange(LONG volatile *Target, LONG Value) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("InterlockedExchange(%p, %ld)\n", Target, static_cast<long>(Value));
LONG initial = *Target;
*Target = Value;
return initial;
std::atomic_ref<LONG> a(*const_cast<LONG *>(Target));
return a.exchange(Value, std::memory_order_seq_cst);
}
LONG WIN_FUNC InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("InterlockedCompareExchange(%p, %ld, %ld)\n", Destination, static_cast<long>(Exchange),
static_cast<long>(Comperand));
LONG original = *Destination;
if (original == Comperand) {
*Destination = Exchange;
}
return original;
std::atomic_ref<LONG> a(*const_cast<LONG *>(Destination));
LONG expected = Comperand;
a.compare_exchange_strong(expected, Exchange, std::memory_order_seq_cst);
return expected;
}
void WIN_FUNC InitializeSListHead(PSLIST_HEADER ListHead) {

View File

@ -26,14 +26,14 @@ struct FsObject : ObjectBase {
struct FileObject final : FsObject {
static constexpr ObjectType kType = ObjectType::File;
off64_t filePos = 0;
off_t filePos = 0;
bool overlapped = false;
bool appendOnly = false;
bool isPipe = false;
explicit FileObject(int fd) : FsObject(kType, fd) {
if (fd >= 0) {
off64_t pos = lseek64(fd, 0, SEEK_CUR);
off_t pos = lseek(fd, 0, SEEK_CUR);
if (pos == -1 && errno == ESPIPE) {
isPipe = true;
} else if (pos >= 0) {

View File

@ -250,7 +250,8 @@ HMODULE WIN_FUNC LoadLibraryW(LPCWSTR lpLibFileName) {
HMODULE WIN_FUNC LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
HOST_CONTEXT_GUARD();
assert(!hFile);
(void)hFile;
// TOOD: handle dwFlags properly
DEBUG_LOG("LoadLibraryExW(%x) -> ", dwFlags);
auto filename = wideStringToString(lpLibFileName);
return LoadLibraryA(filename.c_str());

View File

@ -502,7 +502,7 @@ HANDLE WIN_FUNC CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap
}
mapping->fd = dupFd;
if (size == 0) {
off64_t fileSize = lseek64(dupFd, 0, SEEK_END);
off_t fileSize = lseek(dupFd, 0, SEEK_END);
if (fileSize < 0) {
return nullptr;
}

View File

@ -635,26 +635,31 @@ BOOL WIN_FUNC InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpC
void WIN_FUNC AcquireSRWLockShared(PSRWLOCK SRWLock) {
HOST_CONTEXT_GUARD();
(void)SRWLock;
VERBOSE_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock);
}
void WIN_FUNC ReleaseSRWLockShared(PSRWLOCK SRWLock) {
HOST_CONTEXT_GUARD();
(void)SRWLock;
VERBOSE_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock);
}
void WIN_FUNC AcquireSRWLockExclusive(PSRWLOCK SRWLock) {
HOST_CONTEXT_GUARD();
(void)SRWLock;
VERBOSE_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock);
}
void WIN_FUNC ReleaseSRWLockExclusive(PSRWLOCK SRWLock) {
HOST_CONTEXT_GUARD();
(void)SRWLock;
VERBOSE_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock);
}
BOOLEAN WIN_FUNC TryAcquireSRWLockExclusive(PSRWLOCK SRWLock) {
HOST_CONTEXT_GUARD();
(void)SRWLock;
VERBOSE_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock);
return TRUE;
}

View File

@ -72,16 +72,16 @@ inline bool validateSystemTime(const SYSTEMTIME &st) {
if (st.wDay < 1 || st.wDay > static_cast<short>(daysInMonth(st.wYear, static_cast<unsigned>(st.wMonth)))) {
return false;
}
if (st.wHour < 0 || st.wHour > 23) {
if (st.wHour > 23) {
return false;
}
if (st.wMinute < 0 || st.wMinute > 59) {
if (st.wMinute > 59) {
return false;
}
if (st.wSecond < 0 || st.wSecond > 59) {
if (st.wSecond > 59) {
return false;
}
if (st.wMilliseconds < 0 || st.wMilliseconds > 999) {
if (st.wMilliseconds > 999) {
return false;
}
return true;

View File

@ -27,7 +27,7 @@ static void *resolveByOrdinal(uint16_t ordinal) {
return 0;
}
wibo::ModuleStub lib_lmgr = {
extern const wibo::ModuleStub lib_lmgr = {
(const char *[]){
"lmgr11",
"lmgr326b",

View File

@ -18,7 +18,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_mscoree = {
extern const wibo::ModuleStub lib_mscoree = {
(const char *[]){
"mscoree",
nullptr,

View File

@ -2600,6 +2600,7 @@ namespace msvcrt {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("_itow_s(%d, %p, %zu, %d)\n", value, buffer, size, radix);
if (!buffer || size == 0) return 22;
(void)radix;
assert(radix == 10); // only base 10 supported for now
std::string str = std::to_string(value);
@ -3222,7 +3223,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_msvcrt = {
extern const wibo::ModuleStub lib_msvcrt = {
(const char *[]){
"msvcrt",
"msvcrt40",

View File

@ -152,9 +152,9 @@ NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Ap
useCurrentFilePosition = true;
}
std::optional<off64_t> offset;
std::optional<off_t> offset;
if (!useCurrentFilePosition) {
offset = static_cast<off64_t>(*ByteOffset);
offset = static_cast<off_t>(*ByteOffset);
}
if (useOverlapped && useCurrentFilePosition) {
@ -423,7 +423,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_ntdll = {
extern const wibo::ModuleStub lib_ntdll = {
(const char *[]){
"ntdll",
nullptr,

View File

@ -39,7 +39,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_ole32 = {
extern const wibo::ModuleStub lib_ole32 = {
(const char *[]){
"ole32",
nullptr,

View File

@ -285,7 +285,7 @@ void *resolveByName(const char *name) {
} // namespace
wibo::ModuleStub lib_rpcrt4 = {
extern const wibo::ModuleStub lib_rpcrt4 = {
(const char *[]){"rpcrt4", nullptr},
resolveByName,
nullptr,

View File

@ -120,6 +120,8 @@ namespace user32 {
int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption, unsigned int uType) {
HOST_CONTEXT_GUARD();
(void)hwnd;
(void)uType;
printf("MESSAGE BOX: [%s] %s\n", lpCaption, lpText);
fflush(stdout);
return 1;
@ -183,7 +185,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_user32 = {
extern const wibo::ModuleStub lib_user32 = {
(const char *[]){
"user32",
nullptr,

View File

@ -38,7 +38,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_vcruntime = {
extern const wibo::ModuleStub lib_vcruntime = {
(const char *[]){
"vcruntime140",
nullptr,

View File

@ -327,7 +327,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::ModuleStub lib_version = {
extern const wibo::ModuleStub lib_version = {
(const char *[]){
"version",
nullptr,

View File

@ -1,277 +1,56 @@
#include "async_io.h"
#include "common.h"
#include "errors.h"
#include "kernel32/overlapped_util.h"
#include <memory>
#include <atomic>
#include <cassert>
#include <cerrno>
#include <condition_variable>
#include <liburing.h>
#include <mutex>
#include <optional>
#include <thread>
#include <unistd.h>
namespace async_io {
namespace {
constexpr unsigned kQueueDepth = 64;
std::unique_ptr<wibo::AsyncIOBackend> g_backend;
struct AsyncRequest {
enum class Kind { Read, Write, Shutdown };
Kind kind;
Pin<kernel32::FileObject> file;
OVERLAPPED *overlapped = nullptr;
bool isPipe = false;
struct iovec vec{};
};
class IoUringBackend {
class DummyBackend : public wibo::AsyncIOBackend {
public:
~IoUringBackend() { shutdown(); }
bool init();
void shutdown();
[[nodiscard]] bool running() const noexcept { return mRunning.load(std::memory_order_acquire); }
bool init() override { return true; }
void shutdown() override {}
[[nodiscard]] bool running() const noexcept override { return true; }
bool queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe);
const std::optional<off_t> &offset, bool isPipe) override {
(void)file;
(void)ov;
(void)buffer;
(void)length;
(void)offset;
(void)isPipe;
return false;
}
bool queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe);
private:
bool enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional<off64_t> &offset,
bool isWrite);
void requestStop();
void workerLoop();
void handleCompletion(struct io_uring_cqe *cqe);
void notifySpace();
struct io_uring mRing{};
std::mutex mSubmitMutex;
std::condition_variable mQueueCv;
std::atomic<bool> mRunning{false};
std::atomic<uint32_t> mPending{0};
std::thread mThread;
const std::optional<off_t> &offset, bool isPipe) override {
(void)file;
(void)ov;
(void)buffer;
(void)length;
(void)offset;
(void)isPipe;
return false;
}
};
IoUringBackend gBackend;
} // namespace
bool initialize() {
if (gBackend.running()) {
return true;
namespace wibo {
AsyncIOBackend &asyncIO() {
if (!g_backend) {
#if WIBO_ENABLE_LIBURING
g_backend = detail::createIoUringBackend();
#else
g_backend = std::make_unique<DummyBackend>();
#endif
}
return gBackend.init();
if (!g_backend->init()) {
fprintf(stderr, "asyncIO: failed to initialize backend\n");
abort();
}
return *g_backend;
}
void shutdown() { gBackend.shutdown(); }
bool running() { return gBackend.running(); }
bool queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe) {
if (!gBackend.running()) {
return false;
}
return gBackend.queueRead(std::move(file), ov, buffer, length, offset, isPipe);
}
bool queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe) {
if (!gBackend.running()) {
return false;
}
return gBackend.queueWrite(std::move(file), ov, buffer, length, offset, isPipe);
}
bool IoUringBackend::init() {
if (mRunning.load(std::memory_order_acquire)) {
return true;
}
int rc = io_uring_queue_init(kQueueDepth, &mRing, 0);
if (rc < 0) {
DEBUG_LOG("io_uring_queue_init failed: %d\n", rc);
return false;
}
mRunning.store(true, std::memory_order_release);
mThread = std::thread(&IoUringBackend::workerLoop, this);
DEBUG_LOG("io_uring backend initialized (depth=%u)\n", kQueueDepth);
return true;
}
void IoUringBackend::shutdown() {
if (!mRunning.exchange(false, std::memory_order_acq_rel)) {
return;
}
requestStop();
if (mThread.joinable()) {
mThread.join();
}
io_uring_queue_exit(&mRing);
}
bool IoUringBackend::queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe) {
auto *req = new AsyncRequest{AsyncRequest::Kind::Read, std::move(file), ov, isPipe};
if (!enqueueRequest(req, buffer, length, offset, false)) {
delete req;
return false;
}
return true;
}
bool IoUringBackend::queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe) {
auto *req = new AsyncRequest{AsyncRequest::Kind::Write, std::move(file), ov, isPipe};
if (!enqueueRequest(req, const_cast<void *>(buffer), length, offset, true)) {
delete req;
return false;
}
return true;
}
bool IoUringBackend::enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional<off64_t> &offset,
bool isWrite) {
std::unique_lock lock(mSubmitMutex);
if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) {
return false;
}
struct io_uring_sqe *sqe;
while (true) {
sqe = io_uring_get_sqe(&mRing);
if (!sqe) {
mQueueCv.wait(lock);
if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) {
return false;
}
continue;
}
io_uring_sqe_set_data(sqe, req);
if (req->kind == AsyncRequest::Kind::Shutdown) {
io_uring_prep_nop(sqe);
} else {
req->vec.iov_base = buffer;
req->vec.iov_len = length;
off64_t fileOffset = -1;
if (!req->isPipe && offset.has_value()) {
fileOffset = *offset;
}
int fd = req->file ? req->file->fd : -1;
if (isWrite) {
io_uring_prep_writev(sqe, fd, &req->vec, 1, fileOffset);
} else {
io_uring_prep_readv(sqe, fd, &req->vec, 1, fileOffset);
}
}
mPending.fetch_add(1, std::memory_order_relaxed);
break;
}
while (true) {
int res = io_uring_submit(&mRing);
if (res >= 0) {
break;
} else if (res == -EINTR) {
continue;
} else if (res == -EBUSY || res == -EAGAIN) {
lock.unlock();
std::this_thread::yield();
lock.lock();
continue;
}
DEBUG_LOG("io_uring_submit failed (will retry): %d\n", res);
}
lock.unlock();
mQueueCv.notify_one();
return true;
}
void IoUringBackend::requestStop() {
mRunning.store(false, std::memory_order_release);
auto *req = new AsyncRequest{AsyncRequest::Kind::Shutdown, Pin<kernel32::FileObject>{}, nullptr, false};
if (!enqueueRequest(req, nullptr, 0, std::nullopt, false)) {
delete req;
}
}
void IoUringBackend::workerLoop() {
while (mRunning.load(std::memory_order_acquire) || mPending.load(std::memory_order_acquire) > 0) {
struct io_uring_cqe *cqe = nullptr;
int ret = io_uring_wait_cqe(&mRing, &cqe);
if (ret == -EINTR) {
continue;
}
if (ret < 0) {
DEBUG_LOG("io_uring_wait_cqe failed: %d\n", ret);
continue;
}
handleCompletion(cqe);
io_uring_cqe_seen(&mRing, cqe);
notifySpace();
}
while (mPending.load(std::memory_order_acquire) > 0) {
struct io_uring_cqe *cqe = nullptr;
int ret = io_uring_peek_cqe(&mRing, &cqe);
if (ret != 0 || !cqe) {
break;
}
handleCompletion(cqe);
io_uring_cqe_seen(&mRing, cqe);
notifySpace();
}
}
void IoUringBackend::handleCompletion(struct io_uring_cqe *cqe) {
auto *req = static_cast<AsyncRequest *>(io_uring_cqe_get_data(cqe));
if (!req) {
return;
}
if (req->kind == AsyncRequest::Kind::Shutdown) {
delete req;
mPending.fetch_sub(1, std::memory_order_acq_rel);
return;
}
OVERLAPPED *ov = req->overlapped;
if (ov) {
if (cqe->res >= 0) {
ov->InternalHigh = static_cast<ULONG_PTR>(cqe->res);
if (req->kind == AsyncRequest::Kind::Read && cqe->res == 0) {
ov->Internal = req->isPipe ? STATUS_PIPE_BROKEN : STATUS_END_OF_FILE;
} else {
ov->Internal = STATUS_SUCCESS;
}
} else {
int err = -cqe->res;
ov->InternalHigh = 0;
if (err == EPIPE) {
ov->Internal = STATUS_PIPE_BROKEN;
} else {
NTSTATUS status = wibo::statusFromErrno(err);
if (status == STATUS_SUCCESS) {
status = STATUS_UNEXPECTED_IO_ERROR;
}
ov->Internal = status;
}
}
kernel32::detail::signalOverlappedEvent(ov);
}
delete req;
mPending.fetch_sub(1, std::memory_order_acq_rel);
}
void IoUringBackend::notifySpace() {
std::lock_guard lk(mSubmitMutex);
mQueueCv.notify_all();
}
} // namespace async_io
} // namespace wibo

View File

@ -5,15 +5,28 @@
#include <optional>
namespace async_io {
namespace wibo {
bool initialize();
void shutdown();
bool running();
class AsyncIOBackend {
public:
virtual ~AsyncIOBackend() = default;
virtual bool init() = 0;
virtual void shutdown() = 0;
[[nodiscard]] virtual bool running() const noexcept = 0;
virtual bool queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off_t> &offset, bool isPipe) = 0;
virtual bool queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off_t> &offset, bool isPipe) = 0;
};
bool queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe);
bool queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off64_t> &offset, bool isPipe);
namespace detail {
} // namespace async_io
#if WIBO_ENABLE_LIBURING
std::unique_ptr<AsyncIOBackend> createIoUringBackend();
#endif
} // namespace detail
AsyncIOBackend &asyncIO();
} // namespace wibo

244
src/async_io_uring.cpp Normal file
View File

@ -0,0 +1,244 @@
#include "async_io.h"
#include "errors.h"
#include "kernel32/internal.h"
#include "kernel32/overlapped_util.h"
#include <liburing.h>
#include <optional>
namespace {
constexpr unsigned kQueueDepth = 64;
struct AsyncRequest {
enum class Kind { Read, Write, Shutdown };
Kind kind;
Pin<kernel32::FileObject> file;
OVERLAPPED *overlapped = nullptr;
bool isPipe = false;
struct iovec vec{};
};
class IoUringBackend : public wibo::AsyncIOBackend {
public:
~IoUringBackend() override { shutdown(); }
bool init() override;
void shutdown() override;
[[nodiscard]] bool running() const noexcept override { return mRunning.load(std::memory_order_acquire); }
bool queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off_t> &offset, bool isPipe) override;
bool queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off_t> &offset, bool isPipe) override;
private:
bool enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional<off_t> &offset,
bool isWrite);
void requestStop();
void workerLoop();
void handleCompletion(struct io_uring_cqe *cqe);
void notifySpace();
struct io_uring mRing{};
std::mutex mSubmitMutex;
std::condition_variable mQueueCv;
std::atomic<bool> mRunning{false};
std::atomic<uint32_t> mPending{0};
std::thread mThread;
};
bool IoUringBackend::init() {
if (mRunning.load(std::memory_order_acquire)) {
return true;
}
int rc = io_uring_queue_init(kQueueDepth, &mRing, 0);
if (rc < 0) {
DEBUG_LOG("io_uring_queue_init failed: %d\n", rc);
return false;
}
mRunning.store(true, std::memory_order_release);
mThread = std::thread(&IoUringBackend::workerLoop, this);
DEBUG_LOG("io_uring backend initialized (depth=%u)\n", kQueueDepth);
return true;
}
void IoUringBackend::shutdown() {
if (!mRunning.exchange(false, std::memory_order_acq_rel)) {
return;
}
requestStop();
if (mThread.joinable()) {
mThread.join();
}
io_uring_queue_exit(&mRing);
}
bool IoUringBackend::queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
const std::optional<off_t> &offset, bool isPipe) {
auto *req = new AsyncRequest{AsyncRequest::Kind::Read, std::move(file), ov, isPipe};
if (!enqueueRequest(req, buffer, length, offset, false)) {
delete req;
return false;
}
return true;
}
bool IoUringBackend::queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
const std::optional<off_t> &offset, bool isPipe) {
auto *req = new AsyncRequest{AsyncRequest::Kind::Write, std::move(file), ov, isPipe};
if (!enqueueRequest(req, const_cast<void *>(buffer), length, offset, true)) {
delete req;
return false;
}
return true;
}
bool IoUringBackend::enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional<off_t> &offset,
bool isWrite) {
std::unique_lock lock(mSubmitMutex);
if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) {
return false;
}
struct io_uring_sqe *sqe;
while (true) {
sqe = io_uring_get_sqe(&mRing);
if (!sqe) {
mQueueCv.wait(lock);
if (!mRunning.load(std::memory_order_acquire) && req->kind != AsyncRequest::Kind::Shutdown) {
return false;
}
continue;
}
io_uring_sqe_set_data(sqe, req);
if (req->kind == AsyncRequest::Kind::Shutdown) {
io_uring_prep_nop(sqe);
} else {
req->vec.iov_base = buffer;
req->vec.iov_len = length;
off_t fileOffset = -1;
if (!req->isPipe && offset.has_value()) {
fileOffset = *offset;
}
int fd = req->file ? req->file->fd : -1;
if (isWrite) {
io_uring_prep_writev(sqe, fd, &req->vec, 1, fileOffset);
} else {
io_uring_prep_readv(sqe, fd, &req->vec, 1, fileOffset);
}
}
mPending.fetch_add(1, std::memory_order_relaxed);
break;
}
while (true) {
int res = io_uring_submit(&mRing);
if (res >= 0) {
break;
} else if (res == -EINTR) {
continue;
} else if (res == -EBUSY || res == -EAGAIN) {
lock.unlock();
std::this_thread::yield();
lock.lock();
continue;
}
DEBUG_LOG("io_uring_submit failed (will retry): %d\n", res);
}
lock.unlock();
mQueueCv.notify_one();
return true;
}
void IoUringBackend::requestStop() {
mRunning.store(false, std::memory_order_release);
auto *req = new AsyncRequest{AsyncRequest::Kind::Shutdown, Pin<kernel32::FileObject>{}, nullptr, false};
if (!enqueueRequest(req, nullptr, 0, std::nullopt, false)) {
delete req;
}
}
void IoUringBackend::workerLoop() {
while (mRunning.load(std::memory_order_acquire) || mPending.load(std::memory_order_acquire) > 0) {
struct io_uring_cqe *cqe = nullptr;
int ret = io_uring_wait_cqe(&mRing, &cqe);
if (ret == -EINTR) {
continue;
}
if (ret < 0) {
DEBUG_LOG("io_uring_wait_cqe failed: %d\n", ret);
continue;
}
handleCompletion(cqe);
io_uring_cqe_seen(&mRing, cqe);
notifySpace();
}
while (mPending.load(std::memory_order_acquire) > 0) {
struct io_uring_cqe *cqe = nullptr;
int ret = io_uring_peek_cqe(&mRing, &cqe);
if (ret != 0 || !cqe) {
break;
}
handleCompletion(cqe);
io_uring_cqe_seen(&mRing, cqe);
notifySpace();
}
}
void IoUringBackend::handleCompletion(struct io_uring_cqe *cqe) {
auto *req = static_cast<AsyncRequest *>(io_uring_cqe_get_data(cqe));
if (!req) {
return;
}
if (req->kind == AsyncRequest::Kind::Shutdown) {
delete req;
mPending.fetch_sub(1, std::memory_order_acq_rel);
return;
}
OVERLAPPED *ov = req->overlapped;
if (ov) {
if (cqe->res >= 0) {
ov->InternalHigh = static_cast<ULONG_PTR>(cqe->res);
if (req->kind == AsyncRequest::Kind::Read && cqe->res == 0) {
ov->Internal = req->isPipe ? STATUS_PIPE_BROKEN : STATUS_END_OF_FILE;
} else {
ov->Internal = STATUS_SUCCESS;
}
} else {
int err = -cqe->res;
ov->InternalHigh = 0;
if (err == EPIPE) {
ov->Internal = STATUS_PIPE_BROKEN;
} else {
NTSTATUS status = wibo::statusFromErrno(err);
if (status == STATUS_SUCCESS) {
status = STATUS_UNEXPECTED_IO_ERROR;
}
ov->Internal = status;
}
}
kernel32::detail::signalOverlappedEvent(ov);
}
delete req;
mPending.fetch_sub(1, std::memory_order_acq_rel);
}
void IoUringBackend::notifySpace() {
std::lock_guard lk(mSubmitMutex);
mQueueCv.notify_all();
}
} // namespace
namespace wibo::detail {
std::unique_ptr<AsyncIOBackend> createIoUringBackend() { return std::make_unique<IoUringBackend>(); }
} // namespace wibo::detail

View File

@ -13,11 +13,7 @@
// On Windows, the incoming stack is aligned to a 4 byte boundary.
// force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment.
#ifdef __clang__
#define WIN_ENTRY __attribute__((force_align_arg_pointer))
#else
#define WIN_ENTRY __attribute__((force_align_arg_pointer, callee_pop_aggregate_return(0)))
#endif
#define WIN_ENTRY __attribute__((ms_abi, force_align_arg_pointer))
#define WIN_FUNC WIN_ENTRY __attribute__((stdcall))
#define DEBUG_LOG(...) \

View File

@ -142,7 +142,7 @@ std::string pathToWindows(const std::filesystem::path &path) {
return str;
}
IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional<off64_t> &offset,
IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional<off_t> &offset,
bool updateFilePointer) {
IOResult result{};
if (!file || !file->valid()) {
@ -180,13 +180,13 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt
return result;
}
const auto doRead = [&](off64_t pos) {
const auto doRead = [&](off_t pos) {
size_t total = 0;
size_t remaining = bytesToRead;
uint8_t *in = static_cast<uint8_t *>(buffer);
while (remaining > 0) {
size_t chunk = remaining > SSIZE_MAX ? SSIZE_MAX : remaining;
ssize_t rc = pread64(file->fd, in + total, chunk, pos);
ssize_t rc = pread(file->fd, in + total, chunk, pos);
if (rc == -1) {
if (errno == EINTR) {
continue;
@ -207,10 +207,10 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt
if (updateFilePointer || !offset.has_value()) {
std::lock_guard lk(file->m);
const off64_t pos = offset.value_or(file->filePos);
const off_t pos = offset.value_or(file->filePos);
doRead(pos);
if (updateFilePointer) {
file->filePos = pos + static_cast<off64_t>(result.bytesTransferred);
file->filePos = pos + static_cast<off_t>(result.bytesTransferred);
}
} else {
doRead(*offset);
@ -219,7 +219,7 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt
return result;
}
IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional<off64_t> &offset,
IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional<off_t> &offset,
bool updateFilePointer) {
IOResult result{};
if (!file || !file->valid()) {
@ -256,7 +256,7 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const
}
result.bytesTransferred = total;
if (updateFilePointer) {
off64_t pos = file->isPipe ? 0 : lseek64(file->fd, 0, SEEK_CUR);
off_t pos = file->isPipe ? 0 : lseek(file->fd, 0, SEEK_CUR);
if (pos >= 0) {
file->filePos = pos;
} else if (result.unixError == 0) {
@ -266,13 +266,13 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const
return result;
}
auto doWrite = [&](off64_t pos) {
auto doWrite = [&](off_t pos) {
size_t total = 0;
size_t remaining = bytesToWrite;
const uint8_t *in = static_cast<const uint8_t *>(buffer);
while (remaining > 0) {
size_t chunk = remaining > SSIZE_MAX ? SSIZE_MAX : remaining;
ssize_t rc = pwrite64(file->fd, in + total, chunk, pos);
ssize_t rc = pwrite(file->fd, in + total, chunk, pos);
if (rc == -1) {
if (errno == EINTR) {
continue;
@ -292,10 +292,10 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const
if (updateFilePointer || !offset.has_value()) {
std::lock_guard lk(file->m);
const off64_t pos = offset.value_or(file->filePos);
const off_t pos = offset.value_or(file->filePos);
doWrite(pos);
if (updateFilePointer) {
file->filePos = pos + static_cast<off64_t>(result.bytesTransferred);
file->filePos = pos + static_cast<off_t>(result.bytesTransferred);
}
} else {
doWrite(*offset);

View File

@ -21,9 +21,9 @@ struct IOResult {
void init();
std::filesystem::path pathFromWindows(const char *inStr);
std::string pathToWindows(const std::filesystem::path &path);
IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional<off64_t> &offset,
IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::optional<off_t> &offset,
bool updateFilePointer);
IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional<off64_t> &offset,
IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const std::optional<off_t> &offset,
bool updateFilePointer);
HANDLE getStdHandle(DWORD nStdHandle);
BOOL setStdHandle(DWORD nStdHandle, HANDLE hHandle);

View File

@ -1,5 +1,5 @@
#include "common.h"
#include "async_io.h"
#include "common.h"
#include "context.h"
#include "files.h"
#include "modules.h"
@ -408,14 +408,13 @@ int main(int argc, char **argv) {
blockUpper2GB();
files::init();
wibo::processes().init();
async_io::initialize();
// Create TIB
memset(&tib, 0, sizeof(tib));
tib.tib = &tib;
tib.peb = (PEB *)calloc(sizeof(PEB), 1);
tib.peb->ProcessParameters = (RTL_USER_PROCESS_PARAMETERS *)calloc(sizeof(RTL_USER_PROCESS_PARAMETERS), 1);
tib.peb = static_cast<PEB *>(calloc(1, sizeof(PEB)));
tib.peb->ProcessParameters =
static_cast<RTL_USER_PROCESS_PARAMETERS *>(calloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS)));
wibo::processPeb = tib.peb;
wibo::initializeTibStackInfo(&tib);
if (!wibo::installTibForCurrentThread(&tib)) {

View File

@ -74,6 +74,7 @@ bool ProcessManager::init() {
mRunning.store(true, std::memory_order_release);
mThread = std::thread(&ProcessManager::runLoop, this);
DEBUG_LOG("ProcessManager initialized\n");
return true;
}
@ -159,7 +160,7 @@ void ProcessManager::wake() const {
return;
}
uint64_t n = 1;
write(mWakeFd, &n, sizeof(n));
ssize_t r [[maybe_unused]] = write(mWakeFd, &n, sizeof(n));
}
void ProcessManager::checkPidfd(int pidfd) {
@ -212,6 +213,10 @@ void ProcessManager::checkPidfd(int pidfd) {
ProcessManager &processes() {
static ProcessManager mgr;
if (!mgr.init()) {
fprintf(stderr, "Failed to initialize ProcessManager\n");
abort();
}
return mgr;
}

View File

@ -99,9 +99,8 @@ const wibo::ImageResourceDataEntry *entryAsData(const uint8_t *base, const Image
uint16_t primaryLang(uint16_t lang) { return lang & 0x3FFu; }
const ImageResourceDirectoryEntry *selectLanguageEntry(const ImageResourceDirectory *dir, const uint8_t *base,
uint32_t rsrcSize, std::optional<uint16_t> desired,
uint16_t &chosenLang) {
const ImageResourceDirectoryEntry *selectLanguageEntry(const ImageResourceDirectory *dir,
std::optional<uint16_t> desired, uint16_t &chosenLang) {
const auto *entries = resourceEntries(dir);
uint16_t total = dir->numberOfNamedEntries + dir->numberOfIdEntries;
const ImageResourceDirectoryEntry *primaryMatch = nullptr;
@ -172,7 +171,7 @@ bool Executable::findResource(const ResourceIdentifier &type, const ResourceIden
return false;
}
uint16_t chosenLang = language.value_or(0);
const auto *langEntry = selectLanguageEntry(langDir, base, rsrcSize, language, chosenLang);
const auto *langEntry = selectLanguageEntry(langDir, language, chosenLang);
if (!langEntry) {
wibo::lastError = ERROR_RESOURCE_LANG_NOT_FOUND;
return false;