mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-19 23:53:55 +00:00
Add 'Thread_base::join()'
Using the new 'join()' function, the caller can explicitly block for the completion of the thread's 'entry()' function. The test case for this feature can be found at 'os/src/test/thread_join'. For hybrid Linux/Genode programs, the 'Thread_base::join()' does not map directly to 'pthread_join'. The latter function gets already called by the destructor of 'Thread_base'. According to the documentation, subsequent calls of 'pthread_join' for one thread may result in undefined behaviour. So we use a 'Genode::Lock' on this platform, which is in line with the other platforms. Related to #194, #501
This commit is contained in:
@ -40,7 +40,7 @@ static Lock &startup_lock()
|
||||
static void thread_exit_signal_handler(int) { lx_exit(0); }
|
||||
|
||||
|
||||
static void thread_start(void *arg)
|
||||
void Thread_base::_thread_start()
|
||||
{
|
||||
/*
|
||||
* Set signal handler such that canceled system calls get not
|
||||
@ -53,7 +53,7 @@ static void thread_start(void *arg)
|
||||
*/
|
||||
lx_sigaction(LX_SIGCHLD, (void (*)(int))1);
|
||||
|
||||
Thread_base *thread = (Thread_base *)arg;
|
||||
Thread_base * const thread = Thread_base::myself();
|
||||
|
||||
/* inform core about the new thread and process ID of the new thread */
|
||||
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
|
||||
@ -63,7 +63,11 @@ static void thread_start(void *arg)
|
||||
/* wakeup 'start' function */
|
||||
startup_lock().unlock();
|
||||
|
||||
Thread_base::myself()->entry();
|
||||
thread->entry();
|
||||
|
||||
/* unblock caller of 'join()' */
|
||||
thread->_join_lock.unlock();
|
||||
|
||||
sleep_forever();
|
||||
}
|
||||
|
||||
@ -125,7 +129,7 @@ void Thread_base::start()
|
||||
|
||||
/* align initial stack to 16 byte boundary */
|
||||
void *thread_sp = (void *)((addr_t)(_context->stack) & ~0xf);
|
||||
_tid.tid = lx_create_thread(thread_start, thread_sp, this);
|
||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, thread_sp, this);
|
||||
_tid.pid = lx_getpid();
|
||||
|
||||
/* wait until the 'thread_start' function got entered */
|
||||
|
@ -24,7 +24,7 @@ using namespace Genode;
|
||||
static void empty_signal_handler(int) { }
|
||||
|
||||
|
||||
static void thread_start(void *)
|
||||
void Thread_base::_thread_start()
|
||||
{
|
||||
/*
|
||||
* Set signal handler such that canceled system calls get not
|
||||
@ -52,7 +52,7 @@ void Thread_base::start()
|
||||
{
|
||||
/* align initial stack to 16 byte boundary */
|
||||
void *thread_sp = (void *)((addr_t)(_context->stack) & ~0xf);
|
||||
_tid.tid = lx_create_thread(thread_start, thread_sp, this);
|
||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, thread_sp, this);
|
||||
_tid.pid = lx_getpid();
|
||||
}
|
||||
|
||||
|
@ -306,7 +306,7 @@ inline int lx_tgkill(int pid, int tid, int signal)
|
||||
}
|
||||
|
||||
|
||||
inline int lx_create_thread(void (*entry)(void *), void *stack, void *arg)
|
||||
inline int lx_create_thread(void (*entry)(), void *stack, void *arg)
|
||||
{
|
||||
int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND
|
||||
| CLONE_THREAD | CLONE_SYSVSEM;
|
||||
|
@ -130,16 +130,26 @@ namespace Genode {
|
||||
|
||||
struct Thread_meta_data
|
||||
{
|
||||
/**
|
||||
* Lock with the initial state set to LOCKED
|
||||
*/
|
||||
struct Barrier : Lock { Barrier() : Lock(Lock::LOCKED) { } };
|
||||
|
||||
/**
|
||||
* Used to block the constructor until the new thread has initialized
|
||||
* 'id'
|
||||
*/
|
||||
Lock construct_lock;
|
||||
Barrier construct_lock;
|
||||
|
||||
/**
|
||||
* Used to block the new thread until 'start' is called
|
||||
*/
|
||||
Lock start_lock;
|
||||
Barrier start_lock;
|
||||
|
||||
/**
|
||||
* Used to block the 'join()' function until the 'entry()' is done
|
||||
*/
|
||||
Barrier join_lock;
|
||||
|
||||
/**
|
||||
* Filled out by 'thread_start' function in the context of the new
|
||||
@ -155,13 +165,9 @@ namespace Genode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param thread_base associated 'Thread_base' object
|
||||
* \param thread associated 'Thread_base' object
|
||||
*/
|
||||
Thread_meta_data(Thread_base *thread_base)
|
||||
:
|
||||
construct_lock(Lock::LOCKED), start_lock(Lock::LOCKED),
|
||||
thread_base(thread_base)
|
||||
{ }
|
||||
Thread_meta_data(Thread_base *thread) : thread_base(thread) { }
|
||||
};
|
||||
}
|
||||
|
||||
@ -224,6 +230,8 @@ static void *thread_start(void *arg)
|
||||
meta_data->start_lock.lock();
|
||||
|
||||
Thread_base::myself()->entry();
|
||||
|
||||
meta_data->join_lock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -286,8 +294,15 @@ void Thread_base::start()
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::join()
|
||||
{
|
||||
_tid.meta_data->join_lock.lock();
|
||||
}
|
||||
|
||||
|
||||
Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||
: _list_element(this)
|
||||
:
|
||||
_list_element(this)
|
||||
{
|
||||
_tid.meta_data = new (env()->heap()) Thread_meta_data(this);
|
||||
|
||||
@ -325,13 +340,9 @@ void Thread_base::cancel_blocking()
|
||||
|
||||
Thread_base::~Thread_base()
|
||||
{
|
||||
{
|
||||
int const ret = pthread_cancel(_tid.meta_data->pt);
|
||||
if (ret)
|
||||
PWRN("pthread_cancel unexpectedly returned with %d", ret);
|
||||
}
|
||||
bool const needs_join = (pthread_cancel(_tid.meta_data->pt) == 0);
|
||||
|
||||
{
|
||||
if (needs_join) {
|
||||
int const ret = pthread_join(_tid.meta_data->pt, 0);
|
||||
if (ret)
|
||||
PWRN("pthread_join unexpectedly returned with %d (errno=%d)",
|
||||
|
Reference in New Issue
Block a user