1 | //===- llvm/unittest/Support/ManagedStatic.cpp - ManagedStatic tests ------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Support/Allocator.h" |
10 | #include "llvm/Support/ManagedStatic.h" |
11 | #include "llvm/Config/config.h" |
12 | #ifdef HAVE_PTHREAD_H |
13 | #include <pthread.h> |
14 | #endif |
15 | |
16 | #include "gtest/gtest.h" |
17 | |
18 | using namespace llvm; |
19 | |
20 | namespace { |
21 | |
22 | #if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) && \ |
23 | !__has_feature(memory_sanitizer) |
24 | namespace test1 { |
25 | llvm::ManagedStatic<int> ms; |
26 | void *helper(void*) { |
27 | *ms; |
28 | return nullptr; |
29 | } |
30 | |
31 | // Valgrind's leak checker complains glibc's stack allocation. |
32 | // To appease valgrind, we provide our own stack for each thread. |
33 | void *allocate_stack(pthread_attr_t &a, size_t n = 65536) { |
34 | void *stack = safe_malloc(Sz: n); |
35 | pthread_attr_init(attr: &a); |
36 | #if defined(__linux__) |
37 | pthread_attr_setstack(attr: &a, stackaddr: stack, stacksize: n); |
38 | #endif |
39 | return stack; |
40 | } |
41 | } |
42 | |
43 | TEST(Initialize, MultipleThreads) { |
44 | // Run this test under tsan: http://code.google.com/p/data-race-test/ |
45 | |
46 | pthread_attr_t a1, a2; |
47 | void *p1 = test1::allocate_stack(a&: a1); |
48 | void *p2 = test1::allocate_stack(a&: a2); |
49 | |
50 | pthread_t t1, t2; |
51 | pthread_create(newthread: &t1, attr: &a1, start_routine: test1::helper, arg: nullptr); |
52 | pthread_create(newthread: &t2, attr: &a2, start_routine: test1::helper, arg: nullptr); |
53 | pthread_join(th: t1, thread_return: nullptr); |
54 | pthread_join(th: t2, thread_return: nullptr); |
55 | free(ptr: p1); |
56 | free(ptr: p2); |
57 | } |
58 | #endif |
59 | |
60 | namespace NestedStatics { |
61 | static ManagedStatic<int> Ms1; |
62 | struct Nest { |
63 | Nest() { |
64 | ++(*Ms1); |
65 | } |
66 | |
67 | ~Nest() { |
68 | assert(Ms1.isConstructed()); |
69 | ++(*Ms1); |
70 | } |
71 | }; |
72 | static ManagedStatic<Nest> Ms2; |
73 | |
74 | TEST(ManagedStaticTest, NestedStatics) { |
75 | EXPECT_FALSE(Ms1.isConstructed()); |
76 | EXPECT_FALSE(Ms2.isConstructed()); |
77 | |
78 | *Ms2; |
79 | EXPECT_TRUE(Ms1.isConstructed()); |
80 | EXPECT_TRUE(Ms2.isConstructed()); |
81 | } |
82 | } // namespace NestedStatics |
83 | |
84 | namespace CustomCreatorDeletor { |
85 | struct CustomCreate { |
86 | static void *call() { |
87 | void *Mem = safe_malloc(Sz: sizeof(int)); |
88 | *((int *)Mem) = 42; |
89 | return Mem; |
90 | } |
91 | }; |
92 | struct CustomDelete { |
93 | static void call(void *P) { std::free(ptr: P); } |
94 | }; |
95 | static ManagedStatic<int, CustomCreate, CustomDelete> Custom; |
96 | TEST(ManagedStaticTest, CustomCreatorDeletor) { |
97 | EXPECT_EQ(42, *Custom); |
98 | } |
99 | } // namespace CustomCreatorDeletor |
100 | |
101 | } // anonymous namespace |
102 | |