summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: f3868fa)
raw | patch | inline | side by side (parent: f3868fa)
author | Christopher Ferris <cferris@google.com> | |
Wed, 6 Aug 2014 21:15:01 +0000 (14:15 -0700) | ||
committer | Christopher Ferris <cferris@google.com> | |
Thu, 7 Aug 2014 00:57:04 +0000 (17:57 -0700) |
During pthread_exit, the keys are cleaned. Unfortunately, a call to
free occurs after the cleanup and the memory for some of the keys
is recreated when using jemalloc. The solution is to do the key
cleanup twice.
Also, modify the pthread_detach__leak test to be less flaky
when run on a jemalloc system.
Bug: 16513133
(cherry picked from commit 18d93f2793fad393b6aa6eae6afe1054958339d5)
Change-Id: Idb32e7f9b09e2c088d256ed9eb881df80c81ff8e
free occurs after the cleanup and the memory for some of the keys
is recreated when using jemalloc. The solution is to do the key
cleanup twice.
Also, modify the pthread_detach__leak test to be less flaky
when run on a jemalloc system.
Bug: 16513133
(cherry picked from commit 18d93f2793fad393b6aa6eae6afe1054958339d5)
Change-Id: Idb32e7f9b09e2c088d256ed9eb881df80c81ff8e
libc/bionic/pthread_exit.cpp | patch | blob | history | |
tests/pthread_test.cpp | patch | blob | history |
index a6bb36312c075c39959d0284617d247dfe25d542..6cd5311ede5fc1ef47428eddf02f4d40ae88fd4e 100644 (file)
}
pthread_mutex_unlock(&g_thread_list_lock);
+ // Perform a second key cleanup. When using jemalloc, a call to free from
+ // _pthread_internal_remove_locked causes the memory associated with a key
+ // to be reallocated.
+ // TODO: When b/16847284 is fixed this call can be removed.
+ pthread_key_clean_all();
+
if (user_allocated_stack) {
// Cleaning up this thread's stack is the creator's responsibility, not ours.
__exit(0);
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 4da003f3a32a1de1778d27b96e0def952a35d304..5328e48cffa6452599bf8f4140304e1e2b74aa55 100644 (file)
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
}
TEST(pthread, pthread_detach__leak) {
- size_t initial_bytes = mallinfo().uordblks;
-
- pthread_attr_t attr;
- ASSERT_EQ(0, pthread_attr_init(&attr));
- ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
-
- std::vector<pthread_t> threads;
- for (size_t i = 0; i < 32; ++i) {
- pthread_t t;
- ASSERT_EQ(0, pthread_create(&t, &attr, IdFn, NULL));
- threads.push_back(t);
- }
-
- sleep(1);
-
- for (size_t i = 0; i < 32; ++i) {
- ASSERT_EQ(0, pthread_detach(threads[i])) << i;
+ size_t initial_bytes = 0;
+ // Run this loop more than once since the first loop causes some memory
+ // to be allocated permenantly. Run an extra loop to help catch any subtle
+ // memory leaks.
+ for (size_t loop = 0; loop < 3; loop++) {
+ // Set the initial bytes on the second loop since the memory in use
+ // should have stabilized.
+ if (loop == 1) {
+ initial_bytes = mallinfo().uordblks;
+ }
+
+ pthread_attr_t attr;
+ ASSERT_EQ(0, pthread_attr_init(&attr));
+ ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
+
+ std::vector<pthread_t> threads;
+ for (size_t i = 0; i < 32; ++i) {
+ pthread_t t;
+ ASSERT_EQ(0, pthread_create(&t, &attr, IdFn, NULL));
+ threads.push_back(t);
+ }
+
+ sleep(1);
+
+ for (size_t i = 0; i < 32; ++i) {
+ ASSERT_EQ(0, pthread_detach(threads[i])) << i;
+ }
}
size_t final_bytes = mallinfo().uordblks;
-
int leaked_bytes = (final_bytes - initial_bytes);
// User code (like this test) doesn't know how large pthread_internal_t is.