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

View File

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

View File

@ -33,15 +33,18 @@ namespace {
* @brief Closes an open object handle. * @brief Closes an open object handle.
* @see https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle * @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_(); LIBIMP_LOG_();
if (h == NULL) { if (h == NULL) {
log.error("handle is null."); log.error("handle is null.");
return; return {};
} }
if (!::CloseHandle(h)) { 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 * @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_(); LIBIMP_LOG_();
if (file.empty()) { if (file.empty()) {
log.error("file name is empty."); log.error("file name is empty.");
return NULL; return {};
} }
auto t_name = detail::to_tstring(file); auto t_name = detail::to_tstring(file);
if (t_name.empty()) { if (t_name.empty()) {
log.error("file name is empty. (TCHAR conversion failed)"); log.error("file name is empty. (TCHAR conversion failed)");
return NULL; return {};
} }
/// @brief Opens a named file mapping object. /// @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()); HANDLE h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, t_name.c_str());
if (h == NULL) { 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; return h;
}; };
/// @brief Creates or opens a named or unnamed file mapping object for a specified file. /// @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, HANDLE h = ::CreateFileMapping(INVALID_HANDLE_VALUE, detail::get_sa(), PAGE_READWRITE | SEC_COMMIT,
/// @remark dwMaximumSizeHigh always 0 here. /// @remark dwMaximumSizeHigh always 0 here.
0, static_cast<DWORD>(size), t_name.c_str()); 0, static_cast<DWORD>(size), t_name.c_str());
if (h == NULL) { if (h == NULL) {
log.error("CreateFileMapping fails. error = {}", sys::error()); auto err = sys::error();
return NULL; log.error("CreateFileMapping(PAGE_READWRITE | SEC_COMMIT, {}, {}) fails. error = {}", size, file, err);
return {nullptr, err.value()};
} }
return h; return h;
}; };
@ -99,15 +105,16 @@ HANDLE mmap_open(std::string const &file, std::size_t size, mode::type type) noe
return try_open(); return try_open();
} else if (!(type & mode::create)) { } else if (!(type & mode::create)) {
log.error("mode type is invalid. type = {}", type); 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 /// @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. /// (with its current size, not the specified size), and GetLastError returns ERROR_ALREADY_EXISTS.
if ((type == mode::create) && (::GetLastError() == 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); log.info("the file being created already exists. file = {}, type = {}", file, type);
return NULL; mmap_close(*h);
return {};
} }
return h; 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. * @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 * @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_(); LIBIMP_LOG_();
if (h == NULL) { if (h == NULL) {
log.error("handle is null."); log.error("handle is null.");
return NULL; return {};
} }
LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0); LPVOID mem = ::MapViewOfFile(h, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (h == NULL) { if (mem == NULL) {
log.error("MapViewOfFile fails. error = {}", sys::error()); auto err = sys::error();
return NULL; log.error("MapViewOfFile({}, FILE_MAP_ALL_ACCESS) fails. error = {}", h, err);
return {nullptr, err.value()};
} }
return mem; 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. * @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 * @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_(); LIBIMP_LOG_();
if (mem == NULL) { if (mem == NULL) {
log.error("memory pointer is null."); log.error("memory pointer is null.");
return 0; return {};
} }
MEMORY_BASIC_INFORMATION mem_info {}; MEMORY_BASIC_INFORMATION mem_info {};
if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) { if (::VirtualQuery(mem, &mem_info, sizeof(mem_info)) == 0) {
log.error("VirtualQuery fails. error = {}", sys::error()); auto err = sys::error();
return 0; log.error("VirtualQuery({}) fails. error = {}", mem, err);
return {false, (SIZE_T)err.value()};
} }
return mem_info.RegionSize; 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. * @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 * @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_(); LIBIMP_LOG_();
if (h == NULL) { if (h == NULL) {
log.error("handle is null."); log.error("handle is null.");
return; return {};
} }
if (mem == NULL) { if (mem == NULL) {
log.error("memory pointer is null."); log.error("memory pointer is null.");
return; return {};
} }
if (!::UnmapViewOfFile(mem)) { if (!::UnmapViewOfFile(mem)) {
log.warning("UnmapViewOfFile fails. error = {}", sys::error()); log.warning("UnmapViewOfFile fails. error = {}", sys::error());
} }
mmap_close(h); return mmap_close(h);
} }
} // namespace } // 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); auto h = mmap_open(name, size, type);
if (h == NULL) { if (h == NULL) {
log.error("mmap_open failed."); log.error("mmap_open failed.");
return {nullptr, *sys::error_code()}; return {nullptr, h.code_value()};
} }
auto mem = mmap_memof(h); auto mem = mmap_memof(*h);
if (mem == NULL) { if (*mem == NULL) {
log.warning("mmap_memof failed."); 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 { result_code shm_close(shm_t h) noexcept {
@ -38,9 +46,9 @@ result_code shm_close(shm_t h) noexcept {
return {}; return {};
} }
auto shm = static_cast<shm_handle *>(h); 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; delete shm;
return {0}; return ret;
} }
LIBIPC_NAMESPACE_END_ LIBIPC_NAMESPACE_END_