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
*/
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 &);

View File

@ -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<Cleanup_handler>::Element
{
private:
void (*_routine)(void*);
void *_arg;
public:
Cleanup_handler(void (*routine)(void*), void *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);
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);

View File

@ -32,8 +32,7 @@
#include <internal/init.h>
#include <internal/kernel.h>
#include <internal/pthread.h>
#include <internal/resume.h>
#include <internal/suspend.h>
#include <internal/monitor.h>
#include <internal/time.h>
#include <internal/timer.h>
@ -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)
{