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:
parent
6f3e9c12fb
commit
3f611fe00d
|
@ -20,7 +20,7 @@ install_config {
|
||||||
<any-service> <parent/> <any-child/> </any-service>
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
</default-route>
|
</default-route>
|
||||||
<start name="test-pthread">
|
<start name="test-pthread">
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="64M"/>
|
||||||
<config>
|
<config>
|
||||||
<libc stdout="/dev/log">
|
<libc stdout="/dev/log">
|
||||||
<vfs> <dir name="dev"> <log/> </dir> </vfs>
|
<vfs> <dir name="dev"> <log/> </dir> </vfs>
|
||||||
|
@ -35,6 +35,6 @@ build_boot_image {
|
||||||
ld.lib.so libc.lib.so pthread.lib.so
|
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
|
run_genode_until {--- returning from main ---.*\n} 10
|
||||||
|
|
|
@ -25,6 +25,25 @@
|
||||||
|
|
||||||
using namespace Genode;
|
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" {
|
extern "C" {
|
||||||
|
|
||||||
/* Thread */
|
/* 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)
|
void pthread_exit(void *value_ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -70,6 +70,8 @@ extern "C" {
|
||||||
pthread_exit(exit_status);
|
pthread_exit(exit_status);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void pthread_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */
|
#endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */
|
||||||
|
|
|
@ -27,6 +27,9 @@ extern "C"
|
||||||
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
void *(*start_routine) (void *), void *arg)
|
void *(*start_routine) (void *), void *arg)
|
||||||
{
|
{
|
||||||
|
/* cleanup threads which tried to self-destruct */
|
||||||
|
pthread_cleanup();
|
||||||
|
|
||||||
pthread_t thread_obj = new (Genode::env()->heap())
|
pthread_t thread_obj = new (Genode::env()->heap())
|
||||||
pthread(attr ? *attr : 0, start_routine,
|
pthread(attr ? *attr : 0, start_routine,
|
||||||
arg, STACK_SIZE, "pthread", nullptr);
|
arg, STACK_SIZE, "pthread", nullptr);
|
||||||
|
|
|
@ -52,6 +52,8 @@ void *thread_func(void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *thread_func_self_destruct(void *arg) { return 0; }
|
||||||
|
|
||||||
static inline void compare_semaphore_values(int reported_value, int expected_value)
|
static inline void compare_semaphore_values(int reported_value, int expected_value)
|
||||||
{
|
{
|
||||||
if (reported_value != 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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
printf("--- pthread test ---\n");
|
printf("--- pthread test ---\n");
|
||||||
|
@ -131,6 +132,16 @@ int main(int argc, char **argv)
|
||||||
for (int i = 0; i < NUM_THREADS; i++)
|
for (int i = 0; i < NUM_THREADS; i++)
|
||||||
sem_destroy(&thread[i].thread_args.thread_finished_sem);
|
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");
|
printf("--- returning from main ---\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
void *(*start_routine) (void *), void *arg)
|
void *(*start_routine) (void *), void *arg)
|
||||||
{
|
{
|
||||||
|
/* cleanup threads which tried to self-destruct */
|
||||||
|
pthread_cleanup();
|
||||||
|
|
||||||
PRTTHREADINT rtthread = reinterpret_cast<PRTTHREADINT>(arg);
|
PRTTHREADINT rtthread = reinterpret_cast<PRTTHREADINT>(arg);
|
||||||
|
|
||||||
/* retry thread creation once after CPU session upgrade */
|
/* retry thread creation once after CPU session upgrade */
|
||||||
|
|
Loading…
Reference in New Issue