Skip to content

Commit

Permalink
Add -fno-exceptions support (#53)
Browse files Browse the repository at this point in the history
* Add -fno-exceptions support

* Change <c++/bits/exception_defines.h> include to <bits/exception_defines.h>

* Change:
__throw_exception_again
by
__throw_<<exception_name_here>>

* Change to a more flexible "throw" system

* More robust detection of -fno-exceptions.

If the __cpp_exceptions macro is defined, use it. Otherwise, check for
compiler-specific feature macros (__EXCEPTIONS for GCC) in case an old
version of GCC is being used. If we are unsure, we must assume that C++
exceptions are being used, as this is the standard behavior.

* Create an exception pointer without catch/throw.

Use an appropriate standard-library function to create exception
pointers without using catch or throw clauses.

* Fix many compilation errors.

Despite the intention of previous authors' contributions, the
contributed code did not, in fact, compile with -fno-exceptions set.

This updates all headers so that they will successfully compile
regardless of whether -fno-exceptions is specified (tested in MinGW
GCC).
  • Loading branch information
Maeiky authored and alxvasilev committed Sep 10, 2019
1 parent 5217ba5 commit 8ba714a
Show file tree
Hide file tree
Showing 7 changed files with 933 additions and 841 deletions.
8 changes: 5 additions & 3 deletions mingw.condition_variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

#include "mingw.mutex.h"
#include "mingw.shared_mutex.h"
#include "mingw.throw.h"

#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501)
#error To use the MinGW-std-threads library, you will need to define the macro _WIN32_WINNT to be 0x0501 (Windows XP) or higher.
Expand Down Expand Up @@ -78,12 +79,12 @@ class condition_variable_any
: mSemaphore(CreateSemaphoreA(NULL, 0, 0xFFFF, NULL))
{
if (mSemaphore == NULL)
throw std::system_error(GetLastError(), std::generic_category());
throw_error<std::system_error>(GetLastError(), std::generic_category());
mWakeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (mWakeEvent == NULL)
{
CloseHandle(mSemaphore);
throw std::system_error(GetLastError(), std::generic_category());
throw_error<std::system_error>(GetLastError(), std::generic_category());
}
}
~condition_variable_any()
Expand Down Expand Up @@ -123,8 +124,9 @@ class condition_variable_any
else
{
using namespace std;
throw system_error(make_error_code(errc::protocol_error));
throw_error<std::system_error>(make_error_code(errc::protocol_error));
}
return false;
}
public:
template <class M>
Expand Down
38 changes: 29 additions & 9 deletions mingw.future.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
// Mutexes and condition variables are used explicitly.
#include "mingw.mutex.h"
#include "mingw.condition_variable.h"
#include "mingw.throw.h"

#include <synchapi.h>
#include <handleapi.h>
Expand Down Expand Up @@ -177,7 +178,7 @@ struct FutureBase : public FutureStatic<true>
{
#if !defined(NDEBUG)
if (!valid())
throw future_error(future_errc::no_state);
throw_error<future_error>(future_errc::no_state);
#endif
// If there's already a value or exception, don't do any extraneous
// synchronization. The `get()` method will do that for us.
Expand All @@ -193,7 +194,7 @@ struct FutureBase : public FutureStatic<true>
{
#if !defined(NDEBUG)
if (!valid())
throw future_error(future_errc::no_state);
throw_error<future_error>(future_errc::no_state);
#endif
auto current_state = mState->mType.load(std::memory_order_relaxed);
if (current_state & kReadyFlag)
Expand Down Expand Up @@ -468,9 +469,9 @@ class promise : mingw_stdthread::detail::FutureBase
void check_before_set (void) const
{
if (!valid())
throw future_error(future_errc::no_state);
mingw_stdthread::throw_error<future_error>(future_errc::no_state);
if (mState->mType.load(std::memory_order_relaxed) & kSetFlag)
throw future_error(future_errc::promise_already_satisfied);
mingw_stdthread::throw_error<future_error>(future_errc::promise_already_satisfied);
}

void check_abandon (void)
Expand All @@ -495,11 +496,13 @@ class promise : mingw_stdthread::detail::FutureBase
FALSE, // No need for this to be inherited.
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
if (!success)
throw std::runtime_error("MinGW STD Threads library failed to make a promise ready after thread exit.");
mingw_stdthread::throw_error<std::runtime_error>("MinGW STD Threads library failed to make a promise ready after thread exit.");

mState->increment_references();
bool handle_handled = false;
#if !MINGW_STDTHREAD_NO_EXCEPTIONS
try {
#endif
state_type * ptr = static_cast<state_type *>(mState);
mingw_stdthread::thread watcher_thread ([ptr, thread_handle, &handle_handled](void)
{
Expand Down Expand Up @@ -528,24 +531,27 @@ class promise : mingw_stdthread::detail::FutureBase
});
}
watcher_thread.detach();
#if !MINGW_STDTHREAD_NO_EXCEPTIONS
}
catch (...)
{
// Because the original promise is still alive, this can't be the decrement
// destroys it.
// that destroys it.
mState->decrement_references();
if (!handle_handled)
CloseHandle(thread_handle);
mingw_stdthread::throw_error<std::runtime_error>("MinGW STD Threads library failed to make a promise ready after thread exit.");
}
#endif
}

