upd: [ipc] allow shm error codes to be passed out

This commit is contained in:
mutouyun 2022-11-06 18:22:36 +08:00
parent 375c25bd1e
commit 03dce063f9
4 changed files with 74 additions and 53 deletions

View File

@ -17,23 +17,25 @@
LIBIMP_NAMESPACE_BEG_
using result_type = std::uint64_t;
/**
* @brief Use the least significant (in Little-Endian) of
* a 64-bit unsigned integer to indicate success or failure,
* so the data significant bit cannot exceed 63 bits.
*/
class LIBIMP_EXPORT result_code {
std::uint64_t status_;
result_type status_;
public:
result_code() noexcept;
result_code(std::uint64_t value) noexcept;
result_code(bool ok, std::uint64_t value) noexcept;
result_code(result_type value) noexcept;
result_code(bool ok, result_type value) noexcept;
std::uint64_t value() const noexcept;
result_type value() const noexcept;
bool ok() const noexcept;
std::uint64_t operator*() const noexcept {
result_type operator*() const noexcept {
return value();
}
explicit operator bool() const noexcept {
@ -62,10 +64,10 @@ template <typename T>
struct default_traits<T, std::enable_if_t<std::is_integral<T>::value>> {
constexpr static T value() noexcept { return 0; }
static std::uint64_t cast_to_code(T value) noexcept {
return static_cast<std::uint64_t>(value);
static result_type cast_to_code(T value) noexcept {
return static_cast<result_type>(value);
}
static T cast_from_code(std::uint64_t code) noexcept {
static T cast_from_code(result_type code) noexcept {
return static_cast<T>(code);
}
template <typename Out>
@ -78,10 +80,10 @@ template <typename T>
struct default_traits<T, std::enable_if_t<std::is_pointer<T>::value>> {
constexpr static T value() noexcept { return nullptr; }
static std::uint64_t cast_to_code(T value) noexcept {
return reinterpret_cast<std::uint64_t>(value);
static result_type cast_to_code(T value) noexcept {
return reinterpret_cast<result_type>(value);
}
static T cast_from_code(std::uint64_t code) noexcept {
static T cast_from_code(result_type code) noexcept {
return reinterpret_cast<T>(code);
}
template <typename Out>
@ -89,7 +91,7 @@ struct default_traits<T, std::enable_if_t<std::is_pointer<T>::value>> {
if LIBIMP_LIKELY(r) {
return format_to(out, "{}", static_cast<void *>(*r));
}
return format_to(out, "{}, code = {}", static_cast<void *>(*r), r.code());
return format_to(out, "{}, code = {}", static_cast<void *>(*r), r.code_value());
}
};
@ -137,12 +139,12 @@ public:
: code_(default_traits_t::value() != value,
default_traits_t::cast_to_code(value)) {}
result(std::nullptr_t, std::uint64_t code) noexcept
result(std::nullptr_t, result_type code) noexcept
: code_(false, code) {}
T value() const noexcept { return code_.ok() ? default_traits_t::cast_from_code(code_.value()) : nullptr; }
bool ok() const noexcept { return code_.ok(); }
std::uint64_t code() const noexcept { return code_.value(); }
result_type code_value() const noexcept { return code_.value(); }
T operator*() const noexcept {
return value();
@ -171,7 +173,7 @@ struct fmt::formatter<::LIBIMP_::result<T, D>> {
template <>
struct fmt::formatter<::LIBIMP_::result_code>
: formatter<::LIBIMP_::result<std::uint64_t>> {
: formatter<::LIBIMP_::result<::LIBIMP_::result_type>> {
template <typename FormatContext>
auto format(::LIBIMP_::result_code r, FormatContext &ctx) {
return format_to(ctx.out(), "[{}, value = {}]", (r ? "succ" : "fail"), *r);

View File

@ -25,7 +25,9 @@ namespace sys {
*/
result_code error_code() noexcept {
auto err = ::GetLastError();
if (err == ERROR_SUCCESS) return {true};
if (err == ERROR_SUCCESS) {
return {ERROR_SUCCESS};
}
return {false, std::uint64_t(err)};
}
@ -82,7 +84,7 @@ std::string error_str(result_code code) noexcept {
* https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo
* https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getnativesysteminfo
*/
std::int64_t conf(info r) noexcept {
result<std::int64_t> conf(info r) noexcept {
LIBIMP_LOG_();
switch (r) {
case info::page_size: {
@ -92,7 +94,7 @@ std::int64_t conf(info r) noexcept {
}
default:
log.error("invalid info = {}", enum_cast(r));
return -1;
return {};
}
}

View File

@ -33,15 +33,18 @@ namespace {
* @brief Closes an open object handle.
* @see https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
*/
void mmap_close(HANDLE h) {
result_code mmap_close(HANDLE h) {
LIBIMP_LOG_();
if (h == NULL) {
log.error("handle is null.");
return;
return {};
}
if (!::CloseHandle(h)) {
log.error("CloseHandle fails. error = {}", sys::error());
auto err = sys::error();
log.error("CloseHandle({}) fails. error = {}", h, err);
return err.code();
}
return {ERROR_SUCCESS};
}
/**
@ -57,35 +60,38 @@ void mmap_close(HANDLE h) {
*
* @return File mapping object HANDLE, NULL on error
*/
HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept {
result<HANDLE> mmap_open(std::string const &file, std::size_t size, mode::type type) noexcept {
LIBIMP_LOG_();
if (file.empty()) {
log.error("file name is empty.");
return NULL;
return {};
}
auto t_name = detail::to_tstring(file);
if (t_name.empty()) {
log.error("file name is empty. (TCHAR conversion failed)");
return NULL;
return {};
}
/// @brief Opens a named file mapping object.
auto try_open = [&]() -> HANDLE {
auto try_open = [&]() -> result<HANDLE> {
HANDLE h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, t_name.c_str());
if (h == NULL) {
log.error("OpenFileMapping fails. error = {}", sys::error());
auto err = sys::error();
log.error("OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, {}) fails. error = {}", file, err);
return {nullptr, err.value()};
}
return h;
};
/// @brief Creates or opens a named or unnamed file mapping object for a specified file.
auto try_create = [&]() -> HANDLE {
auto try_create = [&]() -> result<HANDLE> {
HANDLE h = ::CreateFileMapping(INVALID_HANDLE_VALUE, detail::get_sa(), PAGE_READWRITE | SEC_COMMIT,
/// @remark dwMaximumSizeHigh always 0 here.
0, static_cast<DWORD>(size), t_name.c_str());
if (h == NULL) {
log.error("CreateFileMapping fails. error = {}", sys::error());
return NULL;
auto err = sys::error();
log.error("CreateFileMapping(PAGE_READWRITE | SEC_COMMIT, {}, {}) fails. error = {}", size, file, err);
return {nullptr, err.value()};
}
return h;
};
@ -99,15 +105,16 @@ HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noe
return try_open();
} else if (!(type & mode::create)) {
log.error("mode type is invalid. type = {}", type);
return NULL;
return {};
}
HANDLE h = try_create();
auto h = try_create();
if (!h) return h;
/// @remark If the object exists before the function call, the function returns a handle to the existing object
/// (with its current size, not the specified size), and GetLastError returns ERROR_ALREADY_EXISTS.
if ((type == mode::create) && (::GetLastError() == ERROR_ALREADY_EXISTS)) {
mmap_close(h);
log.info("the file being created already exists. file = {}, type = {}", file, type);
return NULL;
mmap_close(*h);
return {};
}
return h;
}
@ -116,16 +123,17 @@ HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noe
* @brief Maps a view of a file mapping into the address space of a calling process.
* @see https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile
*/
LPVOID mmap_memof(HANDLE h) {
result<LPVOID> mmap_memof(HANDLE h) {
LIBIMP_LOG_();
if (h == NULL) {
log.error("handle is null.");
return NULL;
return {};
}
LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (h == NULL) {
log.error("MapViewOfFile fails. error = {}", sys::error());
return NULL;
if (mem == NULL) {
auto err = sys::error();
log.error("MapViewOfFile({}, FILE_MAP_ALL_ACCESS) fails. error = {}", h, err);
return {nullptr, err.value()};
}
return mem;
}
@ -134,16 +142,17 @@ LPVOID mmap_memof(HANDLE h) {
* @brief Retrieves the size about a range of pages in the virtual address space of the calling process.
* @see https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualquery
*/
SIZE_T mmap_sizeof(LPCVOID mem) {
result<SIZE_T> mmap_sizeof(LPCVOID mem) {
LIBIMP_LOG_();
if (mem == NULL) {
log.error("memory pointer is null.");
return 0;
return {};
}
MEMORY_BASIC_INFORMATION mem_info {};
if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) {
log.error("VirtualQuery fails. error = {}", sys::error());
return 0;
auto err = sys::error();
log.error("VirtualQuery({}) fails. error = {}", mem, err);
return {false, (SIZE_T)err.value()};
}
return mem_info.RegionSize;
}
@ -152,20 +161,20 @@ SIZE_T mmap_sizeof(LPCVOID mem) {
* @brief Unmaps a mapped view of a file from the calling process's address space.
* @see https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-unmapviewoffile
*/
void mmap_release(HANDLE h, LPCVOID mem) {
result_code mmap_release(HANDLE h, LPCVOID mem) {
LIBIMP_LOG_();
if (h == NULL) {
log.error("handle is null.");
return;
return {};
}
if (mem == NULL) {
log.error("memory pointer is null.");
return;
return {};
}
if (!::UnmapViewOfFile(mem)) {
log.warning("UnmapViewOfFile fails. error = {}", sys::error());
}
mmap_close(h);
return mmap_close(h);
}
} // namespace

View File

@ -22,13 +22,21 @@ result<shm_t> shm_open(std::string name, std::size_t size, mode::type type) noex
auto h = mmap_open(name, size, type);
if (h == NULL) {
log.error("mmap_open failed.");
return {nullptr, *sys::error_code()};
return {nullptr, h.code_value()};
}
auto mem = mmap_memof(h);
if (mem == NULL) {
log.warning("mmap_memof failed.");
auto mem = mmap_memof(*h);
if (*mem == NULL) {
log.error("mmap_memof failed.");
mmap_close(*h);
return {nullptr, mem.code_value()};
}
return new shm_handle{std::move(name), mmap_sizeof(mem), mem, h};
auto sz = mmap_sizeof(*mem);
if (!sz) {
log.error("mmap_sizeof failed.");
mmap_close(*h);
return {nullptr, static_cast<result_type>(sz.value())};
}
return new shm_handle{std::move(name), *sz, *mem, *h};
}
result_code shm_close(shm_t h) noexcept {
@ -38,9 +46,9 @@ result_code shm_close(shm_t h) noexcept {
return {};
}
auto shm = static_cast<shm_handle *>(h);
mmap_release(shm->h_fmap, shm->memp);
auto ret = mmap_release(shm->h_fmap, shm->memp);
delete shm;
return {0};
return ret;
}
LIBIPC_NAMESPACE_END_