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