Merge "Fix pthread_detach for already-exited threads."

This commit is contained in:
Elliott Hughes 2014-03-08 03:07:46 +00:00 committed by Gerrit Code Review
commit fd9e20d10f
2 changed files with 36 additions and 0 deletions

View file

@ -44,6 +44,12 @@ int pthread_detach(pthread_t t) {
return 0; // Already being joined; silently do nothing, like glibc.
}
if (thread->tid == 0) {
// Already exited; clean up.
_pthread_internal_remove_locked(thread.get());
return 0;
}
thread->attr.flags |= PTHREAD_ATTR_FLAG_DETACHED;
return 0;
}

View file

@ -19,6 +19,7 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <malloc.h>
#include <pthread.h>
#include <signal.h>
#include <sys/mman.h>
@ -350,6 +351,35 @@ TEST(pthread, pthread_detach__no_such_thread) {
ASSERT_EQ(ESRCH, pthread_detach(dead_thread));
}
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 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.
// We can be pretty sure it's more than 128 bytes.
ASSERT_LT(leaked_bytes, 32 /*threads*/ * 128 /*bytes*/);
}
TEST(pthread, pthread_getcpuclockid__clock_gettime) {
pthread_t t;
ASSERT_EQ(0, pthread_create(&t, NULL, SleepFn, reinterpret_cast<void*>(5)));