1 // Copyright (C) 2013 The Android Open Source Project
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the project nor the names of its contributors
13 // may be used to endorse or promote products derived from this software
14 // without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 // A test used to check that __cxa_get_globals() does not use malloc.
29 // This will do the following:
31 // - Lazily load libtest_malloc_lockup.so, which includes a copy of
32 // GAbi++ linked with malloc() / free() functions that exit() with
33 // an error if called.
35 // - Create a large number of concurrent threads, and have each one
36 // call the library's 'get_globals' function, which returns the
37 // result of __cxa_get_globals() linked against the special mallocs,
38 // then store the value in a global array.
40 // - Tell all the threads to stop, wait for them to complete.
42 // - Look at the values stored in the global arrays. They should not be NULL
43 // (to indicate succesful allocation), and all different (each one should
44 // correspond to a thread-specific instance of __cxa_eh_globals).
46 // - Unload the library.
56 typedef void* (*get_globals_fn
)();
58 static get_globals_fn g_get_globals
;
60 // Number of threads to create. Must be > 4096 to really check slab allocation.
61 static const size_t kMaxThreads
= 5000;
63 static pthread_t g_threads
[kMaxThreads
];
64 static void* g_thread_objects
[kMaxThreads
];
66 static pthread_mutex_t g_lock
= PTHREAD_MUTEX_INITIALIZER
;
67 static pthread_cond_t g_cond_exit
= PTHREAD_COND_INITIALIZER
;
68 static pthread_cond_t g_cond_counter
= PTHREAD_COND_INITIALIZER
;
69 static unsigned g_thread_count
= 0;
70 static bool g_can_exit
= false;
72 // Thread routine, just call 'get_globals' and store the result in our global
73 // array, then wait for an event from the main thread. This guarantees that
74 // no thread exits before another one starts, and thus that allocation slots
76 static void* my_thread(void* param
) {
77 // Get thread-specific object pointer, store it in global array.
78 int id
= (int)(intptr_t)param
;
79 g_thread_objects
[id
] = (*g_get_globals
)();
81 // Increment global thread counter and tell the main thread about this.
82 pthread_mutex_lock(&g_lock
);
84 pthread_cond_signal(&g_cond_counter
);
86 // The thread object will be automatically released/recycled when the thread
87 // exits. Wait here until signaled by the main thread to avoid this.
89 pthread_cond_wait(&g_cond_exit
, &g_lock
);
90 pthread_mutex_unlock(&g_lock
);
97 void* lib
= dlopen("libtest_malloc_lockup.so", RTLD_NOW
);
99 fprintf(stderr
, "ERROR: Can't find library: %s\n", strerror(errno
));
103 // Extract 'get_globals' function address.
104 g_get_globals
= reinterpret_cast<get_globals_fn
>(dlsym(lib
, "get_globals"));
105 if (!g_get_globals
) {
106 fprintf(stderr
, "ERROR: Could not find 'get_globals' function: %s\n",
112 // Use a smaller stack per thread to be able to create lots of them.
114 pthread_attr_init(&attr
);
115 pthread_attr_setstacksize(&attr
, 16384);
117 // Start as many threads as needed.
118 printf("Creating %d threads\n", kMaxThreads
);
119 for (size_t n
= 0; n
< kMaxThreads
; ++n
) {
120 int ret
= pthread_create(&g_threads
[n
], &attr
, my_thread
, (void*)n
);
122 fprintf(stderr
, "ERROR: Thread #%d creation error: %s\n",
123 n
+ 1, strerror(errno
));
128 // Wait until they all ran, then tell them to exit.
129 printf("Waiting for all threads to run\n");
130 pthread_mutex_lock(&g_lock
);
131 while (g_thread_count
< kMaxThreads
)
132 pthread_cond_wait(&g_cond_counter
, &g_lock
);
134 printf("Waking up threads\n");
136 pthread_cond_broadcast(&g_cond_exit
);
137 pthread_mutex_unlock(&g_lock
);
139 // Wait for them to complete.
140 printf("Waiting for all threads to complete\n");
141 for (size_t n
= 0; n
< kMaxThreads
; ++n
) {
143 pthread_join(g_threads
[n
], &dummy
);
146 // Verify that the thread objects are all non-NULL and different.
147 printf("Checking results\n");
149 const size_t kMaxFailures
= 16;
150 for (size_t n
= 0; n
< kMaxThreads
; ++n
) {
151 void* obj
= g_thread_objects
[n
];
153 if (++failures
< kMaxFailures
)
154 printf("Thread %d got a NULL object!\n", n
+ 1);
156 for (size_t m
= n
+ 1; m
< kMaxThreads
; ++m
) {
157 if (g_thread_objects
[m
] == obj
) {
158 if (++failures
< kMaxFailures
)
159 printf("Thread %d has same object as thread %d (%p)\n",
169 fprintf(stderr
, "%d failures detected!\n", failures
);