mirror of
https://github.com/decompals/wibo.git
synced 2025-12-12 14:46:09 +00:00
Make liburing optional; rewrite CMakeLists.txt and enable LTO
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
|||||||
run: >-
|
run: >-
|
||||||
docker build
|
docker build
|
||||||
-f ${{ matrix.dockerfile }}
|
-f ${{ matrix.dockerfile }}
|
||||||
--build-arg build_type=${{ matrix.build_type }}
|
--build-arg BUILD_TYPE=${{ matrix.build_type }}
|
||||||
--target build
|
--target build
|
||||||
-t ${{ matrix.image }}
|
-t ${{ matrix.image }}
|
||||||
.
|
.
|
||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
rm -rf dist
|
rm -rf dist
|
||||||
docker build \
|
docker build \
|
||||||
-f ${{ matrix.dockerfile }} \
|
-f ${{ matrix.dockerfile }} \
|
||||||
--build-arg build_type=${{ matrix.build_type }} \
|
--build-arg BUILD_TYPE=${{ matrix.build_type }} \
|
||||||
--target export \
|
--target export \
|
||||||
--output dist \
|
--output dist \
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
- Sample fixtures for exercising the loader live in `test/`.
|
- Sample fixtures for exercising the loader live in `test/`.
|
||||||
|
|
||||||
## Build, Test, and Development Commands
|
## 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.
|
- `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.
|
- `./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`).
|
- `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.
|
- Add `DEBUG_LOG` calls to trace execution and parameter values; these are invaluable when diagnosing issues with real-world binaries.
|
||||||
|
|
||||||
## Testing Guidelines
|
## 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`).
|
- 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.
|
- 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.
|
- Update `CMakeLists.txt` to add new fixture sources.
|
||||||
|
|||||||
567
CMakeLists.txt
567
CMakeLists.txt
@@ -1,10 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
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_C_FLAGS_INIT "-m32")
|
||||||
set(CMAKE_CXX_FLAGS_INIT "-m32")
|
set(CMAKE_CXX_FLAGS_INIT "-m32")
|
||||||
set(CMAKE_EXE_LINKER_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)
|
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)
|
if (WIBO_ENABLE_LTO STREQUAL "AUTO")
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-pie -no-pie -D_LARGEFILE64_SOURCE")
|
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)
|
# Fetch and configure mimalloc
|
||||||
|
set(MI_BUILD_SHARED OFF CACHE BOOL "Build shared library" FORCE)
|
||||||
# Disable mimalloc tests
|
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)
|
set(MI_BUILD_TESTS OFF CACHE BOOL "Build test executables" FORCE)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
@@ -31,35 +46,43 @@ FetchContent_Declare(
|
|||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(mimalloc)
|
FetchContent_MakeAvailable(mimalloc)
|
||||||
|
|
||||||
FetchContent_Declare(
|
# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1`
|
||||||
|
target_compile_options(mimalloc-obj PRIVATE -Wno-psabi)
|
||||||
|
|
||||||
|
if (WIBO_ENABLE_LIBURING)
|
||||||
|
FetchContent_Declare(
|
||||||
liburing
|
liburing
|
||||||
GIT_REPOSITORY https://github.com/axboe/liburing.git
|
GIT_REPOSITORY https://github.com/axboe/liburing.git
|
||||||
GIT_TAG liburing-2.4
|
GIT_TAG e907d6a342e80b70874f93abd440b92b8a40b7bc # liburing-2.12
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(liburing)
|
FetchContent_MakeAvailable(liburing)
|
||||||
|
|
||||||
set(LIBURING_COMPAT ${liburing_SOURCE_DIR}/src/include/liburing/compat.h)
|
add_custom_command(
|
||||||
add_custom_command(
|
OUTPUT ${liburing_SOURCE_DIR}/config-host.h
|
||||||
OUTPUT ${LIBURING_COMPAT}
|
${liburing_SOURCE_DIR}/src/include/liburing/compat.h
|
||||||
COMMAND ${CMAKE_COMMAND} -E env
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
CC=${CMAKE_C_COMPILER}
|
CC=${CMAKE_C_COMPILER}
|
||||||
AR=${CMAKE_AR}
|
CXX=${CMAKE_CXX_COMPILER}
|
||||||
RANLIB=${CMAKE_RANLIB}
|
./configure --prefix=${liburing_BINARY_DIR}
|
||||||
./configure --cc=${CMAKE_C_COMPILER}
|
|
||||||
WORKING_DIRECTORY ${liburing_SOURCE_DIR}
|
WORKING_DIRECTORY ${liburing_SOURCE_DIR}
|
||||||
|
DEPENDS ${liburing_SOURCE_DIR}/configure
|
||||||
COMMENT "Running liburing configure"
|
COMMENT "Running liburing configure"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
add_custom_target(liburing_configure DEPENDS ${LIBURING_COMPAT})
|
add_library(liburing STATIC
|
||||||
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/queue.c
|
||||||
${liburing_SOURCE_DIR}/src/register.c
|
${liburing_SOURCE_DIR}/src/register.c
|
||||||
${liburing_SOURCE_DIR}/src/setup.c
|
${liburing_SOURCE_DIR}/src/setup.c
|
||||||
${liburing_SOURCE_DIR}/src/syscall.c
|
${liburing_SOURCE_DIR}/src/syscall.c
|
||||||
${liburing_SOURCE_DIR}/src/version.c)
|
${liburing_SOURCE_DIR}/src/version.c
|
||||||
add_dependencies(liburing liburing_configure)
|
${liburing_SOURCE_DIR}/src/include/liburing/compat.h)
|
||||||
target_include_directories(liburing PUBLIC ${liburing_SOURCE_DIR}/src/include)
|
target_compile_definitions(liburing PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64)
|
||||||
target_compile_definitions(liburing PRIVATE _GNU_SOURCE)
|
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
|
add_executable(wibo
|
||||||
dll/advapi32.cpp
|
dll/advapi32.cpp
|
||||||
@@ -116,14 +139,24 @@ add_executable(wibo
|
|||||||
src/resources.cpp
|
src/resources.cpp
|
||||||
src/strutil.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_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)
|
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_CC i686-w64-mingw32-gcc)
|
||||||
find_program(WIBO_MINGW_WINDRES i686-w64-mingw32-windres)
|
find_program(WIBO_MINGW_WINDRES i686-w64-mingw32-windres)
|
||||||
|
|
||||||
@@ -132,84 +165,87 @@ if(BUILD_TESTING)
|
|||||||
set(WIBO_HAVE_MINGW_TOOLCHAIN TRUE)
|
set(WIBO_HAVE_MINGW_TOOLCHAIN TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(WIBO_ENABLE_FIXTURE_TESTS "Build and run Windows fixture binaries through wibo" ${WIBO_HAVE_MINGW_TOOLCHAIN})
|
|
||||||
|
|
||||||
if(WIBO_ENABLE_FIXTURE_TESTS)
|
|
||||||
if(NOT WIBO_HAVE_MINGW_TOOLCHAIN)
|
if(NOT WIBO_HAVE_MINGW_TOOLCHAIN)
|
||||||
message(WARNING "MinGW toolchain not found; skipping fixture tests")
|
message(WARNING "MinGW toolchain not found; skipping fixture tests")
|
||||||
else()
|
else()
|
||||||
set(WIBO_TEST_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/test)
|
set(WIBO_TEST_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}/test)
|
||||||
file(MAKE_DIRECTORY ${WIBO_TEST_BIN_DIR})
|
file(MAKE_DIRECTORY ${WIBO_TEST_BIN_DIR})
|
||||||
|
|
||||||
|
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(
|
add_custom_command(
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/external_exports.dll
|
OUTPUT ${fixture_OUTPUT}
|
||||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
|
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
|
||||||
-o external_exports.dll
|
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/external_exports.c
|
-o ${fixture_OUTPUT}
|
||||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
${fixture_SOURCES}
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/external_exports.c)
|
${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)
|
||||||
|
|
||||||
add_custom_command(
|
function(wibo_add_fixture_bin)
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/dll_attach_failure.dll
|
set(options)
|
||||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2 -shared
|
set(oneValueArgs NAME)
|
||||||
-o dll_attach_failure.dll
|
set(multiValueArgs SOURCES COMPILE_OPTIONS DEPENDS)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/dll_attach_failure.c
|
cmake_parse_arguments(PARSE_ARGV 0 fixture "${options}" "${oneValueArgs}" "${multiValueArgs}")
|
||||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/dll_attach_failure.c)
|
|
||||||
|
|
||||||
|
set(fixture_OUTPUT ${WIBO_TEST_BIN_DIR}/${fixture_NAME}.exe)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/thread_notifications.dll
|
OUTPUT ${fixture_OUTPUT}
|
||||||
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
|
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
-o test_external_dll.exe
|
-o ${fixture_OUTPUT}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c
|
${fixture_SOURCES}
|
||||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
${fixture_COMPILE_OPTIONS}
|
||||||
DEPENDS
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_external_dll.c
|
DEPENDS ${fixture_SOURCES} ${fixture_DEPENDS})
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
list(APPEND WIBO_TEST_FIXTURES ${fixture_OUTPUT})
|
||||||
|
set(WIBO_TEST_FIXTURES ${WIBO_TEST_FIXTURES} PARENT_SCOPE)
|
||||||
|
|
||||||
add_custom_command(
|
add_test(NAME wibo.${fixture_NAME}
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_dll_attach_failure.exe
|
COMMAND $<TARGET_FILE:wibo> ${fixture_OUTPUT})
|
||||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
set_tests_properties(wibo.${fixture_NAME} PROPERTIES
|
||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
-o test_dll_attach_failure.exe
|
DEPENDS wibo.build_fixtures)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_dll_attach_failure.c
|
endfunction(wibo_add_fixture_bin)
|
||||||
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(
|
# Define fixture tests
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_thread_notifications.exe
|
wibo_add_fixture_bin(NAME test_external_dll SOURCES test/test_external_dll.c)
|
||||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
wibo_add_fixture_bin(NAME test_dll_attach_failure SOURCES test/test_dll_attach_failure.c)
|
||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
wibo_add_fixture_bin(NAME test_thread_notifications SOURCES test/test_thread_notifications.c)
|
||||||
-o test_thread_notifications.exe
|
wibo_add_fixture_bin(NAME test_bcrypt SOURCES test/test_bcrypt.c COMPILE_OPTIONS -lbcrypt)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_thread_notifications.c
|
wibo_add_fixture_bin(NAME test_resources SOURCES test/test_resources.c ${WIBO_TEST_BIN_DIR}/test_resources_res.o COMPILE_OPTIONS -lversion)
|
||||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
wibo_add_fixture_bin(NAME test_threading SOURCES test/test_threading.c)
|
||||||
DEPENDS
|
wibo_add_fixture_bin(NAME test_handleapi SOURCES test/test_handleapi.c)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_thread_notifications.c
|
wibo_add_fixture_bin(NAME test_findfile SOURCES test/test_findfile.c)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
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)
|
||||||
|
|
||||||
add_custom_command(
|
# DLLs for fixture tests
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
|
wibo_add_fixture_dll(NAME external_exports SOURCES test/external_exports.c)
|
||||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
wibo_add_fixture_dll(NAME dll_attach_failure SOURCES test/dll_attach_failure.c)
|
||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
wibo_add_fixture_dll(NAME thread_notifications SOURCES test/thread_notifications.c)
|
||||||
-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)
|
|
||||||
|
|
||||||
|
# Resources for test_resources
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o
|
OUTPUT ${WIBO_TEST_BIN_DIR}/test_resources_res.o
|
||||||
COMMAND ${WIBO_MINGW_WINDRES}
|
COMMAND ${WIBO_MINGW_WINDRES}
|
||||||
@@ -218,221 +254,7 @@ if(BUILD_TESTING)
|
|||||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc)
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test/test_resources.rc)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_target(wibo_test_fixtures DEPENDS ${WIBO_TEST_FIXTURES})
|
||||||
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)
|
if(CMAKE_CONFIGURATION_TYPES)
|
||||||
set(_wibo_fixture_build_command
|
set(_wibo_fixture_build_command
|
||||||
@@ -443,132 +265,5 @@ if(BUILD_TESTING)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command})
|
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)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
22
Dockerfile
22
Dockerfile
@@ -6,6 +6,7 @@ RUN apk add --no-cache \
|
|||||||
bash \
|
bash \
|
||||||
binutils \
|
binutils \
|
||||||
cmake \
|
cmake \
|
||||||
|
coreutils \
|
||||||
g++ \
|
g++ \
|
||||||
git \
|
git \
|
||||||
linux-headers \
|
linux-headers \
|
||||||
@@ -19,18 +20,21 @@ WORKDIR /wibo
|
|||||||
COPY . /wibo
|
COPY . /wibo
|
||||||
|
|
||||||
# Build type (Release, Debug, RelWithDebInfo, MinSizeRel)
|
# 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
|
# Build static binary
|
||||||
RUN cmake -S /wibo -B /wibo/build -G Ninja \
|
RUN cmake -S /wibo -B /wibo/build -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE="$build_type" \
|
-DCMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \
|
||||||
-DCMAKE_C_FLAGS="-static" \
|
-DCMAKE_C_FLAGS:STRING="-static" \
|
||||||
-DCMAKE_CXX_FLAGS="-static" \
|
-DCMAKE_CXX_FLAGS:STRING="-static" \
|
||||||
-DBUILD_TESTING=ON \
|
-DMI_LIBC_MUSL:BOOL=ON \
|
||||||
-DWIBO_ENABLE_FIXTURE_TESTS=ON \
|
-DWIBO_ENABLE_LIBURING:BOOL=ON \
|
||||||
-DMI_LIBC_MUSL=ON \
|
-DWIBO_ENABLE_LTO:STRING="$ENABLE_LTO" \
|
||||||
&& cmake --build /wibo/build \
|
&& cmake --build /wibo/build --verbose \
|
||||||
&& ( [ "$build_type" != "Release" ] || strip -g /wibo/build/wibo )
|
&& ( [ "$BUILD_TYPE" != "Release" ] || strip -g /wibo/build/wibo )
|
||||||
|
|
||||||
# Export binary (usage: docker build --target export --output build .)
|
# Export binary (usage: docker build --target export --output build .)
|
||||||
FROM scratch AS export
|
FROM scratch AS export
|
||||||
|
|||||||
@@ -25,14 +25,17 @@ WORKDIR /wibo
|
|||||||
COPY . /wibo
|
COPY . /wibo
|
||||||
|
|
||||||
# Build type (Release, Debug, RelWithDebInfo, MinSizeRel)
|
# 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 \
|
RUN cmake -S /wibo -B /wibo/build -G Ninja \
|
||||||
-DCMAKE_BUILD_TYPE="$build_type" \
|
-DCMAKE_BUILD_TYPE:STRING="$BUILD_TYPE" \
|
||||||
-DBUILD_TESTING=ON \
|
-DWIBO_ENABLE_LIBURING:BOOL=ON \
|
||||||
-DWIBO_ENABLE_FIXTURE_TESTS=ON \
|
-DWIBO_ENABLE_LTO:STRING="$ENABLE_LTO" \
|
||||||
&& cmake --build /wibo/build \
|
&& cmake --build /wibo/build --verbose \
|
||||||
&& ( [ "$build_type" != "Release" ] || strip -g /wibo/build/wibo )
|
&& ( [ "$BUILD_TYPE" != "Release" ] || strip -g /wibo/build/wibo )
|
||||||
|
|
||||||
# Export binary (usage: docker build -f Dockerfile.ubuntu --target export --output dist .)
|
# Export binary (usage: docker build -f Dockerfile.ubuntu --target export --output dist .)
|
||||||
FROM scratch AS export
|
FROM scratch AS export
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ A minimal, low-fuss wrapper that can run simple command-line 32-bit Windows bina
|
|||||||
## Building
|
## Building
|
||||||
|
|
||||||
```sh
|
```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
|
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
|
} // namespace
|
||||||
|
|
||||||
wibo::ModuleStub lib_advapi32 = {
|
extern const wibo::ModuleStub lib_advapi32 = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"advapi32",
|
"advapi32",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_bcrypt = {
|
extern const wibo::ModuleStub lib_bcrypt = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_crt = {
|
extern const wibo::ModuleStub lib_crt = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"api-ms-win-crt-heap-l1-1-0",
|
"api-ms-win-crt-heap-l1-1-0",
|
||||||
"api-ms-win-crt-locale-l1-1-0",
|
"api-ms-win-crt-locale-l1-1-0",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#include "kernel32/interlockedapi.h"
|
#include "kernel32/interlockedapi.h"
|
||||||
#include "kernel32/ioapiset.h"
|
#include "kernel32/ioapiset.h"
|
||||||
#include "kernel32/libloaderapi.h"
|
#include "kernel32/libloaderapi.h"
|
||||||
#include "kernel32/namedpipeapi.h"
|
|
||||||
#include "kernel32/memoryapi.h"
|
#include "kernel32/memoryapi.h"
|
||||||
|
#include "kernel32/namedpipeapi.h"
|
||||||
#include "kernel32/processenv.h"
|
#include "kernel32/processenv.h"
|
||||||
#include "kernel32/processthreadsapi.h"
|
#include "kernel32/processthreadsapi.h"
|
||||||
#include "kernel32/profileapi.h"
|
#include "kernel32/profileapi.h"
|
||||||
@@ -602,7 +602,7 @@ void *resolveByName(const char *name) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
wibo::ModuleStub lib_kernel32 = {
|
extern const wibo::ModuleStub lib_kernel32 = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"kernel32",
|
"kernel32",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ DWORD WIN_FUNC FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback) {
|
|||||||
BOOL WIN_FUNC FlsFree(DWORD dwFlsIndex) {
|
BOOL WIN_FUNC FlsFree(DWORD dwFlsIndex) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("FlsFree(%u)\n", dwFlsIndex);
|
DEBUG_LOG("FlsFree(%u)\n", dwFlsIndex);
|
||||||
if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
|
if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
|
||||||
g_flsValuesUsed[dwFlsIndex] = false;
|
g_flsValuesUsed[dwFlsIndex] = false;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else {
|
} else {
|
||||||
@@ -47,7 +47,7 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) {
|
|||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("FlsGetValue(%u)\n", dwFlsIndex);
|
VERBOSE_LOG("FlsGetValue(%u)\n", dwFlsIndex);
|
||||||
PVOID result = nullptr;
|
PVOID result = nullptr;
|
||||||
if (dwFlsIndex >= 0 && dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
|
if (dwFlsIndex < kMaxFlsValues && g_flsValuesUsed[dwFlsIndex]) {
|
||||||
result = g_flsValues[dwFlsIndex];
|
result = g_flsValues[dwFlsIndex];
|
||||||
// See https://learn.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-flsgetvalue
|
// See https://learn.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-flsgetvalue
|
||||||
wibo::lastError = ERROR_SUCCESS;
|
wibo::lastError = ERROR_SUCCESS;
|
||||||
@@ -61,7 +61,7 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex) {
|
|||||||
BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData) {
|
BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("FlsSetValue(%u, %p)\n", dwFlsIndex, lpFlsData);
|
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;
|
g_flsValues[dwFlsIndex] = lpFlsData;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -717,10 +717,10 @@ BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<off64_t> offset;
|
std::optional<off_t> offset;
|
||||||
bool updateFilePointer = true;
|
bool updateFilePointer = true;
|
||||||
if (lpOverlapped != nullptr) {
|
if (lpOverlapped != nullptr) {
|
||||||
offset = static_cast<off64_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
|
offset = static_cast<off_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
|
||||||
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
|
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
|
||||||
lpOverlapped->Internal = STATUS_PENDING;
|
lpOverlapped->Internal = STATUS_PENDING;
|
||||||
lpOverlapped->InternalHigh = 0;
|
lpOverlapped->InternalHigh = 0;
|
||||||
@@ -736,8 +736,7 @@ BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr
|
|||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
auto asyncFile = file.clone();
|
if (wibo::asyncIO().queueWrite(file.clone(), lpOverlapped, lpBuffer, nNumberOfBytesToWrite, offset,
|
||||||
if (async_io::queueWrite(std::move(asyncFile), lpOverlapped, lpBuffer, nNumberOfBytesToWrite, offset,
|
|
||||||
file->isPipe)) {
|
file->isPipe)) {
|
||||||
if (lpNumberOfBytesWritten) {
|
if (lpNumberOfBytesWritten) {
|
||||||
*lpNumberOfBytesWritten = 0;
|
*lpNumberOfBytesWritten = 0;
|
||||||
@@ -814,10 +813,10 @@ BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead
|
|||||||
*lpNumberOfBytesRead = 0;
|
*lpNumberOfBytesRead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<off64_t> offset;
|
std::optional<off_t> offset;
|
||||||
bool updateFilePointer = true;
|
bool updateFilePointer = true;
|
||||||
if (lpOverlapped != nullptr) {
|
if (lpOverlapped != nullptr) {
|
||||||
offset = static_cast<off64_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
|
offset = static_cast<off_t>((static_cast<uint64_t>(lpOverlapped->Offset)) |
|
||||||
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
|
(static_cast<uint64_t>(lpOverlapped->OffsetHigh) << 32));
|
||||||
lpOverlapped->Internal = STATUS_PENDING;
|
lpOverlapped->Internal = STATUS_PENDING;
|
||||||
lpOverlapped->InternalHigh = 0;
|
lpOverlapped->InternalHigh = 0;
|
||||||
@@ -833,7 +832,8 @@ BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead
|
|||||||
}
|
}
|
||||||
return TRUE;
|
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) {
|
if (lpNumberOfBytesRead) {
|
||||||
*lpNumberOfBytesRead = 0;
|
*lpNumberOfBytesRead = 0;
|
||||||
}
|
}
|
||||||
@@ -1193,14 +1193,14 @@ DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistan
|
|||||||
}
|
}
|
||||||
// TODO access check
|
// TODO access check
|
||||||
std::lock_guard lk(file->m);
|
std::lock_guard lk(file->m);
|
||||||
off64_t position = 0;
|
off_t position = 0;
|
||||||
off64_t offset = static_cast<off64_t>(lDistanceToMove);
|
off_t offset = static_cast<off_t>(lDistanceToMove);
|
||||||
if (dwMoveMethod == FILE_BEGIN) {
|
if (dwMoveMethod == FILE_BEGIN) {
|
||||||
position = offset;
|
position = offset;
|
||||||
} else if (dwMoveMethod == FILE_CURRENT) {
|
} else if (dwMoveMethod == FILE_CURRENT) {
|
||||||
position = file->filePos + offset;
|
position = file->filePos + offset;
|
||||||
} else if (dwMoveMethod == FILE_END) {
|
} else if (dwMoveMethod == FILE_END) {
|
||||||
position = lseek64(file->fd, offset, SEEK_END);
|
position = lseek(file->fd, offset, SEEK_END);
|
||||||
}
|
}
|
||||||
if (position < 0) {
|
if (position < 0) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
@@ -1232,14 +1232,14 @@ BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLA
|
|||||||
}
|
}
|
||||||
// TODO access check
|
// TODO access check
|
||||||
std::lock_guard lk(file->m);
|
std::lock_guard lk(file->m);
|
||||||
off64_t position = 0;
|
off_t position = 0;
|
||||||
off64_t offset = static_cast<off64_t>(liDistanceToMove);
|
off_t offset = static_cast<off_t>(liDistanceToMove);
|
||||||
if (dwMoveMethod == FILE_BEGIN) {
|
if (dwMoveMethod == FILE_BEGIN) {
|
||||||
position = offset;
|
position = offset;
|
||||||
} else if (dwMoveMethod == FILE_CURRENT) {
|
} else if (dwMoveMethod == FILE_CURRENT) {
|
||||||
position = file->filePos + offset;
|
position = file->filePos + offset;
|
||||||
} else if (dwMoveMethod == FILE_END) {
|
} else if (dwMoveMethod == FILE_END) {
|
||||||
position = lseek64(file->fd, offset, SEEK_END);
|
position = lseek(file->fd, offset, SEEK_END);
|
||||||
}
|
}
|
||||||
if (position < 0) {
|
if (position < 0) {
|
||||||
if (errno == EINVAL) {
|
if (errno == EINVAL) {
|
||||||
@@ -1279,7 +1279,7 @@ BOOL WIN_FUNC SetEndOfFile(HANDLE hFile) {
|
|||||||
setLastErrorFromErrno();
|
setLastErrorFromErrno();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (ftruncate64(file->fd, file->filePos) != 0) {
|
if (ftruncate(file->fd, file->filePos) != 0) {
|
||||||
setLastErrorFromErrno();
|
setLastErrorFromErrno();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1338,7 +1338,7 @@ DWORD WIN_FUNC GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) {
|
|||||||
DEBUG_LOG("-> INVALID_FILE_SIZE (ERROR_INVALID_HANDLE)\n");
|
DEBUG_LOG("-> INVALID_FILE_SIZE (ERROR_INVALID_HANDLE)\n");
|
||||||
return INVALID_FILE_SIZE;
|
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 (size < 0) {
|
||||||
if (lpFileSizeHigh) {
|
if (lpFileSizeHigh) {
|
||||||
*lpFileSizeHigh = 0;
|
*lpFileSizeHigh = 0;
|
||||||
@@ -1480,8 +1480,8 @@ BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMAT
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
// TODO access check
|
// TODO access check
|
||||||
struct stat64 st{};
|
struct stat st{};
|
||||||
if (fstat64(file->fd, &st) != 0) {
|
if (fstat(file->fd, &st) != 0) {
|
||||||
setLastErrorFromErrno();
|
setLastErrorFromErrno();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
@@ -10,32 +11,33 @@ namespace kernel32 {
|
|||||||
LONG WIN_FUNC InterlockedIncrement(LONG volatile *Addend) {
|
LONG WIN_FUNC InterlockedIncrement(LONG volatile *Addend) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedIncrement(%p)\n", Addend);
|
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) {
|
LONG WIN_FUNC InterlockedDecrement(LONG volatile *Addend) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedDecrement(%p)\n", Addend);
|
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) {
|
LONG WIN_FUNC InterlockedExchange(LONG volatile *Target, LONG Value) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedExchange(%p, %ld)\n", Target, static_cast<long>(Value));
|
VERBOSE_LOG("InterlockedExchange(%p, %ld)\n", Target, static_cast<long>(Value));
|
||||||
LONG initial = *Target;
|
std::atomic_ref<LONG> a(*const_cast<LONG *>(Target));
|
||||||
*Target = Value;
|
return a.exchange(Value, std::memory_order_seq_cst);
|
||||||
return initial;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG WIN_FUNC InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
|
LONG WIN_FUNC InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedCompareExchange(%p, %ld, %ld)\n", Destination, static_cast<long>(Exchange),
|
VERBOSE_LOG("InterlockedCompareExchange(%p, %ld, %ld)\n", Destination, static_cast<long>(Exchange),
|
||||||
static_cast<long>(Comperand));
|
static_cast<long>(Comperand));
|
||||||
LONG original = *Destination;
|
|
||||||
if (original == Comperand) {
|
std::atomic_ref<LONG> a(*const_cast<LONG *>(Destination));
|
||||||
*Destination = Exchange;
|
LONG expected = Comperand;
|
||||||
}
|
a.compare_exchange_strong(expected, Exchange, std::memory_order_seq_cst);
|
||||||
return original;
|
return expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WIN_FUNC InitializeSListHead(PSLIST_HEADER ListHead) {
|
void WIN_FUNC InitializeSListHead(PSLIST_HEADER ListHead) {
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ struct FsObject : ObjectBase {
|
|||||||
struct FileObject final : FsObject {
|
struct FileObject final : FsObject {
|
||||||
static constexpr ObjectType kType = ObjectType::File;
|
static constexpr ObjectType kType = ObjectType::File;
|
||||||
|
|
||||||
off64_t filePos = 0;
|
off_t filePos = 0;
|
||||||
bool overlapped = false;
|
bool overlapped = false;
|
||||||
bool appendOnly = false;
|
bool appendOnly = false;
|
||||||
bool isPipe = false;
|
bool isPipe = false;
|
||||||
|
|
||||||
explicit FileObject(int fd) : FsObject(kType, fd) {
|
explicit FileObject(int fd) : FsObject(kType, fd) {
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
off64_t pos = lseek64(fd, 0, SEEK_CUR);
|
off_t pos = lseek(fd, 0, SEEK_CUR);
|
||||||
if (pos == -1 && errno == ESPIPE) {
|
if (pos == -1 && errno == ESPIPE) {
|
||||||
isPipe = true;
|
isPipe = true;
|
||||||
} else if (pos >= 0) {
|
} else if (pos >= 0) {
|
||||||
|
|||||||
@@ -250,7 +250,8 @@ HMODULE WIN_FUNC LoadLibraryW(LPCWSTR lpLibFileName) {
|
|||||||
|
|
||||||
HMODULE WIN_FUNC LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
|
HMODULE WIN_FUNC LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
assert(!hFile);
|
(void)hFile;
|
||||||
|
// TOOD: handle dwFlags properly
|
||||||
DEBUG_LOG("LoadLibraryExW(%x) -> ", dwFlags);
|
DEBUG_LOG("LoadLibraryExW(%x) -> ", dwFlags);
|
||||||
auto filename = wideStringToString(lpLibFileName);
|
auto filename = wideStringToString(lpLibFileName);
|
||||||
return LoadLibraryA(filename.c_str());
|
return LoadLibraryA(filename.c_str());
|
||||||
|
|||||||
@@ -502,7 +502,7 @@ HANDLE WIN_FUNC CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap
|
|||||||
}
|
}
|
||||||
mapping->fd = dupFd;
|
mapping->fd = dupFd;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
off64_t fileSize = lseek64(dupFd, 0, SEEK_END);
|
off_t fileSize = lseek(dupFd, 0, SEEK_END);
|
||||||
if (fileSize < 0) {
|
if (fileSize < 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -635,26 +635,31 @@ BOOL WIN_FUNC InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpC
|
|||||||
|
|
||||||
void WIN_FUNC AcquireSRWLockShared(PSRWLOCK SRWLock) {
|
void WIN_FUNC AcquireSRWLockShared(PSRWLOCK SRWLock) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
|
(void)SRWLock;
|
||||||
VERBOSE_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock);
|
VERBOSE_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WIN_FUNC ReleaseSRWLockShared(PSRWLOCK SRWLock) {
|
void WIN_FUNC ReleaseSRWLockShared(PSRWLOCK SRWLock) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
|
(void)SRWLock;
|
||||||
VERBOSE_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock);
|
VERBOSE_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WIN_FUNC AcquireSRWLockExclusive(PSRWLOCK SRWLock) {
|
void WIN_FUNC AcquireSRWLockExclusive(PSRWLOCK SRWLock) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
|
(void)SRWLock;
|
||||||
VERBOSE_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock);
|
VERBOSE_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WIN_FUNC ReleaseSRWLockExclusive(PSRWLOCK SRWLock) {
|
void WIN_FUNC ReleaseSRWLockExclusive(PSRWLOCK SRWLock) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
|
(void)SRWLock;
|
||||||
VERBOSE_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock);
|
VERBOSE_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN WIN_FUNC TryAcquireSRWLockExclusive(PSRWLOCK SRWLock) {
|
BOOLEAN WIN_FUNC TryAcquireSRWLockExclusive(PSRWLOCK SRWLock) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
|
(void)SRWLock;
|
||||||
VERBOSE_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock);
|
VERBOSE_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock);
|
||||||
return TRUE;
|
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)))) {
|
if (st.wDay < 1 || st.wDay > static_cast<short>(daysInMonth(st.wYear, static_cast<unsigned>(st.wMonth)))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (st.wHour < 0 || st.wHour > 23) {
|
if (st.wHour > 23) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (st.wMinute < 0 || st.wMinute > 59) {
|
if (st.wMinute > 59) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (st.wSecond < 0 || st.wSecond > 59) {
|
if (st.wSecond > 59) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (st.wMilliseconds < 0 || st.wMilliseconds > 999) {
|
if (st.wMilliseconds > 999) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ static void *resolveByOrdinal(uint16_t ordinal) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_lmgr = {
|
extern const wibo::ModuleStub lib_lmgr = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"lmgr11",
|
"lmgr11",
|
||||||
"lmgr326b",
|
"lmgr326b",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_mscoree = {
|
extern const wibo::ModuleStub lib_mscoree = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"mscoree",
|
"mscoree",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -2600,6 +2600,7 @@ namespace msvcrt {
|
|||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("_itow_s(%d, %p, %zu, %d)\n", value, buffer, size, radix);
|
VERBOSE_LOG("_itow_s(%d, %p, %zu, %d)\n", value, buffer, size, radix);
|
||||||
if (!buffer || size == 0) return 22;
|
if (!buffer || size == 0) return 22;
|
||||||
|
(void)radix;
|
||||||
assert(radix == 10); // only base 10 supported for now
|
assert(radix == 10); // only base 10 supported for now
|
||||||
|
|
||||||
std::string str = std::to_string(value);
|
std::string str = std::to_string(value);
|
||||||
@@ -3222,7 +3223,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_msvcrt = {
|
extern const wibo::ModuleStub lib_msvcrt = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"msvcrt",
|
"msvcrt",
|
||||||
"msvcrt40",
|
"msvcrt40",
|
||||||
|
|||||||
@@ -152,9 +152,9 @@ NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Ap
|
|||||||
useCurrentFilePosition = true;
|
useCurrentFilePosition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<off64_t> offset;
|
std::optional<off_t> offset;
|
||||||
if (!useCurrentFilePosition) {
|
if (!useCurrentFilePosition) {
|
||||||
offset = static_cast<off64_t>(*ByteOffset);
|
offset = static_cast<off_t>(*ByteOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useOverlapped && useCurrentFilePosition) {
|
if (useOverlapped && useCurrentFilePosition) {
|
||||||
@@ -423,7 +423,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_ntdll = {
|
extern const wibo::ModuleStub lib_ntdll = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"ntdll",
|
"ntdll",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_ole32 = {
|
extern const wibo::ModuleStub lib_ole32 = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"ole32",
|
"ole32",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ void *resolveByName(const char *name) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
wibo::ModuleStub lib_rpcrt4 = {
|
extern const wibo::ModuleStub lib_rpcrt4 = {
|
||||||
(const char *[]){"rpcrt4", nullptr},
|
(const char *[]){"rpcrt4", nullptr},
|
||||||
resolveByName,
|
resolveByName,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ namespace user32 {
|
|||||||
|
|
||||||
int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption, unsigned int uType) {
|
int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption, unsigned int uType) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
|
(void)hwnd;
|
||||||
|
(void)uType;
|
||||||
printf("MESSAGE BOX: [%s] %s\n", lpCaption, lpText);
|
printf("MESSAGE BOX: [%s] %s\n", lpCaption, lpText);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -183,7 +185,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_user32 = {
|
extern const wibo::ModuleStub lib_user32 = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"user32",
|
"user32",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_vcruntime = {
|
extern const wibo::ModuleStub lib_vcruntime = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"vcruntime140",
|
"vcruntime140",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ static void *resolveByName(const char *name) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::ModuleStub lib_version = {
|
extern const wibo::ModuleStub lib_version = {
|
||||||
(const char *[]){
|
(const char *[]){
|
||||||
"version",
|
"version",
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
299
src/async_io.cpp
299
src/async_io.cpp
@@ -1,277 +1,56 @@
|
|||||||
#include "async_io.h"
|
#include "async_io.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include <memory>
|
||||||
#include "errors.h"
|
|
||||||
#include "kernel32/overlapped_util.h"
|
|
||||||
|
|
||||||
#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 {
|
namespace {
|
||||||
|
|
||||||
constexpr unsigned kQueueDepth = 64;
|
std::unique_ptr<wibo::AsyncIOBackend> g_backend;
|
||||||
|
|
||||||
struct AsyncRequest {
|
class DummyBackend : public wibo::AsyncIOBackend {
|
||||||
enum class Kind { Read, Write, Shutdown };
|
|
||||||
|
|
||||||
Kind kind;
|
|
||||||
Pin<kernel32::FileObject> file;
|
|
||||||
OVERLAPPED *overlapped = nullptr;
|
|
||||||
bool isPipe = false;
|
|
||||||
struct iovec vec{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class IoUringBackend {
|
|
||||||
public:
|
public:
|
||||||
~IoUringBackend() { shutdown(); }
|
bool init() override { return true; }
|
||||||
bool init();
|
void shutdown() override {}
|
||||||
void shutdown();
|
[[nodiscard]] bool running() const noexcept override { return true; }
|
||||||
[[nodiscard]] bool running() const noexcept { return mRunning.load(std::memory_order_acquire); }
|
|
||||||
|
|
||||||
bool queueRead(Pin<kernel32::FileObject> file, OVERLAPPED *ov, void *buffer, DWORD length,
|
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,
|
bool queueWrite(Pin<kernel32::FileObject> file, OVERLAPPED *ov, const void *buffer, DWORD length,
|
||||||
const std::optional<off64_t> &offset, bool isPipe);
|
const std::optional<off_t> &offset, bool isPipe) override {
|
||||||
|
(void)file;
|
||||||
private:
|
(void)ov;
|
||||||
bool enqueueRequest(AsyncRequest *req, void *buffer, DWORD length, const std::optional<off64_t> &offset,
|
(void)buffer;
|
||||||
bool isWrite);
|
(void)length;
|
||||||
void requestStop();
|
(void)offset;
|
||||||
void workerLoop();
|
(void)isPipe;
|
||||||
void handleCompletion(struct io_uring_cqe *cqe);
|
return false;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IoUringBackend gBackend;
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool initialize() {
|
namespace wibo {
|
||||||
if (gBackend.running()) {
|
|
||||||
return true;
|
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(); }
|
} // namespace wibo
|
||||||
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -5,15 +5,28 @@
|
|||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace async_io {
|
namespace wibo {
|
||||||
|
|
||||||
bool initialize();
|
class AsyncIOBackend {
|
||||||
void shutdown();
|
public:
|
||||||
bool running();
|
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,
|
namespace detail {
|
||||||
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 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.
|
// 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.
|
// force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment.
|
||||||
#ifdef __clang__
|
#define WIN_ENTRY __attribute__((ms_abi, force_align_arg_pointer))
|
||||||
#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_FUNC WIN_ENTRY __attribute__((stdcall))
|
#define WIN_FUNC WIN_ENTRY __attribute__((stdcall))
|
||||||
|
|
||||||
#define DEBUG_LOG(...) \
|
#define DEBUG_LOG(...) \
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ std::string pathToWindows(const std::filesystem::path &path) {
|
|||||||
return str;
|
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) {
|
bool updateFilePointer) {
|
||||||
IOResult result{};
|
IOResult result{};
|
||||||
if (!file || !file->valid()) {
|
if (!file || !file->valid()) {
|
||||||
@@ -180,13 +180,13 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto doRead = [&](off64_t pos) {
|
const auto doRead = [&](off_t pos) {
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
size_t remaining = bytesToRead;
|
size_t remaining = bytesToRead;
|
||||||
uint8_t *in = static_cast<uint8_t *>(buffer);
|
uint8_t *in = static_cast<uint8_t *>(buffer);
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
size_t chunk = remaining > SSIZE_MAX ? SSIZE_MAX : remaining;
|
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 (rc == -1) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
@@ -207,10 +207,10 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt
|
|||||||
|
|
||||||
if (updateFilePointer || !offset.has_value()) {
|
if (updateFilePointer || !offset.has_value()) {
|
||||||
std::lock_guard lk(file->m);
|
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);
|
doRead(pos);
|
||||||
if (updateFilePointer) {
|
if (updateFilePointer) {
|
||||||
file->filePos = pos + static_cast<off64_t>(result.bytesTransferred);
|
file->filePos = pos + static_cast<off_t>(result.bytesTransferred);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
doRead(*offset);
|
doRead(*offset);
|
||||||
@@ -219,7 +219,7 @@ IOResult read(FileObject *file, void *buffer, size_t bytesToRead, const std::opt
|
|||||||
return result;
|
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) {
|
bool updateFilePointer) {
|
||||||
IOResult result{};
|
IOResult result{};
|
||||||
if (!file || !file->valid()) {
|
if (!file || !file->valid()) {
|
||||||
@@ -256,7 +256,7 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const
|
|||||||
}
|
}
|
||||||
result.bytesTransferred = total;
|
result.bytesTransferred = total;
|
||||||
if (updateFilePointer) {
|
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) {
|
if (pos >= 0) {
|
||||||
file->filePos = pos;
|
file->filePos = pos;
|
||||||
} else if (result.unixError == 0) {
|
} else if (result.unixError == 0) {
|
||||||
@@ -266,13 +266,13 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto doWrite = [&](off64_t pos) {
|
auto doWrite = [&](off_t pos) {
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
size_t remaining = bytesToWrite;
|
size_t remaining = bytesToWrite;
|
||||||
const uint8_t *in = static_cast<const uint8_t *>(buffer);
|
const uint8_t *in = static_cast<const uint8_t *>(buffer);
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
size_t chunk = remaining > SSIZE_MAX ? SSIZE_MAX : remaining;
|
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 (rc == -1) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
@@ -292,10 +292,10 @@ IOResult write(FileObject *file, const void *buffer, size_t bytesToWrite, const
|
|||||||
|
|
||||||
if (updateFilePointer || !offset.has_value()) {
|
if (updateFilePointer || !offset.has_value()) {
|
||||||
std::lock_guard lk(file->m);
|
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);
|
doWrite(pos);
|
||||||
if (updateFilePointer) {
|
if (updateFilePointer) {
|
||||||
file->filePos = pos + static_cast<off64_t>(result.bytesTransferred);
|
file->filePos = pos + static_cast<off_t>(result.bytesTransferred);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
doWrite(*offset);
|
doWrite(*offset);
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ struct IOResult {
|
|||||||
void init();
|
void init();
|
||||||
std::filesystem::path pathFromWindows(const char *inStr);
|
std::filesystem::path pathFromWindows(const char *inStr);
|
||||||
std::string pathToWindows(const std::filesystem::path &path);
|
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);
|
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);
|
bool updateFilePointer);
|
||||||
HANDLE getStdHandle(DWORD nStdHandle);
|
HANDLE getStdHandle(DWORD nStdHandle);
|
||||||
BOOL setStdHandle(DWORD nStdHandle, HANDLE hHandle);
|
BOOL setStdHandle(DWORD nStdHandle, HANDLE hHandle);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "common.h"
|
|
||||||
#include "async_io.h"
|
#include "async_io.h"
|
||||||
|
#include "common.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
@@ -408,14 +408,13 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
blockUpper2GB();
|
blockUpper2GB();
|
||||||
files::init();
|
files::init();
|
||||||
wibo::processes().init();
|
|
||||||
async_io::initialize();
|
|
||||||
|
|
||||||
// Create TIB
|
// Create TIB
|
||||||
memset(&tib, 0, sizeof(tib));
|
memset(&tib, 0, sizeof(tib));
|
||||||
tib.tib = &tib;
|
tib.tib = &tib;
|
||||||
tib.peb = (PEB *)calloc(sizeof(PEB), 1);
|
tib.peb = static_cast<PEB *>(calloc(1, sizeof(PEB)));
|
||||||
tib.peb->ProcessParameters = (RTL_USER_PROCESS_PARAMETERS *)calloc(sizeof(RTL_USER_PROCESS_PARAMETERS), 1);
|
tib.peb->ProcessParameters =
|
||||||
|
static_cast<RTL_USER_PROCESS_PARAMETERS *>(calloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS)));
|
||||||
wibo::processPeb = tib.peb;
|
wibo::processPeb = tib.peb;
|
||||||
wibo::initializeTibStackInfo(&tib);
|
wibo::initializeTibStackInfo(&tib);
|
||||||
if (!wibo::installTibForCurrentThread(&tib)) {
|
if (!wibo::installTibForCurrentThread(&tib)) {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ bool ProcessManager::init() {
|
|||||||
|
|
||||||
mRunning.store(true, std::memory_order_release);
|
mRunning.store(true, std::memory_order_release);
|
||||||
mThread = std::thread(&ProcessManager::runLoop, this);
|
mThread = std::thread(&ProcessManager::runLoop, this);
|
||||||
|
DEBUG_LOG("ProcessManager initialized\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ void ProcessManager::wake() const {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint64_t n = 1;
|
uint64_t n = 1;
|
||||||
write(mWakeFd, &n, sizeof(n));
|
ssize_t r [[maybe_unused]] = write(mWakeFd, &n, sizeof(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessManager::checkPidfd(int pidfd) {
|
void ProcessManager::checkPidfd(int pidfd) {
|
||||||
@@ -212,6 +213,10 @@ void ProcessManager::checkPidfd(int pidfd) {
|
|||||||
|
|
||||||
ProcessManager &processes() {
|
ProcessManager &processes() {
|
||||||
static ProcessManager mgr;
|
static ProcessManager mgr;
|
||||||
|
if (!mgr.init()) {
|
||||||
|
fprintf(stderr, "Failed to initialize ProcessManager\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
return mgr;
|
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; }
|
uint16_t primaryLang(uint16_t lang) { return lang & 0x3FFu; }
|
||||||
|
|
||||||
const ImageResourceDirectoryEntry *selectLanguageEntry(const ImageResourceDirectory *dir, const uint8_t *base,
|
const ImageResourceDirectoryEntry *selectLanguageEntry(const ImageResourceDirectory *dir,
|
||||||
uint32_t rsrcSize, std::optional<uint16_t> desired,
|
std::optional<uint16_t> desired, uint16_t &chosenLang) {
|
||||||
uint16_t &chosenLang) {
|
|
||||||
const auto *entries = resourceEntries(dir);
|
const auto *entries = resourceEntries(dir);
|
||||||
uint16_t total = dir->numberOfNamedEntries + dir->numberOfIdEntries;
|
uint16_t total = dir->numberOfNamedEntries + dir->numberOfIdEntries;
|
||||||
const ImageResourceDirectoryEntry *primaryMatch = nullptr;
|
const ImageResourceDirectoryEntry *primaryMatch = nullptr;
|
||||||
@@ -172,7 +171,7 @@ bool Executable::findResource(const ResourceIdentifier &type, const ResourceIden
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint16_t chosenLang = language.value_or(0);
|
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) {
|
if (!langEntry) {
|
||||||
wibo::lastError = ERROR_RESOURCE_LANG_NOT_FOUND;
|
wibo::lastError = ERROR_RESOURCE_LANG_NOT_FOUND;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user