Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IO: implement process wrapper for win32 #14

Merged
merged 7 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 34 additions & 32 deletions io/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@

set(WIN32_SOURCES
win32/file.cpp
win32/mmap.cpp
win32/winapi_category.cpp
win32/error_codes.cpp
win32/path.h
win32/winapi_helpers.h)

set(POSIX_SOURCES
posix/file.cpp
posix/mmap.cpp
posix/helpers.h)

if (AW_CAPABILITIES_WIN32)
list(APPEND SOURCES ${WIN32_SOURCES})
endif()

if (AW_CAPABILITIES_POSIX)
list(APPEND SOURCES ${POSIX_SOURCES})
endif()

aw_add_library(awio SHARED
GLOB_HEADERS
SOURCES
${SOURCES}
EXPORT_NAME
io
)

target_compile_definitions(awio PRIVATE AW_MODULE_IO)
target_link_libraries(awio awutils)

set(WIN32_SOURCES
win32/error_codes.c++
win32/file.c++
win32/mmap.c++
win32/path.h
win32/process.c++
win32/winapi_category.c++
win32/winapi_helpers.h)

set(POSIX_SOURCES
posix/file.c++
posix/helpers.h
posix/mmap.c++
posix/process.c++)

if (AW_CAPABILITIES_WIN32)
list(APPEND SOURCES ${WIN32_SOURCES})
endif()

if (AW_CAPABILITIES_POSIX)
list(APPEND SOURCES ${POSIX_SOURCES})
endif()

aw_add_library(awio SHARED
GLOB_HEADERS
SOURCES
${SOURCES}
EXPORT_NAME
io
)

