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
This commit is contained in:
Alexander Boettcher 2015-09-23 12:12:20 +02:00 committed by Christian Helmuth
parent 6f3e9c12fb
commit 3f611fe00d
6 changed files with 63 additions and 6 deletions

View File

@ -20,7 +20,7 @@ install_config {
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="test-pthread">
<resource name="RAM" quantum="2M"/>
<resource name="RAM" quantum="64M"/>
<config>
<libc stdout="/dev/log">
<vfs> <dir name="dev"> <log/> </dir> </vfs>
@ -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

View File

@ -25,6 +25,25 @@
using namespace Genode;
/*
* Structure to handle self-destructing pthreads.
*/
struct thread_cleanup : List<thread_cleanup>::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<thread_cleanup> 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> 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> 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)
{

View File

@ -70,6 +70,8 @@ extern "C" {
pthread_exit(exit_status);
}
};
void pthread_cleanup();
}
#endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */

View File

@ -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);

View File

@ -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;
}

View File

@ -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<PRTTHREADINT>(arg);
/* retry thread creation once after CPU session upgrade */