diff --git a/repos/libports/lib/symbols/libc b/repos/libports/lib/symbols/libc index 9f24db73d9..2975880145 100644 --- a/repos/libports/lib/symbols/libc +++ b/repos/libports/lib/symbols/libc @@ -976,6 +976,7 @@ _ZN4Libc7suspendERNS_15Suspend_functorEm T _Z16pthread_registryv T _ZN4Libc16Pthread_registry6insertERNS_7PthreadE T _ZN4Libc16Pthread_registry6removeERNS_7PthreadE T +_ZN4Libc16Pthread_registry7cleanupEPNS_7PthreadE T _ZN4Libc16Pthread_registry8containsERNS_7PthreadE T _ZN4Libc14pthread_createEPP7pthreadPFPvS3_ES3_mPKcPN6Genode11Cpu_sessionENS8_8Affinity8LocationE T _ZN4Libc14pthread_createEPP7pthreadRN6Genode6ThreadE T diff --git a/repos/libports/src/lib/libc/internal/pthread.h b/repos/libports/src/lib/libc/internal/pthread.h index c52f4baaee..6aa5f68a7a 100644 --- a/repos/libports/src/lib/libc/internal/pthread.h +++ b/repos/libports/src/lib/libc/internal/pthread.h @@ -18,6 +18,7 @@ /* Genode includes */ #include +#include #include #include #include @@ -51,6 +52,9 @@ class Libc::Pthread_registry Pthread *_array[MAX_NUM_PTHREADS] = { 0 }; + /* thread to be destroyed on next 'cleanup()' call */ + Pthread *_cleanup_thread { nullptr }; + public: void insert(Pthread &thread); @@ -58,6 +62,9 @@ class Libc::Pthread_registry void remove(Pthread &thread); bool contains(Pthread &thread); + + /* destroy '_cleanup_thread' and register another one if given */ + void cleanup(Pthread *new_cleanup_thread = nullptr); }; @@ -68,8 +75,9 @@ extern "C" { struct pthread_attr { - void *stack_addr { nullptr }; - size_t stack_size { Libc::Component::stack_size() }; + void *stack_addr { nullptr }; + size_t stack_size { Libc::Component::stack_size() }; + int detach_state { PTHREAD_CREATE_JOINABLE }; }; /* @@ -160,6 +168,7 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base void _associate_thread_with_pthread() { Thread::Tls::Base::tls(_thread, *this); + pthread_registry().cleanup(); pthread_registry().insert(*this); } @@ -174,6 +183,8 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base */ Genode::Mutex _mutex { }; + Genode::Blockade _detach_blockade; + /* return value for 'pthread_join()' */ void *_retval = PTHREAD_CANCELED; @@ -243,17 +254,29 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base void join(void **retval); + int detach(); + /* * Inform the thread calling 'pthread_join()' that this thread can be * destroyed. */ void cancel(); - void exit(void *retval) + void exit(void *retval) __attribute__((noreturn)) { while (cleanup_pop(1)) { } _retval = retval; cancel(); + + /* + * Block until the thread is destroyed by 'pthread_join()' or + * register the thread for destruction if it is in detached state. + */ + + _detach_blockade.block(); + + pthread_registry().cleanup(this); + sleep_forever(); } void *stack_addr() const { return _stack_addr; } diff --git a/repos/libports/src/lib/libc/pthread.cc b/repos/libports/src/lib/libc/pthread.cc index 2c0c274b1d..5b82f20c6f 100644 --- a/repos/libports/src/lib/libc/pthread.cc +++ b/repos/libports/src/lib/libc/pthread.cc @@ -14,7 +14,6 @@ /* Genode includes */ #include -#include #include #include #include @@ -93,6 +92,13 @@ void Libc::Pthread::join(void **retval) } +int Libc::Pthread::detach() +{ + _detach_blockade.wakeup(); + return 0; +} + + void Libc::Pthread::cancel() { Genode::Mutex::Guard guard(_mutex); @@ -147,6 +153,20 @@ bool Libc::Pthread_registry::contains(Pthread &thread) } +void Libc::Pthread_registry::cleanup(Pthread *new_cleanup_thread) +{ + static Mutex cleanup_mutex; + Mutex::Guard guard(cleanup_mutex); + + if (_cleanup_thread) { + Libc::Allocator alloc { }; + destroy(alloc, _cleanup_thread); + } + + _cleanup_thread = new_cleanup_thread; +} + + Libc::Pthread_registry &pthread_registry() { static Libc::Pthread_registry instance; @@ -558,7 +578,6 @@ extern "C" { void pthread_exit(void *value_ptr) { pthread_self()->exit(value_ptr); - sleep_forever(); } typeof(pthread_exit) _pthread_exit @@ -614,6 +633,34 @@ extern "C" { pthread_t __sys_thr_self(void); + int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) + { + if (!attr || !*attr || !detachstate) + return EINVAL; + + *detachstate = (*attr)->detach_state; + + return 0; + } + + typeof(pthread_attr_getdetachstate) _pthread_attr_getdetachstate + __attribute__((alias("pthread_attr_getdetachstate"))); + + + int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) + { + if (!attr || !*attr) + return EINVAL; + + (*attr)->detach_state = detachstate; + + return 0; + } + + typeof(pthread_attr_setdetachstate) _pthread_attr_setdetachstate + __attribute__((alias("pthread_attr_setdetachstate"))); + + int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) { if (!attr || !*attr) @@ -692,6 +739,15 @@ extern "C" { __attribute__((alias("pthread_equal"))); + int pthread_detach(pthread_t thread) + { + return thread->detach(); + } + + typeof(pthread_detach) _pthread_detach + __attribute__((alias("pthread_detach"))); + + void __pthread_cleanup_push_imp(void (*routine)(void*), void *arg, struct _pthread_cleanup_info *) { diff --git a/repos/libports/src/lib/libc/pthread_create.cc b/repos/libports/src/lib/libc/pthread_create.cc index 8ba2643c5c..55b8439162 100644 --- a/repos/libports/src/lib/libc/pthread_create.cc +++ b/repos/libports/src/lib/libc/pthread_create.cc @@ -141,9 +141,15 @@ extern "C" if (_verbose) Genode::log("create ", pthread_name, " -> cpu ", cpu); - return Libc::pthread_create(thread, start_routine, arg, stack_size, - pthread_name.string(), _cpu_session, - location); + int result = Libc::pthread_create(thread, start_routine, arg, stack_size, + pthread_name.string(), _cpu_session, + location); + + if ((result == 0) && attr && *attr && + ((*attr)->detach_state == PTHREAD_CREATE_DETACHED)) + pthread_detach(*thread); + + return result; } typeof(pthread_create) _pthread_create