From 3f611fe00d721c58af6e93522a801f74bc27c3fc Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 23 Sep 2015 12:12:20 +0200 Subject: [PATCH] pthread: handle self destruction better Defer destruction of threads which tries to self-destruct. Check an perform cleanup of such threads during pthread_cancel and pthread_create. Issue #1687 --- repos/libports/run/pthread.run | 4 +- repos/libports/src/lib/pthread/thread.cc | 44 +++++++++++++++++-- repos/libports/src/lib/pthread/thread.h | 2 + .../libports/src/lib/pthread/thread_create.cc | 3 ++ repos/libports/src/test/pthread/main.cc | 13 +++++- repos/ports/src/virtualbox/thread.cc | 3 ++ 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/repos/libports/run/pthread.run b/repos/libports/run/pthread.run index cb7427ccab..359cea2129 100644 --- a/repos/libports/run/pthread.run +++ b/repos/libports/run/pthread.run @@ -20,7 +20,7 @@ install_config { - + @@ -35,6 +35,6 @@ build_boot_image { ld.lib.so libc.lib.so pthread.lib.so } -append qemu_args " -nographic -m 64 " +append qemu_args " -nographic -m 128 " run_genode_until {--- returning from main ---.*\n} 10 diff --git a/repos/libports/src/lib/pthread/thread.cc b/repos/libports/src/lib/pthread/thread.cc index d7f0a18919..adbaae190b 100644 --- a/repos/libports/src/lib/pthread/thread.cc +++ b/repos/libports/src/lib/pthread/thread.cc @@ -25,6 +25,25 @@ using namespace Genode; +/* + * Structure to handle self-destructing pthreads. + */ +struct thread_cleanup : List::Element +{ + pthread_t thread; + + thread_cleanup(pthread_t t) : thread(t) { } + + ~thread_cleanup() { + if (thread) + destroy(env()->heap(), thread); + } +}; + +static Lock pthread_cleanup_list_lock; +static List pthread_cleanup_list; + + extern "C" { /* Thread */ @@ -53,12 +72,31 @@ extern "C" { } - int pthread_cancel(pthread_t thread) + void pthread_cleanup() { - destroy(env()->heap(), thread); - return 0; + { + Lock_guard lock_guard(pthread_cleanup_list_lock); + + while (thread_cleanup * t = pthread_cleanup_list.first()) { + pthread_cleanup_list.remove(t); + destroy(env()->heap(), t); + } + } } + int pthread_cancel(pthread_t thread) + { + /* cleanup threads which tried to self-destruct */ + pthread_cleanup(); + + if (pthread_equal(pthread_self(), thread)) { + Lock_guard lock_guard(pthread_cleanup_list_lock); + pthread_cleanup_list.insert(new (env()->heap()) thread_cleanup(thread)); + } else + destroy(env()->heap(), thread); + + return 0; + } void pthread_exit(void *value_ptr) { diff --git a/repos/libports/src/lib/pthread/thread.h b/repos/libports/src/lib/pthread/thread.h index 2468266214..7faefd3d0d 100644 --- a/repos/libports/src/lib/pthread/thread.h +++ b/repos/libports/src/lib/pthread/thread.h @@ -70,6 +70,8 @@ extern "C" { pthread_exit(exit_status); } }; + + void pthread_cleanup(); } #endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */ diff --git a/repos/libports/src/lib/pthread/thread_create.cc b/repos/libports/src/lib/pthread/thread_create.cc index 90d8284ccc..ea4d89b149 100644 --- a/repos/libports/src/lib/pthread/thread_create.cc +++ b/repos/libports/src/lib/pthread/thread_create.cc @@ -27,6 +27,9 @@ extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { + /* cleanup threads which tried to self-destruct */ + pthread_cleanup(); + pthread_t thread_obj = new (Genode::env()->heap()) pthread(attr ? *attr : 0, start_routine, arg, STACK_SIZE, "pthread", nullptr); diff --git a/repos/libports/src/test/pthread/main.cc b/repos/libports/src/test/pthread/main.cc index 1565d7cbed..bd1657ed91 100644 --- a/repos/libports/src/test/pthread/main.cc +++ b/repos/libports/src/test/pthread/main.cc @@ -52,6 +52,8 @@ void *thread_func(void *arg) return 0; } +void *thread_func_self_destruct(void *arg) { return 0; } + static inline void compare_semaphore_values(int reported_value, int expected_value) { if (reported_value != expected_value) { @@ -60,7 +62,6 @@ static inline void compare_semaphore_values(int reported_value, int expected_val } } - int main(int argc, char **argv) { printf("--- pthread test ---\n"); @@ -131,6 +132,16 @@ int main(int argc, char **argv) for (int i = 0; i < NUM_THREADS; i++) sem_destroy(&thread[i].thread_args.thread_finished_sem); + printf("main thread: create pthreads which self de-struct\n"); + + for (unsigned i = 0 ; i < 100; i++) { + pthread_t t; + if (pthread_create(&t, 0, thread_func_self_destruct, 0) != 0) { + printf("error: pthread_create() failed\n"); + return -1; + } + } + printf("--- returning from main ---\n"); return 0; } diff --git a/repos/ports/src/virtualbox/thread.cc b/repos/ports/src/virtualbox/thread.cc index 8c3b5bd884..d607a24e2c 100644 --- a/repos/ports/src/virtualbox/thread.cc +++ b/repos/ports/src/virtualbox/thread.cc @@ -118,6 +118,9 @@ static int create_thread(pthread_t *thread, const pthread_attr_t *attr, extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { + /* cleanup threads which tried to self-destruct */ + pthread_cleanup(); + PRTTHREADINT rtthread = reinterpret_cast(arg); /* retry thread creation once after CPU session upgrade */