summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libcxxabi/include/cxxabi.h3
-rw-r--r--libcxxabi/src/cxa_guard.cpp174
-rw-r--r--libcxxabi/src/cxa_virtual.cpp33
-rw-r--r--libcxxabi/test/test_guard.cpp59
4 files changed, 269 insertions, 0 deletions
diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h
index d163dd40a97..918cd5da168 100644
--- a/libcxxabi/include/cxxabi.h
+++ b/libcxxabi/include/cxxabi.h
@@ -55,6 +55,9 @@ extern void __cxa_bad_typeid();
// 3.2.6 Pure Virtual Function API
extern void __cxa_pure_virtual(void);
+// 3.2.7 Deleted Virtual Function API
+extern void __cxa_deleted_virtual(void);
+
// 3.3.2 One-time Construction API
extern int __cxa_guard_acquire(uint64_t*);
extern void __cxa_guard_release(uint64_t*);
diff --git a/libcxxabi/src/cxa_guard.cpp b/libcxxabi/src/cxa_guard.cpp
new file mode 100644
index 00000000000..64abda1e1d4
--- /dev/null
+++ b/libcxxabi/src/cxa_guard.cpp
@@ -0,0 +1,174 @@
+//===---------------------------- cxa_guard.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace __cxxabiv1
+{
+
+namespace
+{
+
+void abort_message(const char* s)
+{
+ fputs(s, stderr);
+ ::abort();
+}
+
+pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
+
+#if __APPLE__
+
+typedef uint32_t lock_type;
+
+#if __LITTLE_ENDIAN__
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ return static_cast<lock_type>(x >> 32);
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ x = static_cast<uint64_t>(y) << 32;
+}
+
+#else // __LITTLE_ENDIAN__
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ return static_cast<lock_type>(x);
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ x = y;
+}
+
+#endif // __LITTLE_ENDIAN__
+
+#else // __APPLE__
+
+typedef bool lock_type;
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ union
+ {
+ uint64_t guard;
+ uint8_t lock[2];
+ } f = {x};
+ return f.lock[1] != 0;
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ union
+ {
+ uint64_t guard;
+ uint8_t lock[2];
+ } f = {0};
+ f.lock[1] = y;
+ x = f.guard;
+}
+
+#endif // __APPLE__
+
+} // unnamed namespace
+
+extern "C"
+{
+
+int __cxa_guard_acquire(uint64_t* guard_object)
+{
+ char* initialized = (char*)guard_object;
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_acquire failed to acquire mutex");
+ int result = *initialized == 0;
+ if (result)
+ {
+#if __APPLE__
+ const lock_type id = pthread_mach_thread_np(pthread_self());
+ lock_type lock = get_lock(*guard_object);
+ if (lock)
+ {
+ // if this thread set lock for this same guard_object, abort
+ if (lock == id)
+ abort_message("__cxa_guard_acquire detected deadlock");
+ do
+ {
+ if (pthread_cond_wait(&guard_cv, &guard_mut))
+ abort_message("__cxa_guard_acquire condition variable wait failed");
+ lock = get_lock(*guard_object);
+ } while (lock);
+ result = *initialized == 0;
+ if (result)
+ set_lock(*guard_object, id);
+ }
+ else
+ set_lock(*guard_object, id);
+#else // __APPLE__
+ while (get_lock(*guard_object))
+ if (pthread_cond_wait(&guard_cv, &guard_mut))
+ abort_message("__cxa_guard_acquire condition variable wait failed");
+ result = *initialized == 0;
+ if (result)
+ set_lock(*guard_object, true);
+#endif // __APPLE__
+ }
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_acquire failed to release mutex");
+ return result;
+}
+
+void __cxa_guard_release(uint64_t* guard_object)
+{
+ char* initialized = (char*)guard_object;
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_release failed to acquire mutex");
+ *guard_object = 0;
+ *initialized = 1;
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_release failed to release mutex");
+ if (pthread_cond_broadcast(&guard_cv))
+ abort_message("__cxa_guard_release failed to broadcast condition variable");
+}
+
+void __cxa_guard_abort(uint64_t* guard_object)
+{
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_abort failed to acquire mutex");
+ *guard_object = 0;
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_abort failed to release mutex");
+ if (pthread_cond_broadcast(&guard_cv))
+ abort_message("__cxa_guard_abort failed to broadcast condition variable");
+}
+
+} // extern "C"
+
+} // __cxxabiv1
diff --git a/libcxxabi/src/cxa_virtual.cpp b/libcxxabi/src/cxa_virtual.cpp
new file mode 100644
index 00000000000..bdcf6878734
--- /dev/null
+++ b/libcxxabi/src/cxa_virtual.cpp
@@ -0,0 +1,33 @@
+//===-------------------------- cxa_virtual.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace __cxxabiv1
+{
+
+extern "C"
+{
+
+void __cxa_pure_virtual(void) {
+ fputs("Pure virtual function called!\n", stderr);
+ abort();
+}
+
+void __cxa_deleted_virtual(void) {
+ fputs("Deleted virtual function called!\n", stderr);
+ abort();
+}
+
+} // extern "C"
+
+} // abi
diff --git a/libcxxabi/test/test_guard.cpp b/libcxxabi/test/test_guard.cpp
new file mode 100644
index 00000000000..c69b8e73077
--- /dev/null
+++ b/libcxxabi/test/test_guard.cpp
@@ -0,0 +1,59 @@
+//===----------------------------- test_guard.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+
+#include <cassert>
+
+namespace test1 {
+ static int run_count = 0;
+ int increment() {
+ ++run_count;
+ return 0;
+ }
+ void helper() {
+ static int a = increment();
+ }
+ void test() {
+ static int a = increment();
+ assert(run_count == 1);
+ static int b = increment();
+ assert(run_count == 2);
+ helper();
+ assert(run_count == 3);
+ helper();
+ assert(run_count == 3);
+ }
+}
+
+namespace test2 {
+ static int run_count = 0;
+ int increment() {
+ ++run_count;
+ throw 0;
+ }
+ void helper() {
+ try {
+ static int a = increment();
+ assert(0);
+ } catch (...) {}
+ }
+ void test() {
+ helper();
+ assert(run_count == 1);
+ helper();
+ assert(run_count == 2);
+ }
+}
+
+int main()
+{
+ test1::test();
+ test2::test();
+}
OpenPOWER on IntegriCloud