libc: use monitor for pthread join/cancel

Issue #3874
This commit is contained in:
Christian Helmuth 2020-09-02 11:27:39 +02:00 committed by Norman Feske
parent d6f89b285d
commit a891b3832c
4 changed files with 31 additions and 54 deletions

View File

@ -112,7 +112,7 @@ namespace Libc {
/** /**
* Pthread/semaphore support * 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_pthread_support(Genode::Cpu_session &, Xml_node);
void init_semaphore_support(Timer_accessor &); void init_semaphore_support(Timer_accessor &);

View File

@ -165,17 +165,7 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base
bool _exiting = false; bool _exiting = false;
/* Genode::Mutex _mutex { };
* 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;
/* return value for 'pthread_join()' */ /* return value for 'pthread_join()' */
void *_retval = PTHREAD_CANCELED; void *_retval = PTHREAD_CANCELED;
@ -189,10 +179,12 @@ struct Libc::Pthread : Noncopyable, Thread::Tls::Base
class Cleanup_handler : public List<Cleanup_handler>::Element class Cleanup_handler : public List<Cleanup_handler>::Element
{ {
private: private:
void (*_routine)(void*); void (*_routine)(void*);
void *_arg; void *_arg;
public: public:
Cleanup_handler(void (*routine)(void*), void *arg) Cleanup_handler(void (*routine)(void*), void *arg)
: _routine(routine), _arg(arg) { } : _routine(routine), _arg(arg) { }

View File

@ -453,7 +453,7 @@ Libc::Kernel::Kernel(Genode::Env &env, Genode::Allocator &heap)
atexit(close_file_descriptors_on_exit); atexit(close_file_descriptors_on_exit);
init_semaphore_support(_timer_accessor); 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()); init_pthread_support(env.cpu(), _pthread_config());
_env.ep().register_io_progress_handler(*this); _env.ep().register_io_progress_handler(*this);

View File

@ -32,8 +32,7 @@
#include <internal/init.h> #include <internal/init.h>
#include <internal/kernel.h> #include <internal/kernel.h>
#include <internal/pthread.h> #include <internal/pthread.h>
#include <internal/resume.h> #include <internal/monitor.h>
#include <internal/suspend.h>
#include <internal/time.h> #include <internal/time.h>
#include <internal/timer.h> #include <internal/timer.h>
@ -42,21 +41,28 @@ using namespace Libc;
static Thread *_main_thread_ptr; static Thread *_main_thread_ptr;
static Resume *_resume_ptr; static Monitor *_monitor_ptr;
static Suspend *_suspend_ptr;
static Timer_accessor *_timer_accessor_ptr; static Timer_accessor *_timer_accessor_ptr;
void Libc::init_pthread_support(Suspend &suspend, Resume &resume, void Libc::init_pthread_support(Monitor &monitor, Timer_accessor &timer_accessor)
Timer_accessor &timer_accessor)
{ {
_main_thread_ptr = Thread::myself(); _main_thread_ptr = Thread::myself();
_suspend_ptr = &suspend; _monitor_ptr = &monitor;
_resume_ptr = &resume;
_timer_accessor_ptr = &timer_accessor; _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 ** ** Pthread **
*************/ *************/
@ -74,47 +80,26 @@ void Libc::Pthread::Thread_object::entry()
void Libc::Pthread::join(void **retval) void Libc::Pthread::join(void **retval)
{ {
struct Check : Suspend_functor Genode::Mutex::Guard guard(_mutex);
{
bool retry { false };
Pthread &_thread; monitor().monitor(_mutex, [&] {
if (!_exiting)
Check(Pthread &thread) : _thread(thread) { } return Fn::INCOMPLETE;
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) if (retval)
*retval = _retval; *retval = _retval;
return Fn::COMPLETE;
});
} }
void Libc::Pthread::cancel() void Libc::Pthread::cancel()
{ {
Genode::Mutex::Guard guard(_mutex);
_exiting = true; _exiting = true;
struct Missing_call_of_init_pthread_support : Exception { }; monitor().trigger_monitor_examination();
if (!_resume_ptr)
throw Missing_call_of_init_pthread_support();
_resume_ptr->resume_all();
_join_blockade.wakeup();
} }
@ -278,7 +263,7 @@ class pthread_mutex : Genode::Noncopyable
/** /**
* Enqueue current context as applicant for mutex * 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) bool _apply_for_mutex(pthread_t thread, Libc::uint64_t timeout_ms)
{ {