libc: support detached pthreads

Fixes #3880
This commit is contained in:
Christian Prochaska 2020-09-08 15:06:51 +02:00 committed by Norman Feske
parent 75ba52a52b
commit e0ca250232
4 changed files with 94 additions and 8 deletions

View File

@ -976,6 +976,7 @@ _ZN4Libc7suspendERNS_15Suspend_functorEm T
_Z16pthread_registryv T _Z16pthread_registryv T
_ZN4Libc16Pthread_registry6insertERNS_7PthreadE T _ZN4Libc16Pthread_registry6insertERNS_7PthreadE T
_ZN4Libc16Pthread_registry6removeERNS_7PthreadE T _ZN4Libc16Pthread_registry6removeERNS_7PthreadE T
_ZN4Libc16Pthread_registry7cleanupEPNS_7PthreadE T
_ZN4Libc16Pthread_registry8containsERNS_7PthreadE T _ZN4Libc16Pthread_registry8containsERNS_7PthreadE T
_ZN4Libc14pthread_createEPP7pthreadPFPvS3_ES3_mPKcPN6Genode11Cpu_sessionENS8_8Affinity8LocationE T _ZN4Libc14pthread_createEPP7pthreadPFPvS3_ES3_mPKcPN6Genode11Cpu_sessionENS8_8Affinity8LocationE T
_ZN4Libc14pthread_createEPP7pthreadRN6Genode6ThreadE T _ZN4Libc14pthread_createEPP7pthreadRN6Genode6ThreadE T

View File

@ -18,6 +18,7 @@
/* Genode includes */ /* Genode includes */
#include <base/blockade.h> #include <base/blockade.h>
#include <base/sleep.h>
#include <libc/allocator.h> #include <libc/allocator.h>
#include <libc/component.h> #include <libc/component.h>
#include <util/reconstructible.h> #include <util/reconstructible.h>
@ -51,6 +52,9 @@ class Libc::Pthread_registry
Pthread *_array[MAX_NUM_PTHREADS] = { 0 }; Pthread *_array[MAX_NUM_PTHREADS] = { 0 };
/* thread to be destroyed on next 'cleanup()' call */
Pthread *_cleanup_thread { nullptr };
public: public:
void insert(Pthread &thread); void insert(Pthread &thread);
@ -58,6 +62,9 @@ class Libc::Pthread_registry
void remove(Pthread &thread); void remove(Pthread &thread);
bool contains(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 struct pthread_attr
{ {
void *stack_addr { nullptr }; void *stack_addr { nullptr };
size_t stack_size { Libc::Component::stack_size() }; 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() void _associate_thread_with_pthread()
{ {
Thread::Tls::Base::tls(_thread, *this); Thread::Tls::Base::tls(_thread, *this);
pthread_registry().cleanup();
pthread_registry().insert(*this); pthread_registry().insert(*this);
} }
@ -174,6 +183,8 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base
*/ */
Genode::Mutex _mutex { }; Genode::Mutex _mutex { };
Genode::Blockade _detach_blockade;
/* return value for 'pthread_join()' */ /* return value for 'pthread_join()' */
void *_retval = PTHREAD_CANCELED; void *_retval = PTHREAD_CANCELED;
@ -243,17 +254,29 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base
void join(void **retval); void join(void **retval);
int detach();
/* /*
* Inform the thread calling 'pthread_join()' that this thread can be * Inform the thread calling 'pthread_join()' that this thread can be
* destroyed. * destroyed.
*/ */
void cancel(); void cancel();
void exit(void *retval) void exit(void *retval) __attribute__((noreturn))
{ {
while (cleanup_pop(1)) { } while (cleanup_pop(1)) { }
_retval = retval; _retval = retval;
cancel(); 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; } void *stack_addr() const { return _stack_addr; }

View File

@ -14,7 +14,6 @@
/* Genode includes */ /* Genode includes */
#include <base/log.h> #include <base/log.h>
#include <base/sleep.h>
#include <base/thread.h> #include <base/thread.h>
#include <util/list.h> #include <util/list.h>
#include <libc/allocator.h> #include <libc/allocator.h>
@ -93,6 +92,13 @@ void Libc::Pthread::join(void **retval)
} }
int Libc::Pthread::detach()
{
_detach_blockade.wakeup();
return 0;
}
void Libc::Pthread::cancel() void Libc::Pthread::cancel()
{ {
Genode::Mutex::Guard guard(_mutex); 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() Libc::Pthread_registry &pthread_registry()
{ {
static Libc::Pthread_registry instance; static Libc::Pthread_registry instance;
@ -558,7 +578,6 @@ extern "C" {
void pthread_exit(void *value_ptr) void pthread_exit(void *value_ptr)
{ {
pthread_self()->exit(value_ptr); pthread_self()->exit(value_ptr);
sleep_forever();
} }
typeof(pthread_exit) _pthread_exit typeof(pthread_exit) _pthread_exit
@ -614,6 +633,34 @@ extern "C" {
pthread_t __sys_thr_self(void); 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) int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{ {
if (!attr || !*attr) if (!attr || !*attr)
@ -692,6 +739,15 @@ extern "C" {
__attribute__((alias("pthread_equal"))); __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, void __pthread_cleanup_push_imp(void (*routine)(void*), void *arg,
struct _pthread_cleanup_info *) struct _pthread_cleanup_info *)
{ {

View File

@ -141,9 +141,15 @@ extern "C"
if (_verbose) if (_verbose)
Genode::log("create ", pthread_name, " -> cpu ", cpu); Genode::log("create ", pthread_name, " -> cpu ", cpu);
return Libc::pthread_create(thread, start_routine, arg, stack_size, int result = Libc::pthread_create(thread, start_routine, arg, stack_size,
pthread_name.string(), _cpu_session, pthread_name.string(), _cpu_session,
location); location);
if ((result == 0) && attr && *attr &&
((*attr)->detach_state == PTHREAD_CREATE_DETACHED))
pthread_detach(*thread);
return result;
} }
typeof(pthread_create) _pthread_create typeof(pthread_create) _pthread_create