2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* \brief Supplemental code for hybrid Genode/Linux programs
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2011-09-02
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2011-2013 Genode Labs GmbH
|
2011-12-22 16:19:25 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <base/crt0.h>
|
|
|
|
#include <base/printf.h>
|
|
|
|
#include <_main_helper.h>
|
2012-08-09 16:52:47 +02:00
|
|
|
#include <linux_cpu_session/linux_cpu_session.h>
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
extern "C" int raw_write_str(const char *str);
|
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
enum { verbose_atexit = false };
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Dummy for symbol that is normally provided by '_main.cc'
|
|
|
|
*/
|
|
|
|
int genode___cxa_atexit(void (*func)(void*), void *arg, void *dso)
|
|
|
|
{
|
2011-12-22 17:17:44 +01:00
|
|
|
if (verbose_atexit)
|
|
|
|
raw_write_str("genode___cxa_atexit called, not implemented\n");
|
2011-12-22 16:19:25 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Manually initialize the 'lx_environ' pointer. For non-hybrid programs, this
|
|
|
|
* pointer is initialized by the startup code.
|
|
|
|
*/
|
|
|
|
extern char **environ;
|
|
|
|
extern char **lx_environ;
|
|
|
|
|
2012-11-06 17:32:30 +01:00
|
|
|
static void empty_signal_handler(int) { }
|
|
|
|
|
2011-12-22 16:19:25 +01:00
|
|
|
/*
|
|
|
|
* This function must be called before any other static constructor in the Genode
|
|
|
|
* application, so it gets the highest priority (lowest priority number >100)
|
|
|
|
*/
|
|
|
|
__attribute__((constructor(101))) void lx_hybrid_init()
|
|
|
|
{
|
|
|
|
lx_environ = environ;
|
2012-11-06 17:32:30 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set signal handler such that canceled system calls get not
|
|
|
|
* transparently retried after a signal gets received.
|
|
|
|
*/
|
|
|
|
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
|
2011-12-22 16:19:25 +01:00
|
|
|
}
|
2011-12-22 17:17:44 +01:00
|
|
|
|
2012-04-18 17:45:03 +02:00
|
|
|
/*
|
|
|
|
* Dummy symbols to let generic tests programs (i.e., 'test-config_args') link
|
|
|
|
* successfully. Please note that such programs are not expected to work when
|
|
|
|
* built as hybrid Linux/Genode programs because when using the glibc startup
|
|
|
|
* code, we cannot manipulate argv prior executing main. However, by defining
|
|
|
|
* these symbols, we prevent the automated build bot from stumbling over such
|
|
|
|
* binaries.
|
|
|
|
*/
|
|
|
|
char **genode_argv = 0;
|
|
|
|
int genode_argc = 1;
|
2011-12-22 17:17:44 +01:00
|
|
|
|
2012-08-09 16:52:47 +02:00
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
/************
|
|
|
|
** Thread **
|
|
|
|
************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For hybrid Linux/Genode programs, Genode's thread API is implemented via
|
|
|
|
* POSIX threads.
|
|
|
|
*
|
|
|
|
* Hybrid Linux/Genode programs are linked against the glibc along with other
|
|
|
|
* native Linux libraries. Such libraries may use the 'pthread' API to spawn
|
|
|
|
* threads, which then may call Genode code. Vice versa, Genode threads may
|
|
|
|
* interact with code of a native Linux libraries. Hence, both worlds Genode
|
|
|
|
* and native Linux libraries should use the same underlying threading API.
|
|
|
|
* Furthermore, using the pthread API is a precondition to satisfy the glibc's
|
|
|
|
* assumption about thread-local storage, which is particularly important
|
|
|
|
* for the correct thread-local handling of 'errno'. As another benefit of
|
|
|
|
* using the pthread API over the normal Genode thread implementation, hybrid
|
|
|
|
* Linux/Genode programs comply with the GNU debugger's expectations. Such
|
|
|
|
* programs can be debugged as normal Linux programs.
|
|
|
|
*
|
|
|
|
* Genode's normal thread API for Linux was introduced to decouple Genode
|
|
|
|
* from the glibc. This is especially important when using Genode's libc
|
|
|
|
* Mixing both Genode's libc and glibc won't work.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/thread.h>
|
2011-12-23 14:04:29 +01:00
|
|
|
#include <base/env.h>
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return TLS key used to storing the thread meta data
|
|
|
|
*/
|
|
|
|
static pthread_key_t tls_key()
|
|
|
|
{
|
|
|
|
struct Tls_key
|
|
|
|
{
|
|
|
|
pthread_key_t key;
|
|
|
|
|
|
|
|
Tls_key()
|
|
|
|
{
|
|
|
|
pthread_key_create(&key, 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Tls_key inst;
|
|
|
|
return inst.key;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace Genode {
|
|
|
|
|
|
|
|
struct Thread_meta_data
|
|
|
|
{
|
2012-11-16 13:53:37 +01:00
|
|
|
/**
|
2013-02-25 21:18:26 +01:00
|
|
|
* Filled out by 'thread_start' function in the context of the new
|
|
|
|
* thread
|
2012-11-16 13:53:37 +01:00
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
Thread_base * const thread_base;
|
2012-11-16 13:53:37 +01:00
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
/**
|
2013-02-25 21:18:26 +01:00
|
|
|
* POSIX thread handle
|
2011-12-22 17:17:44 +01:00
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
pthread_t pt;
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/**
|
2013-02-25 21:18:26 +01:00
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param thread associated 'Thread_base' object
|
2011-12-22 17:17:44 +01:00
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
Thread_meta_data(Thread_base *thread) : thread_base(thread) { }
|
2012-11-16 13:53:37 +01:00
|
|
|
|
|
|
|
/**
|
2013-02-25 21:18:26 +01:00
|
|
|
* Used to block the constructor until the new thread has initialized
|
|
|
|
* 'id'
|
2012-11-16 13:53:37 +01:00
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
virtual void wait_for_construction() = 0;
|
|
|
|
virtual void constructed() = 0;
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/**
|
2013-02-25 21:18:26 +01:00
|
|
|
* Used to block the new thread until 'start' is called
|
2011-12-22 17:17:44 +01:00
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
virtual void wait_for_start() = 0;
|
|
|
|
virtual void started() = 0;
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/**
|
2013-02-25 21:18:26 +01:00
|
|
|
* Used to block the 'join()' function until the 'entry()' is done
|
2011-12-22 17:17:44 +01:00
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
virtual void wait_for_join() = 0;
|
|
|
|
virtual void joined() = 0;
|
|
|
|
};
|
2011-12-22 17:17:44 +01:00
|
|
|
|
2013-02-25 21:18:26 +01:00
|
|
|
/*
|
|
|
|
* Thread meta data for a thread created by Genode
|
|
|
|
*/
|
|
|
|
class Thread_meta_data_created : public Thread_meta_data
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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'
|
|
|
|
*/
|
|
|
|
Barrier _construct_lock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to block the new thread until 'start' is called
|
|
|
|
*/
|
|
|
|
Barrier _start_lock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to block the 'join()' function until the 'entry()' is done
|
|
|
|
*/
|
|
|
|
Barrier _join_lock;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Thread_meta_data_created(Thread_base *thread) : Thread_meta_data(thread) { }
|
|
|
|
|
|
|
|
void wait_for_construction()
|
|
|
|
{
|
|
|
|
_construct_lock.lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void constructed()
|
|
|
|
{
|
|
|
|
_construct_lock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait_for_start()
|
|
|
|
{
|
|
|
|
_start_lock.lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void started()
|
|
|
|
{
|
|
|
|
_start_lock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait_for_join()
|
|
|
|
{
|
|
|
|
_join_lock.lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void joined()
|
|
|
|
{
|
|
|
|
_join_lock.unlock();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Thread meta data for an adopted thread
|
|
|
|
*/
|
|
|
|
class Thread_meta_data_adopted : public Thread_meta_data
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
Thread_meta_data_adopted(Thread_base *thread) : Thread_meta_data(thread) { }
|
|
|
|
|
|
|
|
void wait_for_construction()
|
|
|
|
{
|
|
|
|
PERR("wait_for_construction() called for an adopted thread");
|
|
|
|
}
|
|
|
|
|
|
|
|
void constructed()
|
|
|
|
{
|
|
|
|
PERR("constructed() called for an adopted thread");
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait_for_start()
|
|
|
|
{
|
|
|
|
PERR("wait_for_start() called for an adopted thread");
|
|
|
|
}
|
|
|
|
|
|
|
|
void started()
|
|
|
|
{
|
|
|
|
PERR("started() called for an adopted thread");
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait_for_join()
|
|
|
|
{
|
|
|
|
PERR("wait_for_join() called for an adopted thread");
|
|
|
|
}
|
|
|
|
|
|
|
|
void joined()
|
|
|
|
{
|
|
|
|
PERR("joined() called for an adopted thread");
|
|
|
|
}
|
2011-12-22 17:17:44 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-09 16:52:47 +02:00
|
|
|
/**
|
|
|
|
* Return Linux-specific extension of the Env::CPU session interface
|
|
|
|
*/
|
|
|
|
Linux_cpu_session *cpu_session()
|
|
|
|
{
|
|
|
|
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
|
|
|
|
|
|
|
|
if (!cpu) {
|
|
|
|
PERR("could not obtain Linux extension to CPU session interface");
|
|
|
|
struct Could_not_access_linux_cpu_session { };
|
|
|
|
throw Could_not_access_linux_cpu_session();
|
|
|
|
}
|
|
|
|
|
|
|
|
return cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-23 14:04:29 +01:00
|
|
|
static void adopt_thread(Thread_meta_data *meta_data)
|
2011-12-22 17:17:44 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Set signal handler such that canceled system calls get not
|
|
|
|
* transparently retried after a signal gets received.
|
|
|
|
*/
|
|
|
|
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
|
|
|
|
|
2012-07-09 17:51:39 +02:00
|
|
|
/*
|
|
|
|
* Prevent children from becoming zombies. (SIG_IGN = 1)
|
|
|
|
*/
|
|
|
|
lx_sigaction(LX_SIGCHLD, (void (*)(int))1);
|
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
/* assign 'Thread_meta_data' pointer to TLS entry */
|
2011-12-23 14:04:29 +01:00
|
|
|
pthread_setspecific(tls_key(), meta_data);
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/* enable immediate cancellation when calling 'pthread_cancel' */
|
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize thread meta data
|
|
|
|
*/
|
2011-12-23 14:04:29 +01:00
|
|
|
Native_thread &native_thread = meta_data->thread_base->tid();
|
|
|
|
native_thread.tid = lx_gettid();
|
|
|
|
native_thread.pid = lx_getpid();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *thread_start(void *arg)
|
|
|
|
{
|
2011-12-22 17:17:44 +01:00
|
|
|
Thread_meta_data *meta_data = (Thread_meta_data *)arg;
|
2011-12-23 14:04:29 +01:00
|
|
|
|
|
|
|
adopt_thread(meta_data);
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/* unblock 'Thread_base' constructor */
|
2013-02-25 21:18:26 +01:00
|
|
|
meta_data->constructed();
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
/* block until the 'Thread_base::start' gets called */
|
2013-02-25 21:18:26 +01:00
|
|
|
meta_data->wait_for_start();
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
Thread_base::myself()->entry();
|
2012-11-16 13:53:37 +01:00
|
|
|
|
2013-02-25 21:18:26 +01:00
|
|
|
meta_data->joined();
|
2011-12-22 17:17:44 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-23 14:04:29 +01:00
|
|
|
extern "C" void *malloc(::size_t size);
|
|
|
|
|
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
Thread_base *Thread_base::myself()
|
|
|
|
{
|
2011-12-23 14:04:29 +01:00
|
|
|
void * const tls = pthread_getspecific(tls_key());
|
|
|
|
|
|
|
|
if (tls != 0)
|
|
|
|
return ((Thread_meta_data *)tls)->thread_base;
|
2011-12-22 17:17:44 +01:00
|
|
|
|
2011-12-23 14:04:29 +01:00
|
|
|
bool const is_main_thread = (lx_getpid() == lx_gettid());
|
|
|
|
if (is_main_thread)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The function was called from a thread created by other means than
|
|
|
|
* Genode's thread API. This may happen if a native Linux library creates
|
|
|
|
* threads via the pthread library. If such a thread calls Genode code,
|
|
|
|
* which then tries to perform IPC, the program fails because there exists
|
|
|
|
* no 'Thread_base' object. We recover from this unfortunate situation by
|
|
|
|
* creating a dummy 'Thread_base' object and associate it with the calling
|
|
|
|
* thread.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create dummy 'Thread_base' object but suppress the execution of its
|
|
|
|
* constructor. If we called the constructor, we would create a new Genode
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
Thread_base *thread = (Thread_base *)malloc(sizeof(Thread_base));
|
|
|
|
memset(thread, 0, sizeof(*thread));
|
2013-02-25 21:18:26 +01:00
|
|
|
Thread_meta_data *meta_data = new Thread_meta_data_adopted(thread);
|
2011-12-23 14:04:29 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
meta_data->thread_base->tid() = Native_thread();
|
|
|
|
adopt_thread(meta_data);
|
2011-12-22 17:17:44 +01:00
|
|
|
|
2011-12-23 14:04:29 +01:00
|
|
|
return thread;
|
2011-12-22 17:17:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread_base::start()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Unblock thread that is supposed to slumber in 'thread_start'.
|
|
|
|
*/
|
2013-02-25 21:18:26 +01:00
|
|
|
_tid.meta_data->started();
|
2011-12-22 17:17:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-16 13:53:37 +01:00
|
|
|
void Thread_base::join()
|
|
|
|
{
|
2013-02-25 21:18:26 +01:00
|
|
|
_tid.meta_data->wait_for_join();
|
2012-11-16 13:53:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
Thread_base::Thread_base(const char *name, size_t stack_size)
|
2012-11-16 13:53:37 +01:00
|
|
|
:
|
|
|
|
_list_element(this)
|
2011-12-22 17:17:44 +01:00
|
|
|
{
|
2013-02-25 21:18:26 +01:00
|
|
|
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
|
2011-12-22 17:17:44 +01:00
|
|
|
|
|
|
|
int const ret = pthread_create(&_tid.meta_data->pt, 0, thread_start,
|
|
|
|
_tid.meta_data);
|
|
|
|
if (ret) {
|
|
|
|
PERR("pthread_create failed (returned %d, errno=%d)",
|
|
|
|
ret, errno);
|
2011-12-23 14:04:29 +01:00
|
|
|
destroy(env()->heap(), _tid.meta_data);
|
2011-12-22 17:17:44 +01:00
|
|
|
throw Context_alloc_failed();
|
|
|
|
}
|
|
|
|
|
2013-02-25 21:18:26 +01:00
|
|
|
_tid.meta_data->wait_for_construction();
|
2012-08-09 16:52:47 +02:00
|
|
|
|
|
|
|
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
|
|
|
|
|
|
|
|
if (!cpu) {
|
|
|
|
PERR("could not obtain Linux extension to CPU session interface");
|
|
|
|
struct Could_not_access_linux_cpu_session { };
|
|
|
|
throw Could_not_access_linux_cpu_session();
|
|
|
|
}
|
|
|
|
|
|
|
|
_thread_cap = cpu_session()->create_thread(name);
|
|
|
|
cpu_session()->thread_id(_thread_cap, _tid.pid, _tid.tid);
|
2011-12-22 17:17:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Thread_base::cancel_blocking()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* XXX implement interaction with CPU session
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Thread_base::~Thread_base()
|
|
|
|
{
|
2012-11-16 13:53:37 +01:00
|
|
|
bool const needs_join = (pthread_cancel(_tid.meta_data->pt) == 0);
|
2011-12-22 17:17:44 +01:00
|
|
|
|
2012-11-16 13:53:37 +01:00
|
|
|
if (needs_join) {
|
2011-12-22 17:17:44 +01:00
|
|
|
int const ret = pthread_join(_tid.meta_data->pt, 0);
|
|
|
|
if (ret)
|
|
|
|
PWRN("pthread_join unexpectedly returned with %d (errno=%d)",
|
|
|
|
ret, errno);
|
|
|
|
}
|
|
|
|
|
2013-05-03 14:35:07 +02:00
|
|
|
Thread_meta_data_created *meta_data =
|
|
|
|
dynamic_cast<Thread_meta_data_created *>(_tid.meta_data);
|
|
|
|
|
|
|
|
if (meta_data)
|
|
|
|
destroy(env()->heap(), meta_data);
|
|
|
|
|
2011-12-22 17:17:44 +01:00
|
|
|
_tid.meta_data = 0;
|
2012-08-09 16:52:47 +02:00
|
|
|
|
|
|
|
/* inform core about the killed thread */
|
|
|
|
cpu_session()->kill_thread(_thread_cap);
|
2011-12-22 17:17:44 +01:00
|
|
|
}
|