Browse Source

Update mingw-std-threads

Signed-off-by: falkTX <falktx@falktx.com>
pull/128/head
falkTX 1 year ago
parent
commit
f9508024de
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
13 changed files with 124 additions and 28 deletions
  1. +1
    -1
      libs/juce5/source
  2. +21
    -2
      libs/mingw-std-threads/README.md
  3. +3
    -0
      libs/mingw-std-threads/condition_variable
  4. +3
    -0
      libs/mingw-std-threads/future
  5. +3
    -0
      libs/mingw-std-threads/invoke
  6. +10
    -1
      libs/mingw-std-threads/mingw.condition_variable.h
  7. +1
    -1
      libs/mingw-std-threads/mingw.invoke.h
  8. +18
    -2
      libs/mingw-std-threads/mingw.mutex.h
  9. +7
    -0
      libs/mingw-std-threads/mingw.shared_mutex.h
  10. +48
    -21
      libs/mingw-std-threads/mingw.thread.h
  11. +3
    -0
      libs/mingw-std-threads/mutex
  12. +3
    -0
      libs/mingw-std-threads/shared_mutex
  13. +3
    -0
      libs/mingw-std-threads/thread

+ 1
- 1
libs/juce5/source

@@ -1 +1 @@
Subproject commit 3b826a31c4127df82e23cfd12c2dd14dc77a042d
Subproject commit 176f819c681405a12e7f6ecc1e2e1af472c3ed7b

+ 21
- 2
libs/mingw-std-threads/README.md View File

@@ -18,6 +18,23 @@ This is a header-only library. To use, just include the corresponding `mingw.xxx


For example, `#include "mingw.thread.h"` replaces `#include <thread>`. For example, `#include "mingw.thread.h"` replaces `#include <thread>`.


A `CMakeLists.txt` has also been provided. You can add it to your project by using `add_subdirectory()`, and then this library can be added as your targets' dependency by using `target_link_libraries(YOUR_TARGET PRIVATE mingw_stdthreads)`. By default it just adds a include path, allowing you to include headers using angle brackets (for example `#include <mingw.thread.h>`). But you can also provide options to let it generate "std-like" headers (see next paragraph).

Using "std-like" headers
------------------------

Probably you don't really want to replace all your includes from `#include <header>` to `#include "mingw.header.h"`. So if you are using GCC or clang, here are some ways to make you happy :)

With CMake, you just need to turn on the option `MINGW_STDTHREADS_GENERATE_STDHEADERS` before adding mingw-stdthreads, something like this:
```CMake
option(MINGW_STDTHREADS_GENERATE_STDHEADERS "" ON)
add_subdirectory(mingw_stdthreads)
target_link_libraries(${TARGET} PRIVATE mingw_stdthreads)
```
When CMake generates project files, headers named in the "standard header" way will be generated and added to your include path. Then you can avoid stuffs like `mingw.thread.h`, and keep using `#include <thread>` like always. In addition, `MINGW_STDTHREADS_GENERATED_STDHEADERS` will be defined, you can use this macro to check if those generated headers are actually available.

If you aren't using CMake, you can use one of the three scripts inside [utility_scripts](utility_scripts) directory to manually generate those "std-like" headers. Note that this requires Microsoft Power Shell, so if you are cross-compiling, you would need to install Power Shell.

Compatibility Compatibility
------------- -------------


@@ -25,8 +42,10 @@ This code has been tested to work with MinGW-w64 5.3.0, but should work with any


Switching from the win32-pthread based implementation Switching from the win32-pthread based implementation
----------------------------------------------------- -----------------------------------------------------
It seems that recent versions of MinGW-w64 include a Win32 port of pthreads, and have the `std::thread`, `std::mutex`, etc. classes implemented and working based on that compatibility
layer.
It seems that recent versions of MinGW-w64 include a Win32 port of pthreads, and have the `std::thread`, `std::mutex`, etc. classes implemented and working based on that compatibility layer.

You could use the built-in pthread implementation of Mingw by using the posix compiler, eg: `x86_64-w64-mingw32-g++-posix` (for Windows 64-bit).

