committed by
Christian Helmuth
parent
dc0ebba1ec
commit
da5d182ad3
@@ -20,39 +20,6 @@
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Native thread contains more thread-local data than just the ID
|
||||
*/
|
||||
struct Native_thread
|
||||
{
|
||||
/*
|
||||
* Unfortunately, both - PID and TID - are needed for lx_tgkill()
|
||||
*/
|
||||
unsigned int tid = 0; /* Native thread ID type as returned by the
|
||||
'clone' system call */
|
||||
unsigned int pid = 0; /* process ID (resp. thread-group ID) */
|
||||
|
||||
bool is_ipc_server = false;
|
||||
|
||||
/**
|
||||
* Natively aligned memory location used in the lock implementation
|
||||
*/
|
||||
int futex_counter __attribute__((aligned(sizeof(Genode::addr_t)))) = 0;
|
||||
|
||||
struct Meta_data;
|
||||
|
||||
/**
|
||||
* Opaque pointer to additional thread-specific meta data
|
||||
*
|
||||
* This pointer is used by hybrid Linux/Genode programs to maintain
|
||||
* POSIX-thread-related meta data. For non-hybrid Genode programs, it
|
||||
* remains unused.
|
||||
*/
|
||||
Meta_data *meta_data = nullptr;
|
||||
|
||||
Native_thread() { }
|
||||
};
|
||||
|
||||
struct Cap_dst_policy
|
||||
{
|
||||
struct Dst
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/socket_descriptor_registry.h>
|
||||
#include <base/internal/native_thread.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux_syscalls.h>
|
||||
@@ -509,7 +510,7 @@ Ipc_istream::~Ipc_istream()
|
||||
*/
|
||||
Thread_base *thread = Thread_base::myself();
|
||||
if (thread)
|
||||
thread->tid().is_ipc_server = false;
|
||||
thread->native_thread().is_ipc_server = false;
|
||||
}
|
||||
|
||||
destroy_server_socket_pair(_rcv_cs);
|
||||
@@ -641,7 +642,7 @@ Ipc_server::Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg)
|
||||
* may call 'sleep_forever()', which instantiates 'Ipc_server'.
|
||||
*/
|
||||
|
||||
if (thread && thread->tid().is_ipc_server) {
|
||||
if (thread && thread->native_thread().is_ipc_server) {
|
||||
PRAW("[%d] unexpected multiple instantiation of Ipc_server by one thread",
|
||||
lx_gettid());
|
||||
struct Ipc_server_multiple_instance { };
|
||||
@@ -650,7 +651,7 @@ Ipc_server::Ipc_server(Msgbuf_base *snd_msg, Msgbuf_base *rcv_msg)
|
||||
|
||||
if (thread) {
|
||||
_rcv_cs = server_socket_pair();
|
||||
thread->tid().is_ipc_server = true;
|
||||
thread->native_thread().is_ipc_server = true;
|
||||
}
|
||||
|
||||
/* override capability initialization performed by 'Ipc_istream' */
|
||||
|
||||
@@ -58,7 +58,7 @@ void Thread_base::_thread_start()
|
||||
/* inform core about the new thread and process ID of the new thread */
|
||||
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(thread->_cpu_session);
|
||||
if (cpu)
|
||||
cpu->thread_id(thread->cap(), thread->tid().pid, thread->tid().tid);
|
||||
cpu->thread_id(thread->cap(), thread->native_thread().pid, thread->native_thread().tid);
|
||||
|
||||
/* wakeup 'start' function */
|
||||
startup_lock().unlock();
|
||||
@@ -84,7 +84,7 @@ void Thread_base::_init_platform_thread(size_t weight, Type type)
|
||||
return;
|
||||
}
|
||||
/* adjust initial object state for main threads */
|
||||
tid().futex_counter = main_thread_futex_counter;
|
||||
native_thread().futex_counter = main_thread_futex_counter;
|
||||
_thread_cap = env()->parent()->main_thread_cap();
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ void Thread_base::_deinit_platform_thread()
|
||||
for (;;) {
|
||||
|
||||
/* destroy thread locally */
|
||||
int ret = lx_tgkill(_tid.pid, _tid.tid, LX_SIGCANCEL);
|
||||
int ret = lx_tgkill(native_thread().pid, native_thread().tid, LX_SIGCANCEL);
|
||||
|
||||
if (ret < 0) break;
|
||||
|
||||
@@ -138,8 +138,8 @@ void Thread_base::start()
|
||||
threadlib_initialized = true;
|
||||
}
|
||||
|
||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||
_tid.pid = lx_getpid();
|
||||
native_thread().tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||
native_thread().pid = lx_getpid();
|
||||
|
||||
/* wait until the 'thread_start' function got entered */
|
||||
startup_lock().lock();
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include <base/lock.h>
|
||||
#include <linux_dataspace/client.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/native_thread.h>
|
||||
|
||||
/* local includes */
|
||||
#include "platform.h"
|
||||
#include "core_env.h"
|
||||
@@ -157,7 +160,7 @@ namespace Genode {
|
||||
|
||||
Native_connection_state server_socket_pair()
|
||||
{
|
||||
return create_server_socket_pair(Thread_base::myself()->tid().tid);
|
||||
return create_server_socket_pair(Thread_base::myself()->native_thread().tid);
|
||||
}
|
||||
|
||||
void destroy_server_socket_pair(Native_connection_state const &ncs)
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include <base/thread.h>
|
||||
#include <base/sleep.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/native_thread.h>
|
||||
|
||||
/* Linux syscall bindings */
|
||||
#include <linux_syscalls.h>
|
||||
|
||||
@@ -54,8 +57,8 @@ void Thread_base::_deinit_platform_thread() { }
|
||||
|
||||
void Thread_base::start()
|
||||
{
|
||||
_tid.tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||
_tid.pid = lx_getpid();
|
||||
native_thread().tid = lx_create_thread(Thread_base::_thread_start, stack_top(), this);
|
||||
native_thread().pid = lx_getpid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ static inline void thread_yield()
|
||||
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
|
||||
{
|
||||
const int *futex_counter_ptr = thread_base ?
|
||||
&thread_base->tid().futex_counter :
|
||||
&thread_base->native_thread().futex_counter :
|
||||
&main_thread_futex_counter;
|
||||
return lx_futex(futex_counter_ptr, LX_FUTEX_WAKE, 1);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ static inline void thread_stop_myself()
|
||||
*/
|
||||
Genode::Thread_base *myself = Genode::Thread_base::myself();
|
||||
const int *futex_counter_ptr = myself ?
|
||||
&myself->tid().futex_counter :
|
||||
&myself->native_thread().futex_counter :
|
||||
&main_thread_futex_counter;
|
||||
lx_futex(futex_counter_ptr, LX_FUTEX_WAIT, 0);
|
||||
}
|
||||
|
||||
51
repos/base-linux/src/include/base/internal/native_thread.h
Normal file
51
repos/base-linux/src/include/base/internal/native_thread.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* \brief Kernel-specific thread meta data
|
||||
* \author Norman Feske
|
||||
* \date 2016-03-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_
|
||||
#define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Genode { struct Native_thread; }
|
||||
|
||||
struct Genode::Native_thread
|
||||
{
|
||||
/*
|
||||
* Unfortunately, both - PID and TID - are needed for lx_tgkill()
|
||||
*/
|
||||
unsigned int tid = 0; /* Native thread ID type as returned by the
|
||||
'clone' system call */
|
||||
unsigned int pid = 0; /* process ID (resp. thread-group ID) */
|
||||
|
||||
bool is_ipc_server = false;
|
||||
|
||||
/**
|
||||
* Natively aligned memory location used in the lock implementation
|
||||
*/
|
||||
int futex_counter __attribute__((aligned(sizeof(Genode::addr_t)))) = 0;
|
||||
|
||||
struct Meta_data;
|
||||
|
||||
/**
|
||||
* Opaque pointer to additional thread-specific meta data
|
||||
*
|
||||
* This pointer is used by hybrid Linux/Genode programs to maintain
|
||||
* POSIX-thread-related meta data. For non-hybrid Genode programs, it
|
||||
* remains unused.
|
||||
*/
|
||||
Meta_data *meta_data = nullptr;
|
||||
|
||||
Native_thread() { }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */
|
||||
@@ -11,11 +11,14 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
//#include <base/crt0.h>
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/native_thread.h>
|
||||
|
||||
|
||||
extern "C" int raw_write_str(const char *str);
|
||||
|
||||
@@ -134,8 +137,20 @@ static pthread_key_t tls_key()
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Meta data tied to the thread via the pthread TLS mechanism
|
||||
*/
|
||||
struct Native_thread::Meta_data
|
||||
{
|
||||
/**
|
||||
* Linux-specific thread meta data
|
||||
*
|
||||
* For non-hybrid programs, this information is located at the
|
||||
* 'Stack'. But the POSIX threads of hybrid programs have no 'Stack'
|
||||
* object. So we have to keep the meta data here.
|
||||
*/
|
||||
Native_thread native_thread;
|
||||
|
||||
/**
|
||||
* Filled out by 'thread_start' function in the stack of the new
|
||||
* thread
|
||||
@@ -152,7 +167,10 @@ namespace Genode {
|
||||
*
|
||||
* \param thread associated 'Thread_base' object
|
||||
*/
|
||||
Meta_data(Thread_base *thread) : thread_base(thread) { }
|
||||
Meta_data(Thread_base *thread) : thread_base(thread)
|
||||
{
|
||||
native_thread.meta_data = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to block the constructor until the new thread has initialized
|
||||
@@ -174,8 +192,8 @@ namespace Genode {
|
||||
virtual void joined() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Thread meta data for a thread created by Genode
|
||||
/**
|
||||
* Thread meta data for a thread created by Genode
|
||||
*/
|
||||
class Thread_meta_data_created : public Native_thread::Meta_data
|
||||
{
|
||||
@@ -238,8 +256,8 @@ namespace Genode {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Thread meta data for an adopted thread
|
||||
/**
|
||||
* Thread meta data for an adopted thread
|
||||
*/
|
||||
class Thread_meta_data_adopted : public Native_thread::Meta_data
|
||||
{
|
||||
@@ -320,7 +338,7 @@ static void adopt_thread(Native_thread::Meta_data *meta_data)
|
||||
/*
|
||||
* Initialize thread meta data
|
||||
*/
|
||||
Native_thread &native_thread = meta_data->thread_base->tid();
|
||||
Native_thread &native_thread = meta_data->thread_base->native_thread();
|
||||
native_thread.tid = lx_gettid();
|
||||
native_thread.pid = lx_getpid();
|
||||
}
|
||||
@@ -375,19 +393,18 @@ Thread_base *Thread_base::myself()
|
||||
* thread, which is not what we want. For the allocation, we use glibc
|
||||
* malloc because 'Genode::env()->heap()->alloc()' uses IPC.
|
||||
*
|
||||
* XXX Both the 'Thread_base' and 'Threadm_meta_data' objects are never
|
||||
* freed.
|
||||
* XXX Both the 'Thread_base' and 'Native_thread::Meta_data' objects are
|
||||
* never freed.
|
||||
*/
|
||||
Thread_base *thread = (Thread_base *)malloc(sizeof(Thread_base));
|
||||
memset(thread, 0, sizeof(*thread));
|
||||
Native_thread::Meta_data *meta_data = new Thread_meta_data_adopted(thread);
|
||||
|
||||
/*
|
||||
* Initialize 'Thread_base::_tid' using the default constructor of
|
||||
* 'Native_thread'. This marks the client and server sockets as
|
||||
* uninitialized and prompts the IPC framework to create those as needed.
|
||||
* Initialize 'Thread_base::_native_thread' to point to the default-
|
||||
* constructed 'Native_thread' (part of 'Meta_data').
|
||||
*/
|
||||
meta_data->thread_base->tid() = Native_thread();
|
||||
meta_data->thread_base->_native_thread = &meta_data->native_thread;
|
||||
adopt_thread(meta_data);
|
||||
|
||||
return thread;
|
||||
@@ -399,37 +416,42 @@ void Thread_base::start()
|
||||
/*
|
||||
* Unblock thread that is supposed to slumber in 'thread_start'.
|
||||
*/
|
||||
_tid.meta_data->started();
|
||||
native_thread().meta_data->started();
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::join()
|
||||
{
|
||||
_tid.meta_data->wait_for_join();
|
||||
native_thread().meta_data->wait_for_join();
|
||||
}
|
||||
|
||||
|
||||
Native_thread &Thread_base::native_thread() { return *_native_thread; }
|
||||
|
||||
|
||||
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
|
||||
Type type, Cpu_session * cpu_sess)
|
||||
: _cpu_session(cpu_sess)
|
||||
{
|
||||
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
|
||||
Native_thread::Meta_data *meta_data =
|
||||
new (env()->heap()) Thread_meta_data_created(this);
|
||||
|
||||
int const ret = pthread_create(&_tid.meta_data->pt, 0, thread_start,
|
||||
_tid.meta_data);
|
||||
_native_thread = &meta_data->native_thread;
|
||||
|
||||
int const ret = pthread_create(&meta_data->pt, 0, thread_start, meta_data);
|
||||
if (ret) {
|
||||
PERR("pthread_create failed (returned %d, errno=%d)",
|
||||
ret, errno);
|
||||
destroy(env()->heap(), _tid.meta_data);
|
||||
destroy(env()->heap(), meta_data);
|
||||
throw Out_of_stack_space();
|
||||
}
|
||||
|
||||
_tid.meta_data->wait_for_construction();
|
||||
native_thread().meta_data->wait_for_construction();
|
||||
|
||||
Linux_cpu_session *cpu = cpu_session(_cpu_session);
|
||||
|
||||
_thread_cap = cpu->create_thread(weight, name);
|
||||
cpu->thread_id(_thread_cap, _tid.pid, _tid.tid);
|
||||
cpu->thread_id(_thread_cap, native_thread().pid, native_thread().tid);
|
||||
}
|
||||
|
||||
|
||||
@@ -447,22 +469,22 @@ void Thread_base::cancel_blocking()
|
||||
|
||||
Thread_base::~Thread_base()
|
||||
{
|
||||
bool const needs_join = (pthread_cancel(_tid.meta_data->pt) == 0);
|
||||
bool const needs_join = (pthread_cancel(native_thread().meta_data->pt) == 0);
|
||||
|
||||
if (needs_join) {
|
||||
int const ret = pthread_join(_tid.meta_data->pt, 0);
|
||||
int const ret = pthread_join(native_thread().meta_data->pt, 0);
|
||||
if (ret)
|
||||
PWRN("pthread_join unexpectedly returned with %d (errno=%d)",
|
||||
ret, errno);
|
||||
}
|
||||
|
||||
Thread_meta_data_created *meta_data =
|
||||
dynamic_cast<Thread_meta_data_created *>(_tid.meta_data);
|
||||
dynamic_cast<Thread_meta_data_created *>(native_thread().meta_data);
|
||||
|
||||
if (meta_data)
|
||||
destroy(env()->heap(), meta_data);
|
||||
|
||||
_tid.meta_data = 0;
|
||||
_native_thread = nullptr;
|
||||
|
||||
/* inform core about the killed thread */
|
||||
cpu_session(_cpu_session)->kill_thread(_thread_cap);
|
||||
|
||||
Reference in New Issue
Block a user