diff --git a/src/xtd.core/CMakeLists.txt b/src/xtd.core/CMakeLists.txt index 5925d42e4ab6..74e8c1efdd5b 100644 --- a/src/xtd.core/CMakeLists.txt +++ b/src/xtd.core/CMakeLists.txt @@ -864,10 +864,13 @@ add_sources( src/xtd/threading/mutex.cpp src/xtd/threading/mutex_base.h src/xtd/threading/named_mutex.h + src/xtd/threading/named_semaphore.h src/xtd/threading/semaphore.cpp + src/xtd/threading/semaphore_base.h src/xtd/threading/thread.cpp src/xtd/threading/timeout.cpp src/xtd/threading/unnamed_mutex.h + src/xtd/threading/unnamed_semaphore.h src/xtd/threading/wait_handle.cpp src/xtd/environment.cpp # Must be the last file to be compiled, as the std::atexit method must be the first to be called before static variables are destroyed. ) diff --git a/src/xtd.core/src/xtd/threading/named_semaphore.h b/src/xtd.core/src/xtd/threading/named_semaphore.h new file mode 100644 index 000000000000..86e8c6119684 --- /dev/null +++ b/src/xtd.core/src/xtd/threading/named_semaphore.h @@ -0,0 +1,53 @@ +#prafma once +#include "../../../include/xtd/threading/semaphore.h" +#define __XTD_CORE_NATIVE_LIBRARY__ +#include +#undef __XTD_CORE_NATIVE_LIBRARY__ + +class xtd::threading::semaphore::named_semaphore : public semaphore_base { +public: + ~named_semaphore() {destroy();} + + intptr handle() const noexcept override { + return handle_; + } + + void handle(intptr value) override { + handle_ = value; + } + + bool create(int32 initial_count, int32 maximum_count) override { + throw invalid_operation_exception {csf_}; + } + + bool create(int32 initial_count, int32 maximum_count, const ustring& name) override { + name_ = name; + handle_ = native::named_semaphore::create(initial_count, maximum_count, name); + return handle_ != invalid_handle; + } + + void destroy() override { + if (handle_ == invalid_handle) return; + native::named_semaphore::destroy(handle_, name_); + handle_ = invalid_handle; + } + + bool open(const ustring& name) override { + name_ = name; + handle_ = native::named_semaphore::open(name); + return handle_ != invalid_handle; + } + + bool signal(bool& io_error, int32 release_count, int32& previous_count) override { + io_error = false; + return native::named_semaphore::signal(handle_, release_count, previous_count, io_error); + } + + uint32 wait(int32 milliseconds_timeout) override { + return native::named_semaphore::wait(handle_, milliseconds_timeout); + } + +private: + intptr handle_ = invalid_handle; + ustring name_; +}; diff --git a/src/xtd.core/src/xtd/threading/semaphore.cpp b/src/xtd.core/src/xtd/threading/semaphore.cpp index fbab4c92816f..2a06ccb3af06 100644 --- a/src/xtd.core/src/xtd/threading/semaphore.cpp +++ b/src/xtd.core/src/xtd/threading/semaphore.cpp @@ -1,15 +1,11 @@ -#include "../../../include/xtd/threading/semaphore.h" +#include "named_semaphore.h" +#include "unnamed_semaphore.h" #include "../../../include/xtd/argument_out_of_range_exception.h" #include "../../../include/xtd/object_closed_exception.h" #include "../../../include/xtd/invalid_operation_exception.h" #include "../../../include/xtd/io/io_exception.h" #include "../../../include/xtd/io/path_too_long_exception.h" #include "../../../include/xtd/threading/abandoned_mutex_exception.h" -#define __XTD_CORE_NATIVE_LIBRARY__ -#include -#undef __XTD_CORE_NATIVE_LIBRARY__ -#include -#include using namespace xtd; using namespace xtd::threading; diff --git a/src/xtd.core/src/xtd/threading/semaphore_base.h b/src/xtd.core/src/xtd/threading/semaphore_base.h new file mode 100644 index 000000000000..e6a9dd6f59dc --- /dev/null +++ b/src/xtd.core/src/xtd/threading/semaphore_base.h @@ -0,0 +1,16 @@ +#pragma once +#include "../../../include/xtd/threading/semaphore.h" + +class xtd::threading::semaphore::semaphore_base { +public: + virtual ~semaphore_base() = default; + + virtual intptr handle() const noexcept = 0; + virtual void handle(intptr value) = 0; + virtual bool create(int32 initial_count, int32 maximum_count) = 0; + virtual bool create(int32 initial_count, int32 maximum_count, const ustring& name) = 0; + virtual void destroy() = 0; + virtual bool open(const ustring& name) = 0; + virtual bool signal(bool& io_error, int32 release_count, int32& previous_count) = 0; + virtual uint32 wait(int32 milliseconds_timeout) = 0; +}; diff --git a/src/xtd.core/src/xtd/threading/unnamed_semaphore.h b/src/xtd.core/src/xtd/threading/unnamed_semaphore.h new file mode 100644 index 000000000000..799cab3a619a --- /dev/null +++ b/src/xtd.core/src/xtd/threading/unnamed_semaphore.h @@ -0,0 +1,77 @@ +#pragma once +#include "../../../include/xtd/threading/semaphore.h" +#include +#include + +class xtd::threading::semaphore::unnamed_semaphore : public semaphore_base { +public: + ~unnamed_semaphore() {destroy();} + + intptr handle() const noexcept override { + return handle_ ? reinterpret_cast(handle_.get()) : invalid_handle; + } + + void handle(intptr value) override { + throw invalid_operation_exception {csf_}; + } + + bool create(int32 initial_count, int32 maximum_count) override { + handle_ = std::make_shared(); + handle_->maximum_count = maximum_count; + uint32 error = 0; + for (auto index = 0; !error && index < initial_count; ++index) + error = wait(-1); + if (error) return false; + return true; + } + + bool create(int32 initial_count, int32 maximum_count, const ustring& name) override { + throw invalid_operation_exception {csf_}; + } + + void destroy() override { + if (!handle_) return; + handle_.reset(); + } + + bool open(const ustring& name) override { + throw invalid_operation_exception {csf_}; + } + + bool signal(bool& io_error, int32 release_count, int32& previous_count) override { + std::unique_lock lock(handle_->mutex); + previous_count = handle_->count; + for (int count = 0; count < release_count; ++count) { + if (handle_->count + 1 >= handle_->maximum_count) { + io_error = true; + return false; + } + handle_->count++; + handle_->condition.notify_one(); + } + return true; + } + + uint32 wait(int32 milliseconds_timeout) override { + std::unique_lock lock(handle_->mutex); + if (handle_->count == 0) return 0xFFFFFFFF; + + if (milliseconds_timeout == -1) { + handle_->condition.wait(lock); + handle_->count--; + return 0x00000000; + } + if (handle_->condition.wait_for(lock, std::chrono::milliseconds {milliseconds_timeout}) == std::cv_status::timeout) return 0x00000102; + handle_->count--; + return 0x00000000; + } + +private: + struct data { + std::condition_variable condition; + int count = 0; + int maximum_count = std::numeric_limits::max(); + std::mutex mutex; + }; + std::shared_ptr handle_; +};