aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Chisnall <theraven@FreeBSD.org>2013-01-11 15:00:43 +0000
committerDavid Chisnall <theraven@FreeBSD.org>2013-01-11 15:00:43 +0000
commit8e59c7f5923d3dc5e307124f39868ee870b1be9c (patch)
tree7fed0a8b0e8e52601f23bb41d6b5ac9f67f86e0e
parent60e0399a08860d0c676dd35b09a8c2c21610b5a7 (diff)
downloadsrc-8e59c7f5923d3dc5e307124f39868ee870b1be9c.tar.gz
src-8e59c7f5923d3dc5e307124f39868ee870b1be9c.zip
Import b9db3a010143160624f123763025ab544b69bd9a of libcxxrt. This brings invendor/libcxxrt/2013-01-11-b9db3a010143160624f123763025ab544b69bd9a
three fixes: - Don't treat pointers to members as pointers in catch blocks (they're usually fat pointers). - Correctly catch foreign exceptions in catchalls. - Ensure that a happens-before relationship is established when setting terminate handlers in one thread and calling them in another.
Notes
Notes: svn path=/vendor/libcxxrt/dist/; revision=245302 svn path=/vendor/libcxxrt/2013-01-11-b9db3a010143160624f123763025ab544b69bd9a/; revision=245303; tag=vendor/libcxxrt/2013-01-11-b9db3a010143160624f123763025ab544b69bd9a
-rw-r--r--atomic.h29
-rw-r--r--exception.cc86
-rw-r--r--memory.cc33
-rw-r--r--typeinfo.h18
4 files changed, 132 insertions, 34 deletions
diff --git a/atomic.h b/atomic.h
new file mode 100644
index 000000000000..bcd8a47ac89d
--- /dev/null
+++ b/atomic.h
@@ -0,0 +1,29 @@
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+/**
+ * Swap macro that enforces a happens-before relationship with a corresponding
+ * ATOMIC_LOAD.
+ */
+#if __has_feature(cxx_atomic)
+#define ATOMIC_SWAP(addr, val)\
+ __atomic_exchange(addr, val, __ATOMIC_ACQ_REL)
+#elif __has_builtin(__sync_swap)
+#define ATOMIC_SWAP(addr, val)\
+ __sync_swap(addr, val)
+#else
+#define ATOMIC_SWAP(addr, val)\
+ __sync_lock_test_and_set(addr, val)
+#endif
+
+#if __has_feature(cxx_atomic)
+#define ATOMIC_LOAD(addr)\
+ __atomic_load(addr, __ATOMIC_ACQUIRE)
+#else
+#define ATOMIC_LOAD(addr)\
+ (__sync_synchronize(), *addr)
+#endif
diff --git a/exception.cc b/exception.cc
index fe56297f9dd5..0cb2535f8fd1 100644
--- a/exception.cc
+++ b/exception.cc
@@ -32,6 +32,7 @@
#include <pthread.h>
#include "typeinfo.h"
#include "dwarf_eh.h"
+#include "atomic.h"
#include "cxxabi.h"
#pragma weak pthread_key_create
@@ -155,6 +156,17 @@ struct __cxa_thread_info
*/
_Unwind_Exception *currentCleanup;
/**
+ * Our state with respect to foreign exceptions. Usually none, set to
+ * caught if we have just caught an exception and rethrown if we are
+ * rethrowing it.
+ */
+ enum
+ {
+ none,
+ caught,
+ rethrown
+ } foreign_exception_state;
+ /**
* The public part of this structure, accessible from outside of this
* module.
*/
@@ -308,7 +320,16 @@ static void thread_cleanup(void* thread_info)
__cxa_thread_info *info = (__cxa_thread_info*)thread_info;
if (info->globals.caughtExceptions)
{
- free_exception_list(info->globals.caughtExceptions);
+ // If this is a foreign exception, ask it to clean itself up.
+ if (info->foreign_exception_state != __cxa_thread_info::none)
+ {
+ _Unwind_Exception *e = (_Unwind_Exception*)info->globals.caughtExceptions;
+ e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
+ }
+ else
+ {
+ free_exception_list(info->globals.caughtExceptions);
+ }
}
free(thread_info);
}
@@ -780,7 +801,8 @@ extern "C" void __cxa_decrement_exception_refcount(void* thrown_exception)
*/
extern "C" void __cxa_rethrow()
{
- __cxa_eh_globals *globals = __cxa_get_globals();
+ __cxa_thread_info *ti = thread_info_fast();
+ __cxa_eh_globals *globals = &ti->globals;
// Note: We don't remove this from the caught list here, because
// __cxa_end_catch will be called when we unwind out of the try block. We
// could probably make this faster by providing an alternative rethrow
@@ -795,6 +817,15 @@ extern "C" void __cxa_rethrow()
std::terminate();
}
+ if (ti->foreign_exception_state != __cxa_thread_info::none)
+ {
+ ti->foreign_exception_state = __cxa_thread_info::rethrown;
+ _Unwind_Exception *e = (_Unwind_Exception*)ex;
+ _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e);
+ report_failure(err, ex);
+ return;
+ }
+
assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
// ex->handlerCount will be decremented in __cxa_end_catch in enclosing
@@ -848,9 +879,9 @@ static bool check_type_signature(__cxa_exception *ex,
void *&adjustedPtr)
{
void *exception_ptr = (void*)(ex+1);
- const std::type_info *ex_type = ex->exceptionType;
+ const std::type_info *ex_type = ex ? ex->exceptionType : 0;
- bool is_ptr = ex_type->__is_pointer_p();
+ bool is_ptr = ex ? ex_type->__is_pointer_p() : false;
if (is_ptr)
{
exception_ptr = *(void**)exception_ptr;
@@ -911,8 +942,8 @@ static handler_type check_action_record(_Unwind_Context *context,
action_record = displacement ?
action_record_offset_base + displacement : 0;
// We only check handler types for C++ exceptions - foreign exceptions
- // are only allowed for cleanup.
- if (filter > 0 && 0 != ex)
+ // are only allowed for cleanups and catchalls.
+ if (filter > 0)
{
std::type_info *handler_type = get_type_info_entry(context, lsda, filter);
if (check_type_signature(ex, handler_type, adjustedPtr))
@@ -1133,8 +1164,10 @@ extern "C" void *__cxa_begin_catch(void *e) throw()
extern "C" void *__cxa_begin_catch(void *e)
#endif
{
- // Decrement the uncaught exceptions count
- __cxa_eh_globals *globals = __cxa_get_globals();
+ // We can't call the fast version here, because if the first exception that
+ // we see is a foreign exception then we won't have called it yet.
+ __cxa_thread_info *ti = thread_info();
+ __cxa_eh_globals *globals = &ti->globals;
globals->uncaughtExceptions--;
_Unwind_Exception *exceptionObject = (_Unwind_Exception*)e;
@@ -1177,9 +1210,22 @@ extern "C" void *__cxa_begin_catch(void *e)
{
ex->handlerCount++;
}
+ ti->foreign_exception_state = __cxa_thread_info::none;
return ex->adjustedPtr;
}
+ else
+ {
+ // If this is a foreign exception, then we need to be able to
+ // store it. We can't chain foreign exceptions, so we give up
+ // if there are already some outstanding ones.
+ if (globals->caughtExceptions != 0)
+ {
+ std::terminate();
+ }
+ globals->caughtExceptions = (__cxa_exception*)exceptionObject;
+ ti->foreign_exception_state = __cxa_thread_info::caught;
+ }
// exceptionObject is the pointer to the _Unwind_Exception within the
// __cxa_exception. The throw object is after this
return ((char*)exceptionObject + sizeof(_Unwind_Exception));
@@ -1195,10 +1241,23 @@ extern "C" void __cxa_end_catch()
{
// We can call the fast version here because the slow version is called in
// __cxa_throw(), which must have been called before we end a catch block
- __cxa_eh_globals *globals = __cxa_get_globals_fast();
+ __cxa_thread_info *ti = thread_info_fast();
+ __cxa_eh_globals *globals = &ti->globals;
__cxa_exception *ex = globals->caughtExceptions;
assert(0 != ex && "Ending catch when no exception is on the stack!");
+
+ if (ti->foreign_exception_state != __cxa_thread_info::none)
+ {
+ globals->caughtExceptions = 0;
+ if (ti->foreign_exception_state != __cxa_thread_info::rethrown)
+ {
+ _Unwind_Exception *e = (_Unwind_Exception*)ti->globals.caughtExceptions;
+ e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
+ }
+ ti->foreign_exception_state = __cxa_thread_info::none;
+ return;
+ }
bool deleteException = true;
@@ -1328,7 +1387,7 @@ namespace std
{
if (thread_local_handlers) { return pathscale::set_unexpected(f); }
- return __sync_lock_test_and_set(&unexpectedHandler, f);
+ return ATOMIC_SWAP(&terminateHandler, f);
}
/**
* Sets the function that is called to terminate the program.
@@ -1336,7 +1395,8 @@ namespace std
terminate_handler set_terminate(terminate_handler f) throw()
{
if (thread_local_handlers) { return pathscale::set_terminate(f); }
- return __sync_lock_test_and_set(&terminateHandler, f);
+
+ return ATOMIC_SWAP(&terminateHandler, f);
}
/**
* Terminates the program, calling a custom terminate implementation if
@@ -1390,7 +1450,7 @@ namespace std
{
return info->unexpectedHandler;
}
- return unexpectedHandler;
+ return ATOMIC_LOAD(&unexpectedHandler);
}
/**
* Returns the current terminate handler.
@@ -1402,7 +1462,7 @@ namespace std
{
return info->terminateHandler;
}
- return terminateHandler;
+ return ATOMIC_LOAD(&terminateHandler);
}
}
#ifdef __arm__
diff --git a/memory.cc b/memory.cc
index bd7fd22ae5fd..cc879e0d0d06 100644
--- a/memory.cc
+++ b/memory.cc
@@ -36,14 +36,8 @@
#include <stddef.h>
#include <stdlib.h>
#include "stdexcept.h"
+#include "atomic.h"
-#ifndef __has_builtin
-#define __has_builtin(x) 0
-#endif
-
-#if !__has_builtin(__sync_swap)
-#define __sync_swap __sync_lock_test_and_set
-#endif
namespace std
{
@@ -67,7 +61,12 @@ namespace std
__attribute__((weak))
new_handler set_new_handler(new_handler handler)
{
- return __sync_swap(&new_handl, handler);
+ return ATOMIC_SWAP(&new_handl, handler);
+ }
+ __attribute__((weak))
+ new_handler get_new_handler(void)
+ {
+ return ATOMIC_LOAD(&new_handl);
}
}
@@ -75,12 +74,17 @@ namespace std
__attribute__((weak))
void* operator new(size_t size)
{
+ if (0 == size)
+ {
+ size = 1;
+ }
void * mem = malloc(size);
while (0 == mem)
{
- if (0 != new_handl)
+ new_handler h = std::get_new_handler();
+ if (0 != h)
{
- new_handl();
+ h();
}
else
{
@@ -95,14 +99,19 @@ void* operator new(size_t size)
__attribute__((weak))
void* operator new(size_t size, const std::nothrow_t &) throw()
{
+ if (0 == size)
+ {
+ size = 1;
+ }
void *mem = malloc(size);
while (0 == mem)
{
- if (0 != new_handl)
+ new_handler h = std::get_new_handler();
+ if (0 != h)
{
try
{
- new_handl();
+ h();
}
catch (...)
{
diff --git a/typeinfo.h b/typeinfo.h
index 82239778ec5b..a8a1a980e926 100644
--- a/typeinfo.h
+++ b/typeinfo.h
@@ -70,6 +70,14 @@ namespace std
*/
public:
/**
+ * Returns true if this is some pointer type, false otherwise.
+ */
+ virtual bool __is_pointer_p() const { return false; }
+ /**
+ * Returns true if this is some function type, false otherwise.
+ */
+ virtual bool __is_function_p() const { return false; }
+ /**
* Catch function. Allows external libraries to implement
* their own basic types. This is used, for example, in the
* GNUstep Objective-C runtime to allow Objective-C types to be
@@ -95,14 +103,6 @@ namespace std
{
return false;
}
- /**
- * Returns true if this is some pointer type, false otherwise.
- */
- virtual bool __is_pointer_p() const { return false; }
- /**
- * Returns true if this is some function type, false otherwise.
- */
- virtual bool __is_function_p() const { return false; }
};
}
@@ -284,7 +284,6 @@ namespace ABI_NAMESPACE
/** Pointer is a pointer to a member of an incomplete class. */
__incomplete_class_mask = 0x10
};
- virtual bool __is_pointer_p() const { return true; }
virtual bool __do_catch(const type_info *thrown_type,
void **thrown_object,
unsigned outer) const;
@@ -296,6 +295,7 @@ namespace ABI_NAMESPACE
struct __pointer_type_info : public __pbase_type_info
{
virtual ~__pointer_type_info();
+ virtual bool __is_pointer_p() const { return true; }
};
/**