From a891b3832c60c2af42c74d1918e27d71b65a7762 Mon Sep 17 00:00:00 2001 From: Christian Helmuth Date: Wed, 2 Sep 2020 11:27:39 +0200 Subject: [PATCH] libc: use monitor for pthread join/cancel Issue #3874 --- repos/libports/src/lib/libc/internal/init.h | 2 +- .../libports/src/lib/libc/internal/pthread.h | 14 +--- repos/libports/src/lib/libc/kernel.cc | 2 +- repos/libports/src/lib/libc/pthread.cc | 67 +++++++------------ 4 files changed, 31 insertions(+), 54 deletions(-) diff --git a/repos/libports/src/lib/libc/internal/init.h b/repos/libports/src/lib/libc/internal/init.h index 2436b97494..afb5b09ae6 100644 --- a/repos/libports/src/lib/libc/internal/init.h +++ b/repos/libports/src/lib/libc/internal/init.h @@ -112,7 +112,7 @@ namespace Libc { /** * Pthread/semaphore support */ - void init_pthread_support(Suspend &, Resume &, Timer_accessor &); + void init_pthread_support(Monitor &, Timer_accessor &); void init_pthread_support(Genode::Cpu_session &, Xml_node); void init_semaphore_support(Timer_accessor &); diff --git a/repos/libports/src/lib/libc/internal/pthread.h b/repos/libports/src/lib/libc/internal/pthread.h index a74380386a..33f9fcd580 100644 --- a/repos/libports/src/lib/libc/internal/pthread.h +++ b/repos/libports/src/lib/libc/internal/pthread.h @@ -165,17 +165,7 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base bool _exiting = false; - /* - * The join blockade is needed because 'Libc::resume_all()' uses a - * 'Signal_transmitter' which holds a reference to a signal context - * capability, which needs to be released before the thread can be - * destroyed. - * - * Also, we cannot use 'Thread::join()', because it only - * returns when the thread entry function returns, which does not - * happen with 'pthread_cancel()'. - */ - Genode::Blockade _join_blockade; + Genode::Mutex _mutex { }; /* return value for 'pthread_join()' */ void *_retval = PTHREAD_CANCELED; @@ -189,10 +179,12 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base class Cleanup_handler : public List::Element { private: + void (*_routine)(void*); void *_arg; public: + Cleanup_handler(void (*routine)(void*), void *arg) : _routine(routine), _arg(arg) { } diff --git a/repos/libports/src/lib/libc/kernel.cc b/repos/libports/src/lib/libc/kernel.cc index a1baad5e56..81c7b98258 100644 --- a/repos/libports/src/lib/libc/kernel.cc +++ b/repos/libports/src/lib/libc/kernel.cc @@ -453,7 +453,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap) atexit(close_file_descriptors_on_exit); init_semaphore_support(_timer_accessor); - init_pthread_support(*this, *this, _timer_accessor); + init_pthread_support(*this, _timer_accessor); init_pthread_support(env.cpu(), _pthread_config()); _env.ep().register_io_progress_handler(*this); diff --git a/repos/libports/src/lib/libc/pthread.cc b/repos/libports/src/lib/libc/pthread.cc index cefa5f8e7b..f11cce409c 100644 --- a/repos/libports/src/lib/libc/pthread.cc +++ b/repos/libports/src/lib/libc/pthread.cc @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #include #include @@ -42,21 +41,28 @@ using namespace Libc; static Thread *_main_thread_ptr; -static Resume *_resume_ptr; -static Suspend *_suspend_ptr; +static Monitor *_monitor_ptr; static Timer_accessor *_timer_accessor_ptr; -void Libc::init_pthread_support(Suspend &suspend, Resume &resume, - Timer_accessor &timer_accessor) +void Libc::init_pthread_support(Monitor &monitor, Timer_accessor &timer_accessor) { _main_thread_ptr = Thread::myself(); - _suspend_ptr = &suspend; - _resume_ptr = &resume; + _monitor_ptr = &monitor; _timer_accessor_ptr = &timer_accessor; } +static Libc::Monitor & monitor() +{ + struct Missing_call_of_init_pthread_support : Genode::Exception { }; + if (!_monitor_ptr) + throw Missing_call_of_init_pthread_support(); + return *_monitor_ptr; +} + +namespace { using Fn = Libc::Monitor::Function_result; } + /************* ** Pthread ** *************/ @@ -74,47 +80,26 @@ void Libc::Pthread::Thread_object::entry() void Libc::Pthread::join(void **retval) { - struct Check : Suspend_functor - { - bool retry { false }; + Genode::Mutex::Guard guard(_mutex); - Pthread &_thread; + monitor().monitor(_mutex, [&] { + if (!_exiting) + return Fn::INCOMPLETE; - Check(Pthread &thread) : _thread(thread) { } - - bool suspend() override - { - retry = !_thread._exiting; - return retry; - } - } check(*this); - - struct Missing_call_of_init_pthread_support : Exception { }; - if (!_suspend_ptr) - throw Missing_call_of_init_pthread_support(); - - do { - _suspend_ptr->suspend(check); - } while (check.retry); - - _join_blockade.block(); - - if (retval) - *retval = _retval; + if (retval) + *retval = _retval; + return Fn::COMPLETE; + }); } void Libc::Pthread::cancel() { + Genode::Mutex::Guard guard(_mutex); + _exiting = true; - struct Missing_call_of_init_pthread_support : Exception { }; - if (!_resume_ptr) - throw Missing_call_of_init_pthread_support(); - - _resume_ptr->resume_all(); - - _join_blockade.wakeup(); + monitor().trigger_monitor_examination(); } @@ -278,7 +263,7 @@ class pthread_mutex : Genode::Noncopyable /** * Enqueue current context as applicant for mutex * - * Return true if mutex was aquired, false on timeout expiration. + * Return true if mutex was acquired, false on timeout expiration. */ bool _apply_for_mutex(pthread_t thread, Libc::uint64_t timeout_ms) {