From 19da7f25dcbacb2f28363386e3e68d70ff48451e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Wa=C3=9Fmuth?= Date: Tue, 19 Apr 2022 17:33:42 +0200 Subject: [PATCH 1/4] Set minimum supported Windows version to 10 (Windows 10) --- example/CMakeLists.txt | 8 ++++++++ src/CMakeLists.txt | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 937adb3..edc26a6 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -48,5 +48,13 @@ foreach( SOURCEFILE ${EXAMPLE_SOURCES} ) # Add the necessary external library references target_link_libraries( ${SOURCEFILE} anyrpc ${ASAN_LIBRARY} ${LOG4CPLUS_LIBRARIES} ${MSGPACK_LIBRARIES}) + + if (WIN32) + target_compile_definitions(${SOURCEFILE} + PRIVATE + WINVER=0x0A00 + _WIN32_WINNT=0x0A00 + ) + endif () endforeach () diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4fd6e0f..38abe1a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,12 @@ target_link_libraries( anyrpc ${ASAN_LIBRARY} ${LOG4CPLUS_LIBRARIES}) # Need the winsock library for Windows if (WIN32) target_link_libraries(anyrpc ws2_32) + + target_compile_definitions(anyrpc + PRIVATE + WINVER=0x0A00 + _WIN32_WINNT=0x0A00 + ) endif () set_target_properties( anyrpc PROPERTIES VERSION ${ANYRPC_VERSION} SOVERSION ${ANYRPC_VERSION_MAJOR} ) From 9af1956b1a6ce1448292010b655594193a4d9ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Wa=C3=9Fmuth?= Date: Tue, 19 Apr 2022 15:28:01 +0200 Subject: [PATCH 2/4] Remove obsolete MinGW special cases Code builds well with MinGW-W64-builds-4.2.0 and later --- include/anyrpc/connection.h | 6 +----- include/anyrpc/internal/time.h | 4 ---- include/anyrpc/server.h | 21 +++------------------ src/internal/time.cpp | 17 ++--------------- src/socket.cpp | 10 +++------- 5 files changed, 9 insertions(+), 49 deletions(-) diff --git a/include/anyrpc/connection.h b/include/anyrpc/connection.h index 3e0d6a7..9fab969 100644 --- a/include/anyrpc/connection.h +++ b/include/anyrpc/connection.h @@ -22,11 +22,7 @@ #define ANYRPC_CONNECTION_H_ #if defined(ANYRPC_THREADING) -# if defined(__MINGW32__) -# include "internal/mingw.thread.h" -# else -# include -# endif // defined(__MINGW32__) +# include #endif // defined(ANYRPC_THREADING) #if defined(ANYRPC_REGEX) diff --git a/include/anyrpc/internal/time.h b/include/anyrpc/internal/time.h index b5cc371..a0759c2 100644 --- a/include/anyrpc/internal/time.h +++ b/include/anyrpc/internal/time.h @@ -32,10 +32,6 @@ namespace anyrpc int gettimeofday(struct timeval * tp, struct timezone * tzp); #endif -#if defined(__MINGW32__) -struct tm* localtime_r(const time_t *timep, struct tm *result); -#endif - //! Compute the difference between the two times in milliseconds ANYRPC_API int MilliTimeDiff(struct timeval &time1, struct timeval &time2); diff --git a/include/anyrpc/server.h b/include/anyrpc/server.h index c989a4d..eabeb7f 100644 --- a/include/anyrpc/server.h +++ b/include/anyrpc/server.h @@ -22,24 +22,9 @@ #define ANYRPC_SERVER_H_ #if defined(ANYRPC_THREADING) -# if defined(__MINGW32__) -// These constants are not defined for mingw but are needed in the following libraries -# ifndef EOWNERDEAD -# define EOWNERDEAD 133 /* File too big */ -# endif -# ifndef EPROTO -# define EPROTO 134 /* Protocol error */ -# endif - -# include "internal/mingw.thread.h" -# include -# include "internal/mingw.mutex.h" -# include "internal/mingw.condition_variable.h" -# else -# include -# include -# include -# endif //defined(__MINGW32__) +# include +# include +# include #endif //defined(ANYRPC_THREADING) namespace anyrpc diff --git a/src/internal/time.cpp b/src/internal/time.cpp index 2a76af2..a1c9962 100644 --- a/src/internal/time.cpp +++ b/src/internal/time.cpp @@ -26,11 +26,8 @@ #include #endif -#if defined(_MSC_VER) -#elif defined(__MINGW32__) -#include -#else -#include +#if !defined(_MSC_VER) +# include #endif namespace anyrpc @@ -57,16 +54,6 @@ int gettimeofday(struct timeval * tp, struct timezone * tzp) } #endif -#if defined(__MINGW32__) -struct tm* localtime_r(const time_t *timep, struct tm *result) -{ - // with Windows localtime is threadsafe since the pointer is to thread local storage - struct tm *t=localtime(timep); - memcpy(result,t,sizeof(struct tm)); - return result; -} -#endif - int MilliTimeDiff( struct timeval &time1, struct timeval &time2 ) { return (time1.tv_sec - time2.tv_sec) * 1000 + (time1.tv_usec - time2.tv_usec)/1000; diff --git a/src/socket.cpp b/src/socket.cpp index e8096d8..1e416d6 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -98,7 +98,7 @@ int Socket::SetKeepAlive(int param) int Socket::SetKeepAliveInterval(int startTime, int interval, int probeCount) { log_debug( "SetKeepAliveInterval: startTime=" << startTime << ", interval=" << interval << ", probeCount=" << probeCount); -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) DWORD outBytes; tcp_keepalive tcp_ka; tcp_ka.onoff = 1; @@ -109,7 +109,7 @@ int Socket::SetKeepAliveInterval(int startTime, int interval, int probeCount) if (result < 0) log_debug( "SetKeepAliveInterval: result = " << result ); return result; -#elif defined(__MINGW32__) || defined(__CYGWIN__) +#elif defined(__CYGWIN__) // don't see how this can be performed right now #elif (__APPLE__) int result = setsockopt( fd_, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&startTime, sizeof(startTime) ); @@ -554,15 +554,11 @@ bool UdpSocket::Receive(char* buffer, int maxLength, int &bytesRead, bool &eof, port = ntohs(receiveAddr.sin_port); -#if defined(__MINGW32__) - // should be thread-safe since it would use the Windows call - ipAddress = inet_ntoa(receiveAddr.sin_addr); -#else // Only need this buffer to perform the address conversion in a thread-safe call const unsigned bufferLength = 100; char addrBuffer[bufferLength]; ipAddress = inet_ntop(AF_INET,&receiveAddr.sin_addr, addrBuffer, bufferLength); -#endif + log_debug("Udp Receive: address=" << ipAddress << ", port=" << port); eof = (numBytes == 0); From 4c30bb6d90680e16fde0211e228f385883c463a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Wa=C3=9Fmuth?= Date: Tue, 19 Apr 2022 16:37:33 +0200 Subject: [PATCH 3/4] Fix missing find_package_handle_standard_args for the "else" case --- cmake/FindLog4cplus.cmake | 6 +++--- cmake/FindMsgpack.cmake | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/FindLog4cplus.cmake b/cmake/FindLog4cplus.cmake index ee52df3..d350c66 100644 --- a/cmake/FindLog4cplus.cmake +++ b/cmake/FindLog4cplus.cmake @@ -61,12 +61,12 @@ else () endif () +# needed to use find_package_handle_standard_args +include(FindPackageHandleStandardArgs) + if (LOG4CPLUS_INCLUDE_DIR) # set the correct variable name for the header directories set(LOG4CPLUS_INCLUDE_DIRS ${LOG4CPLUS_INCLUDE_DIR}) - - # needed to use find_package_handle_standard_args - include(FindPackageHandleStandardArgs) if (LOG4CPLUS_LIBRARY_RELEASE AND LOG4CPLUS_LIBRARY_DEBUG) # set the libaries varible to use the release and debug versions diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake index 6fc128d..f399dbb 100644 --- a/cmake/FindMsgpack.cmake +++ b/cmake/FindMsgpack.cmake @@ -61,13 +61,13 @@ else () endif () +# needed to use find_package_handle_standard_args +include(FindPackageHandleStandardArgs) + if (MSGPACK_INCLUDE_DIR) # set the correct variable name for the header directories set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR}) - # needed to use find_package_handle_standard_args - include(FindPackageHandleStandardArgs) - if (MSGPACK_LIBRARY_RELEASE AND MSGPACK_LIBRARY_DEBUG) # set the libaries varible to use the release and debug versions find_package_handle_standard_args(MSGPACK DEFAULT_MSG MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY_RELEASE MSGPACK_LIBRARY_DEBUG) From a703f8f80d64893491975a9c116c1092abc4c1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Wa=C3=9Fmuth?= Date: Mon, 29 Aug 2022 21:09:23 +0200 Subject: [PATCH 4/4] Remove unused mingw headers --- .../internal/mingw.condition_variable.h | 185 ------------- include/anyrpc/internal/mingw.mutex.h | 244 ------------------ include/anyrpc/internal/mingw.thread.h | 126 --------- 3 files changed, 555 deletions(-) delete mode 100644 include/anyrpc/internal/mingw.condition_variable.h delete mode 100644 include/anyrpc/internal/mingw.mutex.h delete mode 100644 include/anyrpc/internal/mingw.thread.h diff --git a/include/anyrpc/internal/mingw.condition_variable.h b/include/anyrpc/internal/mingw.condition_variable.h deleted file mode 100644 index af5ac76..0000000 --- a/include/anyrpc/internal/mingw.condition_variable.h +++ /dev/null @@ -1,185 +0,0 @@ -/** -* @file condition_variable.h -* @brief std::condition_variable implementation for MinGW -* -* This file is part of the mingw-w64 runtime package. -* No warranty is given; refer to the file DISCLAIMER within this package. -*/ - -// https://github.com/meganz/mingw-std-threads - -#ifndef MINGW_CONDITIONAL_VARIABLE_H -#define MINGW_CONDITIONAL_VARIABLE_H -#include -#include -#include -namespace std -{ - -enum class cv_status { no_timeout, timeout }; -class condition_variable_any -{ -protected: - recursive_mutex mMutex; - atomic mNumWaiters; - HANDLE mSemaphore; - HANDLE mWakeEvent; -public: - typedef HANDLE native_handle_type; - native_handle_type native_handle() {return mSemaphore;} - condition_variable_any(const condition_variable_any&) = delete; - condition_variable_any& operator=(const condition_variable_any&) = delete; - condition_variable_any() - :mNumWaiters(0), mSemaphore(CreateSemaphore(NULL, 0, 0xFFFF, NULL)), - mWakeEvent(CreateEvent(NULL, FALSE, FALSE, NULL)) - {} - ~condition_variable_any() { CloseHandle(mWakeEvent); CloseHandle(mSemaphore); } -protected: - template - bool wait_impl(M& lock, DWORD timeout) - { - { - lock_guard guard(mMutex); - mNumWaiters++; - } - lock.unlock(); - DWORD ret = WaitForSingleObject(mSemaphore, timeout); - - mNumWaiters--; - SetEvent(mWakeEvent); - lock.lock(); - if (ret == WAIT_OBJECT_0) - return true; - else if (ret == WAIT_TIMEOUT) - return false; -//2 possible cases: -//1)The point in notify_all() where we determine the count to -//increment the semaphore with has not been reached yet: -//we just need to decrement mNumWaiters, but setting the event does not hurt -// -//2)Semaphore has just been released with mNumWaiters just before -//we decremented it. This means that the semaphore count -//after all waiters finish won't be 0 - because not all waiters -//woke up by acquiring the semaphore - we woke up by a timeout. -//The notify_all() must handle this grafecully -// - else - throw system_error(EPROTO, generic_category()); - } -public: - template - void wait(M& lock) - { - wait_impl(lock, INFINITE); - } - template - void wait(M& lock, Predicate pred) - { - while(!pred()) - { - wait(lock); - }; - } - - void notify_all() noexcept - { - lock_guard lock(mMutex); //block any further wait requests until all current waiters are unblocked - if (mNumWaiters.load() <= 0) - return; - - ReleaseSemaphore(mSemaphore, mNumWaiters, NULL); - while(mNumWaiters > 0) - { - auto ret = WaitForSingleObject(mWakeEvent, 1000); - if ((ret == WAIT_FAILED) || (ret == WAIT_ABANDONED)) - throw system_error(EPROTO, generic_category()); - } - assert(mNumWaiters == 0); -//in case some of the waiters timed out just after we released the -//semaphore by mNumWaiters, it won't be zero now, because not all waiters -//woke up by acquiring the semaphore. So we must zero the semaphore before -//we accept waiters for the next event -//See _wait_impl for details - while(WaitForSingleObject(mSemaphore, 0) == WAIT_OBJECT_0); - } - void notify_one() noexcept - { - lock_guard lock(mMutex); - if (!mNumWaiters) - return; - int targetWaiters = mNumWaiters.load() - 1; - ReleaseSemaphore(mSemaphore, 1, NULL); - while(mNumWaiters > targetWaiters) - { - auto ret = WaitForSingleObject(mWakeEvent, 1000); - if ((ret == WAIT_FAILED) || (ret == WAIT_ABANDONED)) - throw system_error(EPROTO, generic_category()); - } - assert(mNumWaiters == targetWaiters); - } - template - std::cv_status wait_for(M& lock, - const std::chrono::duration& rel_time) - { - long long timeout = chrono::duration_cast(rel_time).count(); - if (timeout < 0) - timeout = 0; - bool ret = wait_impl(lock, (DWORD)timeout); - return ret?cv_status::no_timeout:cv_status::timeout; - } - - template - bool wait_for(M& lock, - const std::chrono::duration& rel_time, Predicate pred) - { - wait_for(lock, rel_time); - return pred(); - } - template - cv_status wait_until (M& lock, - const chrono::time_point& abs_time) - { - return wait_for(lock, abs_time - Clock::now()); - } - template - bool wait_until (M& lock, - const std::chrono::time_point& abs_time, - Predicate pred) - { - auto time = abs_time - Clock::now(); - if (time < 0) - return pred(); - else - return wait_for(lock, time, pred); - } -}; -class condition_variable: protected condition_variable_any -{ -protected: - typedef condition_variable_any base; -public: - using base::native_handle_type; - using base::native_handle; - using base::base; - using base::notify_all; - using base::notify_one; - void wait(unique_lock &lock) - { base::wait(lock); } - template - void wait(unique_lock& lock, Predicate pred) - { base::wait(lock, pred); } - template - std::cv_status wait_for(unique_lock& lock, const std::chrono::duration& rel_time) - { return base::wait_for(lock, rel_time); } - template - bool wait_for(unique_lock& lock, const std::chrono::duration& rel_time, Predicate pred) - { return base::wait_for(lock, rel_time, pred); } - template - cv_status wait_until (unique_lock& lock, const chrono::time_point& abs_time) - { return base::wait_for(lock, abs_time); } - template - bool wait_until (unique_lock& lock, const std::chrono::time_point& abs_time, Predicate pred) - { return base::wait_until(lock, abs_time, pred); } -}; -} -#endif // MINGW_CONDITIONAL_VARIABLE_H diff --git a/include/anyrpc/internal/mingw.mutex.h b/include/anyrpc/internal/mingw.mutex.h deleted file mode 100644 index 9d60e57..0000000 --- a/include/anyrpc/internal/mingw.mutex.h +++ /dev/null @@ -1,244 +0,0 @@ -/** -* @file mingw.mutex.h -* @brief std::mutex et al implementation for MinGW -* -* This file is part of the mingw-w64 runtime package. -* No warranty is given; refer to the file DISCLAIMER within this package. -*/ - -// https://github.com/meganz/mingw-std-threads - -#ifndef WIN32STDMUTEX_H -#define WIN32STDMUTEX_H - -#if !defined(STDTHREAD_STRICT_NONRECURSIVE_LOCKS) && !defined(NDEBUG) - #define STDTHREAD_STRICT_NONRECURSIVE_LOCKS -#endif - -namespace std -{ -class recursive_mutex -{ -protected: - CRITICAL_SECTION mHandle; -public: - typedef LPCRITICAL_SECTION native_handle_type; - native_handle_type native_handle() {return &mHandle;} - recursive_mutex() noexcept - { - InitializeCriticalSection(&mHandle); - } - recursive_mutex (const recursive_mutex&) = delete; - ~recursive_mutex() noexcept - { - DeleteCriticalSection(&mHandle); - } - void lock() - { - EnterCriticalSection(&mHandle); - } - void unlock() - { - LeaveCriticalSection(&mHandle); - } - bool try_lock() - { - return (TryEnterCriticalSection(&mHandle)!=0); - } -}; -template -class _NonRecursiveMutex: protected B -{ -protected: - typedef B base; -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - DWORD mOwnerThread; -#endif -public: - using base::native_handle_type; - using base::native_handle; - _NonRecursiveMutex() noexcept :base() -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - , mOwnerThread(0) -#endif - {} - _NonRecursiveMutex (const _NonRecursiveMutex&) = delete; - void lock() - { - base::lock(); -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - checkSetOwnerAfterLock(); -#endif - } -protected: -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - void checkSetOwnerAfterLock() - { - DWORD self = GetCurrentThreadId(); - if (mOwnerThread == self) - { - fprintf(stderr, "FATAL: Recursive locking or non-recursive mutex detected. Throwing sysetm exception\n"); - fflush(stderr); - throw system_error(EDEADLK, generic_category()); - } - mOwnerThread = self; - } - void checkSetOwnerBeforeUnlock() - { - DWORD self = GetCurrentThreadId(); - if (mOwnerThread != self) - { - fprintf(stderr, "FATAL: Recursive unlocking of non-recursive mutex detected. Throwing system exception\n"); - fflush(stderr); - throw system_error(EDEADLK, generic_category()); - } - mOwnerThread = 0; - } -#endif -public: - void unlock() - { -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - checkSetOwnerBeforeUnlock(); -#endif - base::unlock(); - } - bool try_lock() - { - bool ret = base::try_lock(); -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - if (ret) - checkSetOwnerAfterLock(); -#endif - return ret; - } -}; - -typedef _NonRecursiveMutex mutex; - -class recursive_timed_mutex -{ -protected: - HANDLE mHandle; -public: - typedef HANDLE native_handle_type; - native_handle_type native_handle() const {return mHandle;} - recursive_timed_mutex(const recursive_timed_mutex&) = delete; - recursive_timed_mutex(): mHandle(CreateMutex(NULL, FALSE, NULL)){} - ~recursive_timed_mutex() - { - CloseHandle(mHandle); - } - void lock() - { - DWORD ret = WaitForSingleObject(mHandle, INFINITE); - if (ret != WAIT_OBJECT_0) - { - if (ret == WAIT_ABANDONED) - throw system_error(EOWNERDEAD, generic_category()); - else - throw system_error(EPROTO, generic_category()); - } - } - void unlock() - { - if (!ReleaseMutex(mHandle)) - throw system_error(EDEADLK, generic_category()); - } - bool try_lock() - { - DWORD ret = WaitForSingleObject(mHandle, 0); - if (ret == WAIT_TIMEOUT) - return false; - else if (ret == WAIT_OBJECT_0) - return true; - else if (ret == WAIT_ABANDONED) - throw system_error(EOWNERDEAD, generic_category()); - else - throw system_error(EPROTO, generic_category()); - } - template - bool try_lock_for(const std::chrono::duration& dur) - { - DWORD timeout = (DWORD)chrono::duration_cast(dur).count(); - - DWORD ret = WaitForSingleObject(mHandle, timeout); - if (ret == WAIT_TIMEOUT) - return false; - else if (ret == WAIT_OBJECT_0) - return true; - else if (ret == WAIT_ABANDONED) - throw system_error(EOWNERDEAD, generic_category()); - else - throw system_error(EPROTO, generic_category()); - } - template - bool try_lock_until(const std::chrono::time_point& timeout_time) - { - return try_lock_for(timeout_time - Clock::now()); - } -}; -class timed_mutex: public _NonRecursiveMutex -{ -protected: - typedef _NonRecursiveMutex base; -public: - using base::base; - template - void try_lock_for(const std::chrono::duration& dur) - { - bool ret = base::try_lock_for(dur); -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - if (ret) - checkSetOwnerAfterLock(); -#endif - return ret; - } -public: - template - bool try_lock_until(const std::chrono::time_point& timeout_time) - { - bool ret = base::try_lock_until(timeout_time); -#ifdef STDTHREAD_STRICT_NONRECURSIVE_LOCKS - if (ret) - checkSetOwnerAfterLock(); -#endif - return ret; - } -}; -// You can use the scoped locks and other helpers that are still provided by -// In that case, you must include before inclusing this file, so that this -// file will not try to redefine them -#ifndef _GLIBCXX_MUTEX - -/// Do not acquire ownership of the mutex. -struct defer_lock_t { }; - - /// Try to acquire ownership of the mutex without blocking. -struct try_to_lock_t { }; - - /// Assume the calling thread has already obtained mutex ownership - /// and manage it. -struct adopt_lock_t { }; - -constexpr defer_lock_t defer_lock { }; -constexpr try_to_lock_t try_to_lock { }; -constexpr adopt_lock_t adopt_lock { }; - -template -class lock_guard -{ -protected: - M& mMutex; -public: - typedef M mutex_type; - lock_guard(const lock_guard&) = delete; - lock_guard& operator=(const lock_guard&) = delete; - explicit lock_guard(mutex_type& m): mMutex(m) { mMutex.lock(); } - lock_guard(mutex_type& m, std::adopt_lock_t):mMutex(m){} - ~lock_guard() { mMutex.unlock(); } -}; - -#endif -} -#endif // WIN32STDMUTEX_H diff --git a/include/anyrpc/internal/mingw.thread.h b/include/anyrpc/internal/mingw.thread.h deleted file mode 100644 index 2b0c887..0000000 --- a/include/anyrpc/internal/mingw.thread.h +++ /dev/null @@ -1,126 +0,0 @@ -/** -* @file mingw.thread.h -* @brief std::thread implementation for MinGW -* -* This file is part of the mingw-w64 runtime package. -* No warranty is given; refer to the file DISCLAIMER within this package. -*/ - -// https://github.com/meganz/mingw-std-threads - -#ifndef WIN32STDTHREAD_H -#define WIN32STDTHREAD_H - -#include -#include -#include -#include -#include -#include - -//instead of INVALID_HANDLE_VALUE _beginthreadex returns 0 -#define _STD_THREAD_INVALID_HANDLE 0 -namespace std -{ - -class thread -{ -public: - class id - { - DWORD mId; - void clear() {mId = 0;} - friend class thread; - public: - id(DWORD aId=0):mId(aId){} - bool operator==(const id& other) const {return mId == other.mId;} - }; -protected: - HANDLE mHandle; - id mThreadId; -public: - typedef HANDLE native_handle_type; - id get_id() const noexcept {return mThreadId;} - native_handle_type native_handle() const {return mHandle;} - thread(): mHandle(_STD_THREAD_INVALID_HANDLE){} - thread(thread& other) - :mHandle(other.mHandle), mThreadId(other.mThreadId) - { - other.mHandle = _STD_THREAD_INVALID_HANDLE; - other.mThreadId.clear(); - } - template - explicit thread(Function&& f, Args&&... args) - { - typedef decltype(std::bind(f, args...)) Call; - Call* call = new Call(std::bind(f, args...)); - mHandle = (HANDLE)_beginthreadex(NULL, 0, threadfunc, - (LPVOID)call, 0, (unsigned*)&(mThreadId.mId)); - } - template - static unsigned int __stdcall threadfunc(void* arg) - { - std::unique_ptr upCall(static_cast(arg)); - (*upCall)(); - return (unsigned long)0; - } - bool joinable() const {return mHandle != _STD_THREAD_INVALID_HANDLE;} - void join() - { - if (get_id() == GetCurrentThreadId()) - throw system_error(EDEADLK, generic_category()); - if (mHandle == _STD_THREAD_INVALID_HANDLE) - throw system_error(ESRCH, generic_category()); - if (!joinable()) - throw system_error(EINVAL, generic_category()); - WaitForSingleObject(mHandle, INFINITE); - CloseHandle(mHandle); - mHandle = _STD_THREAD_INVALID_HANDLE; - mThreadId.clear(); - } - - ~thread() - { - if (joinable()) - std::terminate(); - } - thread& operator=(const thread&) = delete; - thread& operator=(thread&& other) noexcept - { - if (joinable()) - std::terminate(); - swap(std::forward(other)); - return *this; - } - void swap(thread&& other) noexcept - { - std::swap(mHandle, other.mHandle); - std::swap(mThreadId.mId, other.mThreadId.mId); - } - static unsigned int hardware_concurrency() noexcept {return 1;} - void detach() - { - if (!joinable()) - throw system_error(); - mHandle = _STD_THREAD_INVALID_HANDLE; - mThreadId.clear(); - } -}; -namespace this_thread -{ - inline thread::id get_id() {return thread::id(GetCurrentThreadId());} - inline void yield() {Sleep(0);} - template< class Rep, class Period > - void sleep_for( const std::chrono::duration& sleep_duration) - { - Sleep(chrono::duration_cast(sleep_duration).count()); - } - template - void sleep_until(const std::chrono::time_point& sleep_time) - { - sleep_for(sleep_time-Clock::now()); - } -} - -} -#endif // WIN32STDTHREAD_H