| //===- llvm/unittest/Support/ManagedStatic.cpp - ManagedStatic tests ------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Support/Allocator.h" | |
| #include "llvm/Support/ManagedStatic.h" | |
| #include "llvm/Config/config.h" | |
| #ifdef HAVE_PTHREAD_H | |
| #include <pthread.h> | |
| #endif | |
| #include "gtest/gtest.h" | |
| using namespace llvm; | |
| namespace { | |
| #if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) && \ | |
| !__has_feature(memory_sanitizer) | |
| namespace test1 { | |
| llvm::ManagedStatic<int> ms; | |
| void *helper(void*) { | |
| *ms; | |
| return nullptr; | |
| } | |
| // Valgrind's leak checker complains glibc's stack allocation. | |
| // To appease valgrind, we provide our own stack for each thread. | |
| void *allocate_stack(pthread_attr_t &a, size_t n = 65536) { | |
| void *stack = safe_malloc(n); | |
| pthread_attr_init(&a); | |
| #if defined(__linux__) | |
| pthread_attr_setstack(&a, stack, n); | |
| #endif | |
| return stack; | |
| } | |
| } | |
| TEST(Initialize, MultipleThreads) { | |
| // Run this test under tsan: http://code.google.com/p/data-race-test/ | |
| pthread_attr_t a1, a2; | |
| void *p1 = test1::allocate_stack(a1); | |
| void *p2 = test1::allocate_stack(a2); | |
| pthread_t t1, t2; | |
| pthread_create(&t1, &a1, test1::helper, nullptr); | |
| pthread_create(&t2, &a2, test1::helper, nullptr); | |
| pthread_join(t1, nullptr); | |
| pthread_join(t2, nullptr); | |
| free(p1); | |
| free(p2); | |
| } | |
| #endif | |
| namespace NestedStatics { | |
| static ManagedStatic<int> Ms1; | |
| struct Nest { | |
| Nest() { | |
| ++(*Ms1); | |
| } | |
| ~Nest() { | |
| assert(Ms1.isConstructed()); | |
| ++(*Ms1); | |
| } | |
| }; | |
| static ManagedStatic<Nest> Ms2; | |
| TEST(ManagedStaticTest, NestedStatics) { | |
| EXPECT_FALSE(Ms1.isConstructed()); | |
| EXPECT_FALSE(Ms2.isConstructed()); | |
| *Ms2; | |
| EXPECT_TRUE(Ms1.isConstructed()); | |
| EXPECT_TRUE(Ms2.isConstructed()); | |
| } | |
| } // namespace NestedStatics | |
| namespace CustomCreatorDeletor { | |
| struct CustomCreate { | |
| static void *call() { | |
| void *Mem = safe_malloc(sizeof(int)); | |
| *((int *)Mem) = 42; | |
| return Mem; | |
| } | |
| }; | |
| struct CustomDelete { | |
| static void call(void *P) { std::free(P); } | |
| }; | |
| static ManagedStatic<int, CustomCreate, CustomDelete> Custom; | |
| TEST(ManagedStaticTest, CustomCreatorDeletor) { | |
| EXPECT_EQ(42, *Custom); | |
| } | |
| } // namespace CustomCreatorDeletor | |
| } // anonymous namespace |