mirror of
https://github.com/decompals/wibo.git
synced 2025-10-17 15:45:15 +00:00
Make liburing optional; rewrite CMakeLists.txt and enable LTO
This commit is contained in:
parent
df36de18bf
commit
061228c971
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -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 \
|
||||
.
|
||||
|
@ -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.
|
||||
|
653
CMakeLists.txt
653
CMakeLists.txt
@ -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()
|
||||
|
22
Dockerfile
22
Dockerfile
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
|
@ -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()
|
@ -106,7 +106,7 @@ void *resolveByName(const char *name) {
|
||||
|
||||
} // namespace
|
||||
|
||||
wibo::ModuleStub lib_advapi32 = {
|
||||
extern const wibo::ModuleStub lib_advapi32 = {
|
||||
(const char *[]){
|
||||
"advapi32",
|
||||
nullptr,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
299
src/async_io.cpp
299
src/async_io.cpp
@ -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
|
||||
|
@ -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
244
src/async_io_uring.cpp
Normal 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
|
@ -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(...) \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user