That is a somewhat heavier implementation, as it relies on an abstraction layer, so you may still want to use this implementation for efficiency purposes. That is a somewhat heavier implementation, as it relies on an abstraction layer, so you may still want to use this implementation for efficiency purposes.
Unfortunately you can't use this library standalone and independent of the system `<mutex>` headers, as it relies on those headers for `std::unique_lock` and other non-trivial utility classes. Unfortunately you can't use this library standalone and independent of the system `<mutex>` headers, as it relies on those headers for `std::unique_lock` and other non-trivial utility classes.
In that case you will need to edit the `c++-config.h` file of your MinGW setup and comment out the definition of _GLIBCXX_HAS_GTHREADS. In that case you will need to edit the `c++-config.h` file of your MinGW setup and comment out the definition of _GLIBCXX_HAS_GTHREADS.


+ 3
- 0
libs/mingw-std-threads/condition_variable View File

@@ -3,4 +3,7 @@


#pragma once #pragma once
#include_next <condition_variable> #include_next <condition_variable>

#if __GNUC__ < 12
#include "mingw.condition_variable.h" #include "mingw.condition_variable.h"
#endif

+ 3
- 0
libs/mingw-std-threads/future View File

@@ -3,4 +3,7 @@


#pragma once #pragma once
#include_next <future> #include_next <future>

#if __GNUC__ < 12
#include "mingw.future.h" #include "mingw.future.h"
#endif

+ 3
- 0
libs/mingw-std-threads/invoke View File

@@ -3,4 +3,7 @@


#pragma once #pragma once
#include_next <invoke> #include_next <invoke>

#if __GNUC__ < 12
#include "mingw.invoke.h" #include "mingw.invoke.h"
#endif

+ 10
- 1
libs/mingw-std-threads/mingw.condition_variable.h View File

@@ -34,11 +34,20 @@
#include <sdkddkver.h> // Detect Windows version. #include <sdkddkver.h> // Detect Windows version.
#if (WINVER < _WIN32_WINNT_VISTA) #if (WINVER < _WIN32_WINNT_VISTA)
#include <atomic> #include <atomic>
#endif
#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
#pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
with Microsoft's API. We'll try to work around this, but we can make no\
guarantees. This problem does not exist in MinGW-w64."
#include <windows.h> // No further granularity can be expected.
#else
#if (WINVER < _WIN32_WINNT_VISTA)
#include <windef.h> #include <windef.h>
#include <winbase.h> // For CreateSemaphore #include <winbase.h> // For CreateSemaphore
#include <handleapi.h> #include <handleapi.h>
#endif #endif
#include <synchapi.h> #include <synchapi.h>
#endif
#include "mingw.mutex.h" #include "mingw.mutex.h"
#include "mingw.shared_mutex.h" #include "mingw.shared_mutex.h"
@@ -123,7 +132,7 @@ private:
else else
{ {
using namespace std; using namespace std;
throw system_error(make_error_code((errc)EPROTO));
throw system_error(make_error_code(errc::protocol_error));
} }
} }
public: public:


+ 1
- 1
libs/mingw-std-threads/mingw.invoke.h View File

@@ -92,7 +92,7 @@ namespace detail
inline static auto invoke (F&& f, Args&&... args) -> decltype(invoker::invoke(std::forward<F>(f), std::forward<Args>(args)...)) inline static auto invoke (F&& f, Args&&... args) -> decltype(invoker::invoke(std::forward<F>(f), std::forward<Args>(args)...))
{ {
return invoker::invoke(std::forward<F>(f), std::forward<Args>(args)...); return invoker::invoke(std::forward<F>(f), std::forward<Args>(args)...);
};
}
}; };


template<class F, class...Args> template<class F, class...Args>


+ 18
- 2
libs/mingw-std-threads/mingw.mutex.h View File

