aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYabin Cui2014-12-19 18:10:38 -0600
committerGerrit Code Review2014-12-19 18:10:38 -0600
commitcdc7ad11e931ed9fc329b96e880f22e24be1c267 (patch)
tree984fc14c46e87b17635e004747cd993c87f492c3
parente28a1864916373f4c520f2a8be1c1c7ea97424cf (diff)
parent8cf1b305670123aed7638d984ca39bfd22388440 (diff)
downloadplatform-bionic-cdc7ad11e931ed9fc329b96e880f22e24be1c267.tar.gz
platform-bionic-cdc7ad11e931ed9fc329b96e880f22e24be1c267.tar.xz
platform-bionic-cdc7ad11e931ed9fc329b96e880f22e24be1c267.zip
Merge "Use mmap to create the pthread_internal_t"
-rw-r--r--benchmarks/pthread_benchmark.cpp92
-rw-r--r--libc/bionic/libc_init_common.cpp4
-rw-r--r--libc/bionic/pthread_create.cpp91
-rw-r--r--libc/bionic/pthread_detach.cpp2
-rw-r--r--libc/bionic/pthread_exit.cpp26
-rw-r--r--libc/bionic/pthread_internal.h12
-rw-r--r--libc/bionic/pthread_internals.cpp30
-rw-r--r--libc/bionic/pthread_join.cpp2
8 files changed, 171 insertions, 88 deletions
diff --git a/benchmarks/pthread_benchmark.cpp b/benchmarks/pthread_benchmark.cpp
index 92e59982..42023e04 100644
--- a/benchmarks/pthread_benchmark.cpp
+++ b/benchmarks/pthread_benchmark.cpp
@@ -47,6 +47,21 @@ static void BM_pthread_getspecific(int iters) {
47} 47}
48BENCHMARK(BM_pthread_getspecific); 48BENCHMARK(BM_pthread_getspecific);
49 49
50static void BM_pthread_setspecific(int iters) {
51 StopBenchmarkTiming();
52 pthread_key_t key;
53 pthread_key_create(&key, NULL);
54 StartBenchmarkTiming();
55
56 for (int i = 0; i < iters; ++i) {
57 pthread_setspecific(key, NULL);
58 }
59
60 StopBenchmarkTiming();
61 pthread_key_delete(key);
62}
63BENCHMARK(BM_pthread_setspecific);
64
50static void DummyPthreadOnceInitFunction() { 65static void DummyPthreadOnceInitFunction() {
51} 66}
52 67
@@ -137,3 +152,80 @@ static void BM_pthread_rw_lock_write(int iters) {
137 pthread_rwlock_destroy(&lock); 152 pthread_rwlock_destroy(&lock);
138} 153}
139BENCHMARK(BM_pthread_rw_lock_write); 154BENCHMARK(BM_pthread_rw_lock_write);
155
156static void* IdleThread(void*) {
157 return NULL;
158}
159
160static void BM_pthread_create(int iters) {
161 StopBenchmarkTiming();
162 pthread_t thread;
163
164 for (int i = 0; i < iters; ++i) {
165 StartBenchmarkTiming();
166 pthread_create(&thread, NULL, IdleThread, NULL);
167 StopBenchmarkTiming();
168 pthread_join(thread, NULL);
169 }
170}
171BENCHMARK(BM_pthread_create);
172
173static void* RunThread(void*) {
174 StopBenchmarkTiming();
175 return NULL;
176}
177
178static void BM_pthread_create_and_run(int iters) {
179 StopBenchmarkTiming();
180 pthread_t thread;
181
182 for (int i = 0; i < iters; ++i) {
183 StartBenchmarkTiming();
184 pthread_create(&thread, NULL, RunThread, NULL);
185 pthread_join(thread, NULL);
186 }
187}
188BENCHMARK(BM_pthread_create_and_run);
189
190static void* ExitThread(void*) {
191 StartBenchmarkTiming();
192 pthread_exit(NULL);
193}
194
195static void BM_pthread_exit_and_join(int iters) {
196 StopBenchmarkTiming();
197 pthread_t thread;
198
199 for (int i = 0; i < iters; ++i) {
200 pthread_create(&thread, NULL, ExitThread, NULL);
201 pthread_join(thread, NULL);
202 StopBenchmarkTiming();
203 }
204}
205BENCHMARK(BM_pthread_exit_and_join);
206
207static void BM_pthread_key_create(int iters) {
208 StopBenchmarkTiming();
209 pthread_key_t key;
210
211 for (int i = 0; i < iters; ++i) {
212 StartBenchmarkTiming();
213 pthread_key_create(&key, NULL);
214 StopBenchmarkTiming();
215 pthread_key_delete(key);
216 }
217}
218BENCHMARK(BM_pthread_key_create);
219
220static void BM_pthread_key_delete(int iters) {
221 StopBenchmarkTiming();
222 pthread_key_t key;
223
224 for (int i = 0; i < iters; ++i) {
225 pthread_key_create(&key, NULL);
226 StartBenchmarkTiming();
227 pthread_key_delete(key);
228 StopBenchmarkTiming();
229 }
230}
231BENCHMARK(BM_pthread_key_delete);
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 2a6a03b5..15b3fd5e 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -74,9 +74,7 @@ uintptr_t __stack_chk_guard = 0;
74void __libc_init_tls(KernelArgumentBlock& args) { 74void __libc_init_tls(KernelArgumentBlock& args) {
75 __libc_auxv = args.auxv; 75 __libc_auxv = args.auxv;
76 76
77 static void* tls[BIONIC_TLS_SLOTS];
78 static pthread_internal_t main_thread; 77 static pthread_internal_t main_thread;
79 main_thread.tls = tls;
80 78
81 // Tell the kernel to clear our tid field when we exit, so we're like any other pthread. 79 // Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
82 // As a side-effect, this tells us our pid (which is the same as the main thread's tid). 80 // As a side-effect, this tells us our pid (which is the same as the main thread's tid).
@@ -96,7 +94,7 @@ void __libc_init_tls(KernelArgumentBlock& args) {
96 __init_thread(&main_thread, false); 94 __init_thread(&main_thread, false);
97 __init_tls(&main_thread); 95 __init_tls(&main_thread);
98 __set_tls(main_thread.tls); 96 __set_tls(main_thread.tls);
99 tls[TLS_SLOT_BIONIC_PREINIT] = &args; 97 main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
100 98
101 __init_alternate_signal_stack(&main_thread); 99 __init_alternate_signal_stack(&main_thread);
102} 100}
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index c99e69c9..c47b7504 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -35,6 +35,7 @@
35#include "pthread_internal.h" 35#include "pthread_internal.h"
36 36
37#include "private/bionic_macros.h" 37#include "private/bionic_macros.h"
38#include "private/bionic_prctl.h"
38#include "private/bionic_ssp.h" 39#include "private/bionic_ssp.h"
39#include "private/bionic_tls.h" 40#include "private/bionic_tls.h"
40#include "private/libc_logging.h" 41#include "private/libc_logging.h"
@@ -72,6 +73,10 @@ void __init_alternate_signal_stack(pthread_internal_t* thread) {
72 ss.ss_flags = 0; 73 ss.ss_flags = 0;
73 sigaltstack(&ss, NULL); 74 sigaltstack(&ss, NULL);
74 thread->alternate_signal_stack = ss.ss_sp; 75 thread->alternate_signal_stack = ss.ss_sp;
76
77 // We can only use const static allocated string for mapped region name, as Android kernel
78 // uses the string pointer directly when dumping /proc/pid/maps.
79 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
75 } 80 }
76} 81}
77 82
@@ -101,31 +106,64 @@ int __init_thread(pthread_internal_t* thread, bool add_to_thread_list) {
101 return error; 106 return error;
102} 107}
103 108
104static void* __create_thread_stack(pthread_internal_t* thread) { 109static void* __create_thread_stack(const pthread_attr_t& attr) {
105 // Create a new private anonymous map. 110 // Create a new private anonymous map.
106 int prot = PROT_READ | PROT_WRITE; 111 int prot = PROT_READ | PROT_WRITE;
107 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; 112 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
108 void* stack = mmap(NULL, thread->attr.stack_size, prot, flags, -1, 0); 113 void* stack = mmap(NULL, attr.stack_size, prot, flags, -1, 0);
109 if (stack == MAP_FAILED) { 114 if (stack == MAP_FAILED) {
110 __libc_format_log(ANDROID_LOG_WARN, 115 __libc_format_log(ANDROID_LOG_WARN,
111 "libc", 116 "libc",
112 "pthread_create failed: couldn't allocate %zd-byte stack: %s", 117 "pthread_create failed: couldn't allocate %zd-byte stack: %s",
113 thread->attr.stack_size, strerror(errno)); 118 attr.stack_size, strerror(errno));
114 return NULL; 119 return NULL;
115 } 120 }
116 121
117 // Set the guard region at the end of the stack to PROT_NONE. 122 // Set the guard region at the end of the stack to PROT_NONE.
118 if (mprotect(stack, thread->attr.guard_size, PROT_NONE) == -1) { 123 if (mprotect(stack, attr.guard_size, PROT_NONE) == -1) {
119 __libc_format_log(ANDROID_LOG_WARN, "libc", 124 __libc_format_log(ANDROID_LOG_WARN, "libc",
120 "pthread_create failed: couldn't mprotect PROT_NONE %zd-byte stack guard region: %s", 125 "pthread_create failed: couldn't mprotect PROT_NONE %zd-byte stack guard region: %s",
121 thread->attr.guard_size, strerror(errno)); 126 attr.guard_size, strerror(errno));
122 munmap(stack, thread->attr.stack_size); 127 munmap(stack, attr.stack_size);
123 return NULL; 128 return NULL;
124 } 129 }
125 130
126 return stack; 131 return stack;
127} 132}
128 133
134static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, void** child_stack) {
135 if (attr->stack_base == NULL) {
136 // The caller didn't provide a stack, so allocate one.
137 // Make sure the stack size and guard size are multiples of PAGE_SIZE.
138 attr->stack_size = BIONIC_ALIGN(attr->stack_size, PAGE_SIZE);
139 attr->guard_size = BIONIC_ALIGN(attr->guard_size, PAGE_SIZE);
140 attr->stack_base = __create_thread_stack(*attr);
141 if (attr->stack_base == NULL) {
142 return EAGAIN;
143 }
144 } else {
145 // The caller did provide a stack, so remember we're not supposed to free it.
146 attr->flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
147 }
148
149 // Thread stack is used for two sections:
150 // pthread_internal_t.
151 // regular stack, from top to down.
152 uint8_t* stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + attr->stack_size;
153 stack_top -= sizeof(pthread_internal_t);
154 pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
155
156 // No need to check stack_top alignment. The size of pthread_internal_t is 16-bytes aligned,
157 // and user allocated stack is guaranteed by pthread_attr_setstack.
158
159 thread->attr = *attr;
160 __init_tls(thread);
161
162 *threadp = thread;
163 *child_stack = stack_top;
164 return 0;
165}
166
129static int __pthread_start(void* arg) { 167static int __pthread_start(void* arg) {
130 pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg); 168 pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
131 169
@@ -158,43 +196,21 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
158 // Inform the rest of the C library that at least one thread was created. 196 // Inform the rest of the C library that at least one thread was created.
159 __isthreaded = 1; 197 __isthreaded = 1;
160 198
161 pthread_internal_t* thread = __create_thread_struct(); 199 pthread_attr_t thread_attr;
162 if (thread == NULL) {
163 return EAGAIN;
164 }
165
166 if (attr == NULL) { 200 if (attr == NULL) {
167 pthread_attr_init(&thread->attr); 201 pthread_attr_init(&thread_attr);
168 } else { 202 } else {
169 thread->attr = *attr; 203 thread_attr = *attr;
170 attr = NULL; // Prevent misuse below. 204 attr = NULL; // Prevent misuse below.
171 } 205 }
172 206
173 // Make sure the stack size and guard size are multiples of PAGE_SIZE. 207 pthread_internal_t* thread = NULL;
174 thread->attr.stack_size = BIONIC_ALIGN(thread->attr.stack_size, PAGE_SIZE); 208 void* child_stack = NULL;
175 thread->attr.guard_size = BIONIC_ALIGN(thread->attr.guard_size, PAGE_SIZE); 209 int result = __allocate_thread(&thread_attr, &thread, &child_stack);
176 210 if (result != 0) {
177 if (thread->attr.stack_base == NULL) { 211 return result;
178 // The caller didn't provide a stack, so allocate one.
179 thread->attr.stack_base = __create_thread_stack(thread);
180 if (thread->attr.stack_base == NULL) {
181 __free_thread_struct(thread);
182 return EAGAIN;
183 }
184 } else {
185 // The caller did provide a stack, so remember we're not supposed to free it.
186 thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
187 } 212 }
188 213
189 // Make room for the TLS area.
190 // The child stack is the same address, just growing in the opposite direction.
191 // At offsets >= 0, we have the TLS slots.
192 // At offsets < 0, we have the child stack.
193 thread->tls = reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(thread->attr.stack_base) +
194 thread->attr.stack_size - BIONIC_ALIGN(BIONIC_TLS_SLOTS * sizeof(void*), 16));
195 void* child_stack = thread->tls;
196 __init_tls(thread);
197
198 // Create a mutex for the thread in TLS to wait on once it starts so we can keep 214 // Create a mutex for the thread in TLS to wait on once it starts so we can keep
199 // it from doing anything until after we notify the debugger about it 215 // it from doing anything until after we notify the debugger about it
200 // 216 //
@@ -211,7 +227,7 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
211 227
212 int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | 228 int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
213 CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; 229 CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
214 void* tls = thread->tls; 230 void* tls = reinterpret_cast<void*>(thread->tls);
215#if defined(__i386__) 231#if defined(__i386__)
216 // On x86 (but not x86-64), CLONE_SETTLS takes a pointer to a struct user_desc rather than 232 // On x86 (but not x86-64), CLONE_SETTLS takes a pointer to a struct user_desc rather than
217 // a pointer to the TLS itself. 233 // a pointer to the TLS itself.
@@ -229,7 +245,6 @@ int pthread_create(pthread_t* thread_out, pthread_attr_t const* attr,
229 if (!thread->user_allocated_stack()) { 245 if (!thread->user_allocated_stack()) {
230 munmap(thread->attr.stack_base, thread->attr.stack_size); 246 munmap(thread->attr.stack_base, thread->attr.stack_size);
231 } 247 }
232 __free_thread_struct(thread);
233 __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno)); 248 __libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
234 return clone_errno; 249 return clone_errno;
235 } 250 }
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp
index a8608e3a..715acf13 100644
--- a/libc/bionic/pthread_detach.cpp
+++ b/libc/bionic/pthread_detach.cpp
@@ -46,7 +46,7 @@ int pthread_detach(pthread_t t) {
46 46
47 if (thread->tid == 0) { 47 if (thread->tid == 0) {
48 // Already exited; clean up. 48 // Already exited; clean up.
49 _pthread_internal_remove_locked(thread.get()); 49 _pthread_internal_remove_locked(thread.get(), true);
50 return 0; 50 return 0;
51 } 51 }
52 52
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index a6bb3631..e04cf8e7 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -90,7 +90,7 @@ void pthread_exit(void* return_value) {
90 // Keep track of what we need to know about the stack before we lose the pthread_internal_t. 90 // Keep track of what we need to know about the stack before we lose the pthread_internal_t.
91 void* stack_base = thread->attr.stack_base; 91 void* stack_base = thread->attr.stack_base;
92 size_t stack_size = thread->attr.stack_size; 92 size_t stack_size = thread->attr.stack_size;
93 bool user_allocated_stack = thread->user_allocated_stack(); 93 bool free_stack = false;
94 94
95 pthread_mutex_lock(&g_thread_list_lock); 95 pthread_mutex_lock(&g_thread_list_lock);
96 if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) { 96 if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
@@ -98,24 +98,18 @@ void pthread_exit(void* return_value) {
98 // First make sure that the kernel does not try to clear the tid field 98 // First make sure that the kernel does not try to clear the tid field
99 // because we'll have freed the memory before the thread actually exits. 99 // because we'll have freed the memory before the thread actually exits.
100 __set_tid_address(NULL); 100 __set_tid_address(NULL);
101 _pthread_internal_remove_locked(thread); 101
102 } else { 102 // pthread_internal_t is freed below with stack, not here.
103 // Make sure that the pthread_internal_t doesn't have stale pointers to a stack that 103 _pthread_internal_remove_locked(thread, false);
104 // will be unmapped after the exit call below. 104 if (!thread->user_allocated_stack()) {
105 if (!user_allocated_stack) { 105 free_stack = true;
106 thread->attr.stack_base = NULL;
107 thread->attr.stack_size = 0;
108 thread->tls = NULL;
109 } 106 }
110 // pthread_join is responsible for destroying the pthread_internal_t for non-detached threads.
111 // The kernel will futex_wake on the pthread_internal_t::tid field to wake pthread_join.
112 } 107 }
113 pthread_mutex_unlock(&g_thread_list_lock); 108 pthread_mutex_unlock(&g_thread_list_lock);
114 109
115 if (user_allocated_stack) { 110 // Detached threads exit with stack teardown, and everything deallocated here.
116 // Cleaning up this thread's stack is the creator's responsibility, not ours. 111 // Threads that can be joined exit but leave their stacks for the pthread_join caller to clean up.
117 __exit(0); 112 if (free_stack) {
118 } else {
119 // We need to munmap the stack we're running on before calling exit. 113 // We need to munmap the stack we're running on before calling exit.
120 // That's not something we can do in C. 114 // That's not something we can do in C.
121 115
@@ -126,5 +120,7 @@ void pthread_exit(void* return_value) {
126 sigprocmask(SIG_SETMASK, &mask, NULL); 120 sigprocmask(SIG_SETMASK, &mask, NULL);
127 121
128 _exit_with_stack_teardown(stack_base, stack_size); 122 _exit_with_stack_teardown(stack_base, stack_size);
123 } else {
124 __exit(0);
129 } 125 }
130} 126}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index c5136c93..95097b7e 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -30,6 +30,8 @@
30 30
31#include <pthread.h> 31#include <pthread.h>
32 32
33#include "private/bionic_tls.h"
34
33/* Has the thread been detached by a pthread_join or pthread_detach call? */ 35/* Has the thread been detached by a pthread_join or pthread_detach call? */
34#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001 36#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
35 37
@@ -72,8 +74,6 @@ struct pthread_internal_t {
72 return (attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) != 0; 74 return (attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) != 0;
73 } 75 }
74 76
75 void** tls;
76
77 pthread_attr_t attr; 77 pthread_attr_t attr;
78 78
79 __pthread_cleanup_t* cleanup_stack; 79 __pthread_cleanup_t* cleanup_stack;
@@ -86,16 +86,16 @@ struct pthread_internal_t {
86 86
87 pthread_mutex_t startup_handshake_mutex; 87 pthread_mutex_t startup_handshake_mutex;
88 88
89 void* tls[BIONIC_TLS_SLOTS];
90
89 /* 91 /*
90 * The dynamic linker implements dlerror(3), which makes it hard for us to implement this 92 * The dynamic linker implements dlerror(3), which makes it hard for us to implement this
91 * per-thread buffer by simply using malloc(3) and free(3). 93 * per-thread buffer by simply using malloc(3) and free(3).
92 */ 94 */
93#define __BIONIC_DLERROR_BUFFER_SIZE 512 95#define __BIONIC_DLERROR_BUFFER_SIZE 512
94 char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE]; 96 char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE];
95}; 97} __attribute__((aligned(16))); // Align it as thread stack top below it should be aligned.
96 98
97__LIBC_HIDDEN__ pthread_internal_t* __create_thread_struct();
98__LIBC_HIDDEN__ void __free_thread_struct(pthread_internal_t*);
99__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread, bool add_to_thread_list); 99__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread, bool add_to_thread_list);
100__LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread); 100__LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread);
101__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*); 101__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
@@ -105,7 +105,7 @@ __LIBC_HIDDEN__ void _pthread_internal_add(pthread_internal_t* thread);
105extern "C" __LIBC64_HIDDEN__ pthread_internal_t* __get_thread(void); 105extern "C" __LIBC64_HIDDEN__ pthread_internal_t* __get_thread(void);
106 106
107__LIBC_HIDDEN__ void pthread_key_clean_all(void); 107__LIBC_HIDDEN__ void pthread_key_clean_all(void);
108__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread); 108__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread);
109 109
110/* 110/*
111 * Traditionally we gave threads a 1MiB stack. When we started 111 * Traditionally we gave threads a 1MiB stack. When we started
diff --git a/libc/bionic/pthread_internals.cpp b/libc/bionic/pthread_internals.cpp
index 33cddd74..7c30e6e4 100644
--- a/libc/bionic/pthread_internals.cpp
+++ b/libc/bionic/pthread_internals.cpp
@@ -41,26 +41,7 @@
41pthread_internal_t* g_thread_list = NULL; 41pthread_internal_t* g_thread_list = NULL;
42pthread_mutex_t g_thread_list_lock = PTHREAD_MUTEX_INITIALIZER; 42pthread_mutex_t g_thread_list_lock = PTHREAD_MUTEX_INITIALIZER;
43 43
44pthread_internal_t* __create_thread_struct() { 44void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread) {
45 void* result = mmap(NULL, sizeof(pthread_internal_t), PROT_READ | PROT_WRITE,
46 MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
47 if (result == MAP_FAILED) {
48 __libc_format_log(ANDROID_LOG_WARN, "libc",
49 "__create_thread_struct() failed: %s", strerror(errno));
50 return NULL;
51 }
52 return reinterpret_cast<pthread_internal_t*>(result);
53}
54
55void __free_thread_struct(pthread_internal_t* thread) {
56 int result = munmap(thread, sizeof(pthread_internal_t));
57 if (result != 0) {
58 __libc_format_log(ANDROID_LOG_WARN, "libc",
59 "__free_thread_struct() failed: %s", strerror(errno));
60 }
61}
62
63void _pthread_internal_remove_locked(pthread_internal_t* thread) {
64 if (thread->next != NULL) { 45 if (thread->next != NULL) {
65 thread->next->prev = thread->prev; 46 thread->next->prev = thread->prev;
66 } 47 }
@@ -70,10 +51,11 @@ void _pthread_internal_remove_locked(pthread_internal_t* thread) {
70 g_thread_list = thread->next; 51 g_thread_list = thread->next;
71 } 52 }
72 53
73 // The main thread is not heap-allocated. See __libc_init_tls for the declaration, 54 // For threads using user allocated stack (including the main thread), the pthread_internal_t
74 // and __libc_init_common for the point where it's added to the thread list. 55 // can't be freed since it is on the stack.
75 if ((thread->attr.flags & PTHREAD_ATTR_FLAG_MAIN_THREAD) == 0) { 56 if (free_thread && !(thread->attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK)) {
76 __free_thread_struct(thread); 57 // Use one munmap to free the whole thread stack, including pthread_internal_t.
58 munmap(thread->attr.stack_base, thread->attr.stack_size);
77 } 59 }
78} 60}
79 61
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
index 0cbed62b..e3350efd 100644
--- a/libc/bionic/pthread_join.cpp
+++ b/libc/bionic/pthread_join.cpp
@@ -74,6 +74,6 @@ int pthread_join(pthread_t t, void** return_value) {
74 *return_value = thread->return_value; 74 *return_value = thread->return_value;
75 } 75 }
76 76
77 _pthread_internal_remove_locked(thread.get()); 77 _pthread_internal_remove_locked(thread.get(), true);
78 return 0; 78 return 0;
79} 79}