summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Chisnall <dchisnall@pathscale.com>2012-03-27 19:34:09 +0100
committerDavid Chisnall <dchisnall@pathscale.com>2012-03-27 19:34:09 +0100
commitfb8cc3b07be8677604df8df8e7b270edc2000aef (patch)
tree812f8e4d37b0838e9babb67597cfb6575d3aa816
parentd48277e2a7749bd2555e0b75f30ed33225462429 (diff)
downloadlibcxxrt-fb8cc3b07be8677604df8df8e7b270edc2000aef.tar.gz
libcxxrt-fb8cc3b07be8677604df8df8e7b270edc2000aef.tar.bz2
libcxxrt-fb8cc3b07be8677604df8df8e7b270edc2000aef.tar.xz
Ensure the correct happens-before relationship between set / get
functions. Add the C++11 std::get_new_handler().
-rw-r--r--src/atomic.h29
-rw-r--r--src/exception.cc10
-rw-r--r--src/memory.cc25
3 files changed, 48 insertions, 16 deletions
diff --git a/src/atomic.h b/src/atomic.h
new file mode 100644
index 0000000..bcd8a47
--- /dev/null
+++ b/src/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/src/exception.cc b/src/exception.cc
index fe56297..6e841ef 100644
--- a/src/exception.cc
+++ b/src/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
@@ -1328,7 +1329,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 +1337,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 +1392,7 @@ namespace std
{
return info->unexpectedHandler;
}
- return unexpectedHandler;
+ return ATOMIC_LOAD(&unexpectedHandler);
}
/**
* Returns the current terminate handler.
@@ -1402,7 +1404,7 @@ namespace std
{
return info->terminateHandler;
}
- return terminateHandler;
+ return ATOMIC_LOAD(&terminateHandler);
}
}
#ifdef __arm__
diff --git a/src/memory.cc b/src/memory.cc
index bd7fd22..fec861a 100644
--- a/src/memory.cc
+++ b/src/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);
}
}
@@ -78,9 +77,10 @@ void* operator new(size_t size)
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
{
@@ -98,11 +98,12 @@ void* operator new(size_t size, const std::nothrow_t &) throw()
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 (...)
{