@@ -43,14 +43,21 @@
#include <cstdio> #include <cstdio>
#endif #endif
#include <sdkddkver.h> // Detect Windows version. #include <sdkddkver.h> // Detect Windows version.
#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
#pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
with Microsoft's API. We'll try to work around this, but we can make no\
guarantees. This problem does not exist in MinGW-w64."
#include <windows.h> // No further granularity can be expected.
#else
#if STDMUTEX_RECURSION_CHECKS #if STDMUTEX_RECURSION_CHECKS
#include <processthreadsapi.h> // For GetCurrentThreadId #include <processthreadsapi.h> // For GetCurrentThreadId
#endif #endif
#include <synchapi.h> // For InitializeCriticalSection, etc. #include <synchapi.h> // For InitializeCriticalSection, etc.
#include <errhandlingapi.h> // For GetLastError #include <errhandlingapi.h> // For GetLastError
#include <handleapi.h> #include <handleapi.h>
#endif
// Need for the implementation of invoke // Need for the implementation of invoke
#include "mingw.invoke.h" #include "mingw.invoke.h"
@@ -151,6 +158,14 @@ struct _OwnerThread
// Though the Slim Reader-Writer (SRW) locks used here are not complete until // Though the Slim Reader-Writer (SRW) locks used here are not complete until
// Windows 7, implementing partial functionality in Vista will simplify the // Windows 7, implementing partial functionality in Vista will simplify the
// interaction with condition variables. // interaction with condition variables.
//Define SRWLOCK_INIT.
#if !defined(SRWLOCK_INIT)
#pragma message "SRWLOCK_INIT macro is not defined. Defining automatically."
#define SRWLOCK_INIT {0}
#endif
#if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA) #if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA)
namespace windows7 namespace windows7
{ {
@@ -388,6 +403,7 @@ public:
class timed_mutex: recursive_timed_mutex class timed_mutex: recursive_timed_mutex
{ {
public: public:
timed_mutex() = default;
timed_mutex(const timed_mutex&) = delete; timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete; timed_mutex& operator=(const timed_mutex&) = delete;
void lock() void lock()
@@ -449,7 +465,7 @@ void call_once(once_flag& flag, Callable&& func, Args&&... args)
if (flag.mHasRun.load(std::memory_order_acquire)) if (flag.mHasRun.load(std::memory_order_acquire))
return; return;
lock_guard<decltype(flag.mMutex)> lock(flag.mMutex); lock_guard<decltype(flag.mMutex)> lock(flag.mMutex);
if (flag.mHasRun.load(std::memory_order_acquire))
if (flag.mHasRun.load(std::memory_order_relaxed))
return; return;
detail::invoke(std::forward<Callable>(func),std::forward<Args>(args)...); detail::invoke(std::forward<Callable>(func),std::forward<Args>(args)...);
flag.mHasRun.store(true, std::memory_order_release); flag.mHasRun.store(true, std::memory_order_release);


+ 7
- 0
libs/mingw-std-threads/mingw.shared_mutex.h View File

@@ -56,8 +56,15 @@
// Might be able to use native Slim Reader-Writer (SRW) locks. // Might be able to use native Slim Reader-Writer (SRW) locks.
#ifdef _WIN32 #ifdef _WIN32
#include <sdkddkver.h> // Detect Windows version. #include <sdkddkver.h> // Detect Windows version.
#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
#pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
with Microsoft's API. We'll try to work around this, but we can make no\
guarantees. This problem does not exist in MinGW-w64."
#include <windows.h> // No further granularity can be expected.
#else
#include <synchapi.h> #include <synchapi.h>
#endif #endif
#endif


namespace mingw_stdthread namespace mingw_stdthread
{ {


+ 48
- 21
libs/mingw-std-threads/mingw.thread.h View File

@@ -40,10 +40,17 @@
#include "mingw.invoke.h" #include "mingw.invoke.h"
#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
#pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
with Microsoft's API. We'll try to work around this, but we can make no\
guarantees. This problem does not exist in MinGW-w64."
#include <windows.h> // No further granularity can be expected.
#else
#include <synchapi.h> // For WaitForSingleObject #include <synchapi.h> // For WaitForSingleObject
#include <handleapi.h> // For CloseHandle, etc. #include <handleapi.h> // For CloseHandle, etc.
#include <sysinfoapi.h> // For GetNativeSystemInfo #include <sysinfoapi.h> // For GetNativeSystemInfo
#include <processthreadsapi.h> // For GetCurrentThreadId #include <processthreadsapi.h> // For GetCurrentThreadId
#endif
#include <process.h> // For _beginthreadex #include <process.h> // For _beginthreadex
#ifndef NDEBUG #ifndef NDEBUG
@@ -68,20 +75,19 @@ namespace detail
template<std::size_t... S> template<std::size_t... S>
struct GenIntSeq<0, S...> { typedef IntSeq<S...> type; }; struct GenIntSeq<0, S...> { typedef IntSeq<S...> type; };
// We can't define the Call struct in the function - the standard forbids template methods in that case
template<class Func, typename... Args>
class ThreadFuncCall
// Use a template specialization to avoid relying on compiler optimization
// when determining the parameter integer sequence.
template<class Func, class T, typename... Args>
class ThreadFuncCall;
// We can't define the Call struct in the function - the standard forbids template methods in that case
template<class Func, std::size_t... S, typename... Args>
class ThreadFuncCall<Func, detail::IntSeq<S...>, Args...>
{ {
static_assert(sizeof...(S) == sizeof...(Args), "Args must match.");
using Tuple = std::tuple<typename std::decay<Args>::type...>; using Tuple = std::tuple<typename std::decay<Args>::type...>;
typename std::decay<Func>::type mFunc; typename std::decay<Func>::type mFunc;
Tuple mArgs; Tuple mArgs;
template <std::size_t... S>
void callFunc(detail::IntSeq<S...>)
{
// Note: Only called once (per thread)
detail::invoke(std::move(mFunc), std::move(std::get<S>(mArgs)) ...);
}
public: public:
ThreadFuncCall(Func&& aFunc, Args&&... aArgs) ThreadFuncCall(Func&& aFunc, Args&&... aArgs)
: mFunc(std::forward<Func>(aFunc)), : mFunc(std::forward<Func>(aFunc)),
@@ -91,10 +97,12 @@ namespace detail
void callFunc() void callFunc()
{ {
callFunc(typename detail::GenIntSeq<sizeof...(Args)>::type());
detail::invoke(std::move(mFunc), std::move(std::get<S>(mArgs)) ...);
} }
}; };
// Allow construction of threads without exposing implementation.
class ThreadIdTool;
} // Namespace "detail" } // Namespace "detail"
class thread class thread
@@ -102,12 +110,13 @@ class thread
public: public:
class id class id
{ {
DWORD mId;
void clear() {mId = 0;}
DWORD mId = 0;
friend class thread; friend class thread;
friend class std::hash<id>; friend class std::hash<id>;
friend class detail::ThreadIdTool;
explicit id(DWORD aId) noexcept : mId(aId){}
public: public:
explicit id(DWORD aId=0) noexcept : mId(aId){}
id (void) noexcept = default;
friend bool operator==(id x, id y) noexcept {return x.mId == y.mId; } friend bool operator==(id x, id y) noexcept {return x.mId == y.mId; }
friend bool operator!=(id x, id y) noexcept {return x.mId != y.mId; } friend bool operator!=(id x, id y) noexcept {return x.mId != y.mId; }
friend bool operator< (id x, id y) noexcept {return x.mId < y.mId; } friend bool operator< (id x, id y) noexcept {return x.mId < y.mId; }
@@ -166,7 +175,7 @@ public:
:mHandle(other.mHandle), mThreadId(other.mThreadId) :mHandle(other.mHandle), mThreadId(other.mThreadId)
{ {
other.mHandle = kInvalidHandle; other.mHandle = kInvalidHandle;
other.mThreadId.clear();
other.mThreadId = id{};
} }
thread(const thread &other)=delete; thread(const thread &other)=delete;
@@ -174,12 +183,13 @@ public:
template<class Func, typename... Args> template<class Func, typename... Args>
explicit thread(Func&& func, Args&&... args) : mHandle(), mThreadId() explicit thread(Func&& func, Args&&... args) : mHandle(), mThreadId()
{ {
typedef detail::ThreadFuncCall<Func, Args...> Call;
using ArgSequence = typename detail::GenIntSeq<sizeof...(Args)>::type;
using Call = detail::ThreadFuncCall<Func, ArgSequence, Args...>;
auto call = new Call( auto call = new Call(
std::forward<Func>(func), std::forward<Args>(args)...); std::forward<Func>(func), std::forward<Args>(args)...);
unsigned id_receiver;
auto int_handle = _beginthreadex(NULL, 0, threadfunc<Call>, auto int_handle = _beginthreadex(NULL, 0, threadfunc<Call>,
static_cast<LPVOID>(call), 0,
reinterpret_cast<unsigned*>(&(mThreadId.mId)));
static_cast<LPVOID>(call), 0, &id_receiver);
if (int_handle == 0) if (int_handle == 0)
{ {
mHandle = kInvalidHandle; mHandle = kInvalidHandle;
@@ -187,8 +197,10 @@ public:
delete call; delete call;
// Note: Should only throw EINVAL, EAGAIN, EACCES // Note: Should only throw EINVAL, EAGAIN, EACCES
throw std::system_error(errnum, std::generic_category()); throw std::system_error(errnum, std::generic_category());
} else
} else {
mThreadId.mId = id_receiver;
mHandle = reinterpret_cast<HANDLE>(int_handle); mHandle = reinterpret_cast<HANDLE>(int_handle);
}
} }
bool joinable() const {return mHandle != kInvalidHandle;} bool joinable() const {return mHandle != kInvalidHandle;}
@@ -209,7 +221,7 @@ public:
WaitForSingleObject(mHandle, kInfinite); WaitForSingleObject(mHandle, kInfinite);
CloseHandle(mHandle); CloseHandle(mHandle);
mHandle = kInvalidHandle; mHandle = kInvalidHandle;
mThreadId.clear();
mThreadId = id{};
} }
~thread() ~thread()
@@ -261,13 +273,28 @@ moving another thread to it.\n");
CloseHandle(mHandle); CloseHandle(mHandle);
mHandle = kInvalidHandle; mHandle = kInvalidHandle;
} }
mThreadId.clear();
mThreadId = id{};
} }
}; };
namespace detail
{
class ThreadIdTool
{
public:
static thread::id make_id (DWORD base_id) noexcept
{
return thread::id(base_id);
}
};
} // Namespace "detail"
namespace this_thread namespace this_thread
{ {
inline thread::id get_id() noexcept {return thread::id(GetCurrentThreadId());}
inline thread::id get_id() noexcept
{
return detail::ThreadIdTool::make_id(GetCurrentThreadId());
}
inline void yield() noexcept {Sleep(0);} inline void yield() noexcept {Sleep(0);}
template< class Rep, class Period > template< class Rep, class Period >
void sleep_for( const std::chrono::duration<Rep,Period>& sleep_duration) void sleep_for( const std::chrono::duration<Rep,Period>& sleep_duration)


+ 3
- 0
libs/mingw-std-threads/mutex View File

@@ -3,4 +3,7 @@


#pragma once #pragma once
#include_next <mutex> #include_next <mutex>

#if __GNUC__ < 12
#include "mingw.mutex.h" #include "mingw.mutex.h"
#endif

+ 3
- 0
libs/mingw-std-threads/shared_mutex View File

@@ -3,4 +3,7 @@


#pragma once #pragma once
#include_next <shared_mutex> #include_next <shared_mutex>

#if __GNUC__ < 12
#include "mingw.shared_mutex.h" #include "mingw.shared_mutex.h"
#endif

+ 3
- 0
libs/mingw-std-threads/thread View File

@@ -3,4 +3,7 @@


#pragma once #pragma once
#include_next <thread> #include_next <thread>

#if __GNUC__ < 12
#include "mingw.thread.h" #include "mingw.thread.h"
#endif

Loading…
Cancel
Save