template<class U>
future<U> make_future (void)
{
if (!valid())
throw future_error(future_errc::no_state);
mingw_stdthread::throw_error<future_error>(future_errc::no_state);
if (mRetrieved)
throw future_error(future_errc::future_already_retrieved);
mingw_stdthread::throw_error<future_error>(future_errc::future_already_retrieved);
mState->increment_references();
mRetrieved = true;
return future<U>(static_cast<state_type *>(mState));
Expand Down Expand Up @@ -929,11 +935,15 @@ struct StorageHelper
template<class Func, class ... Args>
static void store_deferred (FutureState<Ret> * state_ptr, Func && func, Args&&... args)
{
#if MINGW_STDTHREAD_NO_EXCEPTIONS
state_ptr->set_value(invoke(std::forward<Func>(func), std::forward<Args>(args)...));
#else
try {
state_ptr->set_value(invoke(std::forward<Func>(func), std::forward<Args>(args)...));
} catch (...) {
state_ptr->set_exception(std::current_exception());
}
#endif
}
template<class Func, class ... Args>
static void store (FutureState<Ret> * state_ptr, Func && func, Args&&... args)
Expand All @@ -952,13 +962,18 @@ struct StorageHelper<Ref&>
template<class Func, class ... Args>
static void store_deferred (FutureState<void*> * state_ptr, Func && func, Args&&... args)
{
using Ref_non_cv = typename std::remove_cv<Ref>::type;
#if MINGW_STDTHREAD_NO_EXCEPTIONS
Ref & rf = invoke(std::forward<Func>(func), std::forward<Args>(args)...);
state_ptr->set_value(const_cast<Ref_non_cv *>(std::addressof(rf)));
#else
try {
typedef typename std::remove_cv<Ref>::type Ref_non_cv;
Ref & rf = invoke(std::forward<Func>(func), std::forward<Args>(args)...);
state_ptr->set_value(const_cast<Ref_non_cv *>(std::addressof(rf)));
} catch (...) {
state_ptr->set_exception(std::current_exception());
}
#endif
}
template<class Func, class ... Args>
static void store (FutureState<void*> * state_ptr, Func && func, Args&&... args)
Expand All @@ -977,12 +992,17 @@ struct StorageHelper<void>
template<class Func, class ... Args>
static void store_deferred (FutureState<Empty> * state_ptr, Func && func, Args&&... args)
{
#if MINGW_STDTHREAD_NO_EXCEPTIONS
invoke(std::forward<Func>(func), std::forward<Args>(args)...);
state_ptr->set_value(Empty{});
#else
try {
invoke(std::forward<Func>(func), std::forward<Args>(args)...);
state_ptr->set_value(Empty{});
} catch (...) {
state_ptr->set_exception(std::current_exception());
}
#endif
}
template<class Func, class ... Args>
static void store (FutureState<Empty> * state_ptr, Func && func, Args&&... args)
Expand Down
Loading

0 comments on commit 8ba714a

Please sign in to comment.