diff options
| -rw-r--r-- | libcxxabi/include/cxxabi.h | 3 | ||||
| -rw-r--r-- | libcxxabi/src/cxa_guard.cpp | 174 | ||||
| -rw-r--r-- | libcxxabi/src/cxa_virtual.cpp | 33 | ||||
| -rw-r--r-- | libcxxabi/test/test_guard.cpp | 59 |
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(); +} |

