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
_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

View File

@ -18,6 +18,7 @@
/* Genode includes */
#include <base/blockade.h>
#include <base/sleep.h>
#include <libc/allocator.h>
#include <libc/component.h>
#include <util/reconstructible.h>
@ -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; }

View File

@ -14,7 +14,6 @@
/* Genode includes */
#include <base/log.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <util/list.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()
{
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 *)
{

View File

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