target_compile_definitions(awio PRIVATE AW_MODULE_IO)
target_link_libraries(awio awutils)
2 changes: 1 addition & 1 deletion io/include/aw/io/mmap_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct mmap_file {
: _file{fd}
{
if (!ec)
create_mapping( ec, perms );
create_mapping( ec, perms );
}

mmap_file(fs::path const& path, map_perms perms = map_perms::rdwr)
Expand Down
81 changes: 81 additions & 0 deletions io/include/aw/io/posix/process.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#ifndef aw_io_posix_process_h
#define aw_io_posix_process_h

#include <aw/types/array_view.h>
#include <aw/types/support/enum.h>

#include <aw/io/export.h>
#include <aw/io/wait_status.h>

#include <string>
#include <system_error>

namespace aw::io::posix {

enum class process_handle : long {};
constexpr auto invalid_process_handle = process_handle(-1L );

/*!
* Spawn a child process with specified \a path and argument list \a argv.
* Argument list must end with `nullptr`.
*/
AW_IO_EXP process_handle spawn(const char* path, aw::array_view<char*> argv, std::error_code& ec) noexcept;
/*!
* Spawn a child process with specified argument list \a argv. `argv[0]` is used as path.
*/
AW_IO_EXP process_handle spawn(aw::array_view<char*> argv, std::error_code& ec) noexcept;

inline process_handle spawn(const char* path, aw::array_view<char*> argv)
{
std::error_code ec;
return spawn(path, argv, ec);
}
inline process_handle spawn(aw::array_view<char*> argv)
{
std::error_code ec;
return spawn(argv, ec);
}
AW_IO_EXP process_handle spawn(std::string path, aw::array_ref<std::string> argv, std::error_code& ec);
AW_IO_EXP process_handle spawn(std::string path, aw::array_ref<std::string> argv)
{
std::error_code ec;
return spawn(path, argv, ec);
}


AW_IO_EXP wait_status wait(process_handle pid, std::error_code& ec) noexcept;
inline wait_status wait(process_handle pid)
{
std::error_code ec;
return wait(pid, ec);
}

AW_IO_EXP int kill(process_handle pid, int signal, std::error_code& ec) noexcept;
inline int kill(process_handle pid, int signal)
{
std::error_code ec;
return kill(pid, signal, ec);
}


inline wait_status run(std::string path, aw::array_ref<std::string> argv, std::error_code& ec)
{
auto handle = spawn(path, argv, ec);
if (handle == invalid_process_handle)
return wait_status::failed;

return wait(handle, ec);
}

inline wait_status run(std::string path, aw::array_ref<std::string> argv)
{
std::error_code ec;
return run(path, argv, ec);
}

inline std::string executable_name(std::string path)
{
return path;
}
} // namespace aw::io::posix
#endif // aw_io_posix_process_h
40 changes: 40 additions & 0 deletions io/include/aw/io/process.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2016 absurdworlds
*
* License LGPLv3 or later:
* GNU Lesser GPL version 3 <http://gnu.org/licenses/lgpl-3.0.html>
* This is free software: you are free to change and redistribute it.
* There is NO WARRANTY, to the extent permitted by law.
*/
#ifndef aw_platform_process_h
#define aw_platform_process_h
#include <aw/io/export.h>
#include <aw/types/array_view.h>

#if defined(AW_SUPPORT_PLATFORM_WIN32)
#include "win32/process.h"
#endif
#if defined(AW_SUPPORT_PLATFORM_POSIX)
#include "posix/process.h"
#endif

namespace aw::io {
#if (AW_PLATFORM == AW_PLATFORM_POSIX)
using posix::process_handle;
using posix::invalid_process_handle;
using posix::spawn;
using posix::kill;
using posix::wait;
using posix::run;
using posix::executable_name;
#elif (AW_PLATFORM == AW_PLATFORM_WIN32)
using win32::invalid_process_handle;
using win32::process_handle;
using win32::spawn;
using win32::kill;
using win32::wait;
using win32::run;
using win32::executable_name;
#endif
} // namespace aw::platform
#endif//aw_platform_process_h
15 changes: 15 additions & 0 deletions io/include/aw/io/wait_status.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef aw_io_wait_status_h
#define aw_io_wait_status_h

namespace aw::io {

enum class wait_status {
finished,
timeout,
failed,
};

} // namespace aw::io


#endif // aw_io_wait_status_h
47 changes: 47 additions & 0 deletions io/include/aw/io/win32/detail/handle_holder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef aw_io_handle_holder_h
#define aw_io_handle_holder_h

#include <aw/types/types.h>

#include <aw/io/export.h>

#include <utility>

namespace aw::io::win32::detail {

AW_IO_EXP
void close_handle( uintptr_t handle );

template<typename Handle>
class handle_holder {
public:
handle_holder( Handle handle )
: handle( handle )
{}

handle_holder(const handle_holder& other) = delete;
handle_holder(handle_holder&& other)
: handle(std::exchange(other.handle, Handle(0)))
{
}

~handle_holder() { close_handle(handle); }

handle_holder& operator=(const handle_holder& other) = delete;
handle_holder& operator=(handle_holder&& other)
{
close_handle(handle);
handle = std::exchange(other.handle, Handle(0));
return *this;
}

operator Handle() { return static_cast<Handle>(handle); }

private:
Handle handle;
};


} // namespace aw::io::win32::detail

#endif // aw_io_handle_holder_h
96 changes: 96 additions & 0 deletions io/include/aw/io/win32/process.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#ifndef aw_io_win32_process_h
#define aw_io_win32_process_h

#include "detail/handle_holder.h"

#include <aw/types/array_view.h>
#include <aw/types/support/enum.h>

#include <aw/io/wait_status.h>

#include <string>
#include <chrono>
#include <system_error>

namespace aw::io::win32 {
enum class process_handle : uintptr_t {};
constexpr auto invalid_process_handle = process_handle(-1);

using process_holder = detail::handle_holder<process_handle>;
using timeout_spec_ms = std::optional<std::chrono::milliseconds>;

inline void close_handle(process_handle handle)
{
detail::close_handle( underlying(handle) );
}

/*!
* Spawn a child process with specified \a path and argument list \a argv.
* Argument list must end with `nullptr`.
*/
AW_IO_EXP process_holder spawn(const char* path, aw::array_view<const char*> argv, std::error_code& ec) noexcept;
/*!
* Spawn a child process with specified argument list \a argv. `argv[0]` is used as path.
*/
AW_IO_EXP process_holder spawn(aw::array_view<const char*> argv, std::error_code& ec) noexcept;

inline process_holder spawn(const char* path, aw::array_view<const char*> argv)
{
std::error_code ec;
return spawn(path, argv, ec);
}
inline process_holder spawn(aw::array_view<const char*> argv)
{
std::error_code ec;
return spawn(argv, ec);
}

AW_IO_EXP process_holder spawn(std::string path, aw::array_view<std::string> argv, std::error_code& ec);
inline process_holder spawn(std::string path, aw::array_view<std::string> argv)
{
std::error_code ec;
return spawn(path, argv, ec);
}

AW_IO_EXP wait_status wait(process_handle pid, std::error_code& ec, timeout_spec_ms timeout = {}) noexcept;
inline wait_status wait(process_handle pid, timeout_spec_ms timeout = {})
{
std::error_code ec;
return wait(pid, ec, timeout);
}

AW_IO_EXP int kill(process_handle pid, int signal, std::error_code& ec) noexcept;
inline int kill(process_handle pid, int signal)
{
std::error_code ec;
return kill(pid, signal, ec);
}

inline wait_status run(
std::string path,
aw::array_view<std::string> argv,
std::error_code& ec,
timeout_spec_ms timeout = {})
{
auto handle = spawn(path, argv, ec);
if (handle == invalid_process_handle)
return wait_status::failed;

return wait(handle, ec, timeout);
}

inline wait_status run(std::string path, aw::array_view<std::string> argv, timeout_spec_ms timeout = {})
{
std::error_code ec;
return run(path, argv, ec, timeout);
}

inline std::string executable_name(std::string path)
{
if (!path.ends_with(".exe"))
path += ".exe";
return path;
}
} // namespace aw::io::win32

#endif // aw_io_win32_process_h
File renamed without changes.
File renamed without changes.
Loading
Loading