Skip to content

Commit

Permalink
os: Emulate C++11 threads on MinGW.
Browse files Browse the repository at this point in the history
  • Loading branch information
jrfonseca committed Apr 13, 2021
1 parent a0905e8 commit 2d6d8f1
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 258 deletions.
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,15 @@ if (APPLE)
endif ()

if (MINGW)
# We use our C++11 threads implementation to avoid depending on winpthreads
check_cxx_source_compiles ("#include <thread>\nstd::thread t; int main() { return 0; }" HAVE_CXX11_THREADS)
if (HAVE_CXX11_THREADS)
message (FATAL_ERROR "MinGW builds require WIN32 threads.")
else ()
# TODO: Consider https://github.com/meganz/mingw-std-threads
include_directories (${CMAKE_CURRENT_SOURCE_DIR}/compat/cxx11-threads)
endif ()

# Avoid depending on MinGW runtime DLLs
add_linker_flags (-static-libgcc -static-libstdc++)
elseif (ENABLE_STATIC_EXE)
Expand Down
83 changes: 83 additions & 0 deletions compat/cxx11-threads/condition_variable
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**************************************************************************
*
* Copyright 2011-2021 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**************************************************************************/


#pragma once


#include_next <condition_variable>

#include <assert.h>
#include <process.h>
#include <windows.h>

#include <mutex>


namespace std {


class condition_variable
{
private:
// Supported on Vista an higher.
typedef CONDITION_VARIABLE native_handle_type;
native_handle_type _native_handle;

public:
condition_variable() {
InitializeConditionVariable(&_native_handle);
}

~condition_variable() {
/* No-op */
}

inline void
notify_one(void) {
WakeConditionVariable(&_native_handle);
}

inline void
notify_all(void) {
WakeAllConditionVariable(&_native_handle);
}

inline void
wait(unique_lock<mutex> & lock) {
mutex::native_handle_type & mutex_native_handle = lock.mutex()->native_handle();
SleepConditionVariableCS(&_native_handle, &mutex_native_handle, INFINITE);
}

inline void
wait(unique_lock<mutex> & lock, std::function<bool()> pred) {
while (!pred) {
wait(lock);
}
}
};


} /* namespace std */
99 changes: 99 additions & 0 deletions compat/cxx11-threads/mutex
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**************************************************************************
*
* Copyright 2011-2021 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**************************************************************************/


#pragma once


#include_next <mutex>

#include <assert.h>
#include <process.h>
#include <windows.h>


namespace std {


/**
* Base class for mutex and recursive_mutex.
*/
class _base_mutex
{
public:
typedef CRITICAL_SECTION native_handle_type;

protected:
_base_mutex(void) {
}

public:
~_base_mutex() {
DeleteCriticalSection(&_native_handle);
}

inline void
lock(void) {
EnterCriticalSection(&_native_handle);
}

inline void
unlock(void) {
LeaveCriticalSection(&_native_handle);
}

native_handle_type & native_handle() {
return _native_handle;
}

protected:
native_handle_type _native_handle;
};


/**
* Same interface as std::mutex.
*/
class mutex : public _base_mutex
{
public:
inline
mutex(void) {
InitializeCriticalSection(&_native_handle);
}
};


class recursive_mutex : public _base_mutex
{
public:
inline
recursive_mutex(void) {
InitializeCriticalSection(&_native_handle);
}
};


} /* namespace std */
118 changes: 118 additions & 0 deletions compat/cxx11-threads/thread
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**************************************************************************
*
* Copyright 2011-2021 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
**************************************************************************/


#pragma once


#include_next <thread>

#include <assert.h>
#include <process.h>
#include <windows.h>

#include <functional>


namespace std {


class thread {
public:
typedef HANDLE native_handle_type;

inline
thread() :
_native_handle(0)
{
}

inline
thread(thread &&other) :
_native_handle(other._native_handle)
{
other._native_handle = 0;
}

thread(const thread &other) = delete;

inline
~thread() {
}

static unsigned
hardware_concurrency(void) {
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwNumberOfProcessors;
}

template< class Function, class... Args >
explicit thread(Function &&f, Args&&... args) {
auto bound = std::bind(std::forward<Function>(f), std::forward<Args>(args)...);
auto data = new decltype(bound) (std::move(bound));
_native_handle = _create(data);
}

inline thread &
operator =(thread &&other) {
assert(_native_handle == 0);
_native_handle = other._native_handle;
other._native_handle = 0;
return *this;
}

inline bool
joinable(void) const {
return _native_handle != 0;
}

inline void
join() {
WaitForSingleObject(_native_handle, INFINITE);
}

private:
native_handle_type _native_handle;

template< typename Param >
static
unsigned __stdcall
_callback(void *lpParameter) {
Param *pParam = static_cast<Param *>(lpParameter);
(*pParam)();
delete pParam;
return 0;
}

template< typename Param >
static inline native_handle_type
_create(Param *function) {
uintptr_t handle =_beginthreadex(NULL, 0, &_callback<Param>, function, 0, NULL);
return reinterpret_cast<HANDLE>(handle);
}
};

} /* namespace std */
Loading

0 comments on commit 2d6d8f1

Please sign in to comment.