pthread: prevent copy of `Genode::Thread` object
This patch also adjusts virtualbox because it relies on pthread-internal interfaces. Fixes #2630
This commit is contained in:
parent
8af45fd5fb
commit
2a33d9aa76
|
@ -53,6 +53,8 @@ class Genode::Thread
|
||||||
|
|
||||||
struct Stack_info { addr_t base; addr_t top; };
|
struct Stack_info { addr_t base; addr_t top; };
|
||||||
|
|
||||||
|
struct Tls { struct Base; Base *ptr; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -145,6 +147,17 @@ class Genode::Thread
|
||||||
*/
|
*/
|
||||||
static Trace::Logger *_logger();
|
static Trace::Logger *_logger();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base pointer to thread-local storage
|
||||||
|
*
|
||||||
|
* The opaque pointer allows higher-level thread libraries (i.e.,
|
||||||
|
* pthread) to implement TLS. It should never be used outside such
|
||||||
|
* libraries.
|
||||||
|
*/
|
||||||
|
Tls _tls { };
|
||||||
|
|
||||||
|
friend class Tls::Base;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for platform-specific constructor supplements
|
* Hook for platform-specific constructor supplements
|
||||||
*
|
*
|
||||||
|
|
|
@ -179,37 +179,35 @@ extern "C" {
|
||||||
|
|
||||||
pthread_t pthread_self(void)
|
pthread_t pthread_self(void)
|
||||||
{
|
{
|
||||||
Thread *myself = Thread::myself();
|
try {
|
||||||
|
pthread_t pthread_myself =
|
||||||
|
static_cast<pthread_t>(&Thread::Tls::Base::tls());
|
||||||
|
|
||||||
pthread_t pthread_myself = static_cast<pthread_t>(myself);
|
if (pthread_registry().contains(pthread_myself))
|
||||||
|
return pthread_myself;
|
||||||
if (pthread_registry().contains(pthread_myself))
|
}
|
||||||
return pthread_myself;
|
catch (Thread::Tls::Base::Undefined) { }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We pass here if the main thread or an alien thread calls
|
* We pass here if the main thread or an alien thread calls
|
||||||
* pthread_self(). So check for aliens (or other bugs) and opt-out
|
* pthread_self(). So check for aliens (or other bugs) and opt-out
|
||||||
* early.
|
* early.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!_pthread_main_np()) {
|
if (!_pthread_main_np()) {
|
||||||
error("pthread_self() called from alien thread named ",
|
error("pthread_self() called from alien thread named ",
|
||||||
"'", myself->name().string(), "'");
|
"'", Thread::myself()->name().string(), "'");
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We create a pthread object containing a copy of main thread's
|
* We create a pthread object associated to the main thread's Thread
|
||||||
* Thread object. Therefore, we ensure the pthread object does not
|
* object. We ensure the pthread object does never get deleted by
|
||||||
* get deleted by allocating it in heap via new(). Otherwise, the
|
* allocating it in heap via new(). Otherwise, the static destruction
|
||||||
* static destruction of the pthread object would also destruct the
|
* of the pthread object would also destruct the 'Thread' of the main
|
||||||
* 'Thread' of the main thread.
|
* thread.
|
||||||
*/
|
*/
|
||||||
|
static pthread_attr main_thread_attr;
|
||||||
static struct pthread_attr main_thread_attr;
|
static pthread *main = new pthread(*Thread::myself(), &main_thread_attr);
|
||||||
static struct pthread *main = new pthread(*myself, &main_thread_attr);
|
|
||||||
|
|
||||||
return main;
|
return main;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +251,7 @@ extern "C" {
|
||||||
if (!attr)
|
if (!attr)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
*attr = pthread->_attr;
|
*attr = pthread->attr();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
#ifndef _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_
|
#ifndef _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_
|
||||||
#define _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_
|
#define _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <util/reconstructible.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -53,60 +56,142 @@ extern "C" {
|
||||||
pthread_attr() : pthread(0), stack_size(0) { }
|
pthread_attr() : pthread(0), stack_size(0) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class is named 'struct pthread' because the 'pthread_t' type is
|
* This class is named 'struct pthread' because the 'pthread_t' type is
|
||||||
* defined as 'struct pthread*' in '_pthreadtypes.h'
|
* defined as 'struct pthread*' in '_pthreadtypes.h'
|
||||||
*/
|
*/
|
||||||
struct pthread : Genode::Thread
|
struct pthread;
|
||||||
{
|
|
||||||
pthread_attr_t _attr;
|
|
||||||
void *(*_start_routine) (void *);
|
|
||||||
void *_arg;
|
|
||||||
|
|
||||||
enum { WEIGHT = Genode::Cpu_session::Weight::DEFAULT_WEIGHT };
|
|
||||||
|
|
||||||
pthread(pthread_attr_t attr, void *(*start_routine) (void *),
|
|
||||||
void *arg, size_t stack_size, char const * name,
|
|
||||||
Genode::Cpu_session * cpu, Genode::Affinity::Location location)
|
|
||||||
: Thread(WEIGHT, name, stack_size, Type::NORMAL, cpu, location),
|
|
||||||
_attr(attr),
|
|
||||||
_start_routine(start_routine),
|
|
||||||
_arg(arg)
|
|
||||||
{
|
|
||||||
if (_attr)
|
|
||||||
_attr->pthread = this;
|
|
||||||
|
|
||||||
pthread_registry().insert(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor to create pthread object out of existing thread,
|
|
||||||
* e.g. main Genode thread
|
|
||||||
*/
|
|
||||||
pthread(Thread &myself, pthread_attr_t attr)
|
|
||||||
: Thread(myself),
|
|
||||||
_attr(attr), _start_routine(nullptr), _arg(nullptr)
|
|
||||||
{
|
|
||||||
if (_attr)
|
|
||||||
_attr->pthread = this;
|
|
||||||
|
|
||||||
pthread_registry().insert(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~pthread()
|
|
||||||
{
|
|
||||||
pthread_registry().remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void entry()
|
|
||||||
{
|
|
||||||
void *exit_status = _start_routine(_arg);
|
|
||||||
pthread_exit(exit_status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void pthread_cleanup();
|
void pthread_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Genode::Thread::Tls::Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register thread-local-storage object at Genode thread
|
||||||
|
*/
|
||||||
|
static void tls(Genode::Thread &thread, Tls::Base &tls)
|
||||||
|
{
|
||||||
|
thread._tls = Tls { &tls };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Undefined : Exception { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain thread-local-storage object for the calling thread
|
||||||
|
*
|
||||||
|
* \throw Undefined
|
||||||
|
*/
|
||||||
|
static Tls::Base &tls()
|
||||||
|
{
|
||||||
|
Thread &myself = *Thread::myself();
|
||||||
|
|
||||||
|
if (!myself._tls.ptr)
|
||||||
|
throw Undefined();
|
||||||
|
|
||||||
|
return *myself._tls.ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct pthread : Genode::Noncopyable, Genode::Thread::Tls::Base
|
||||||
|
{
|
||||||
|
typedef void *(*start_routine_t) (void *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Thread_object : Genode::Thread
|
||||||
|
{
|
||||||
|
start_routine_t _start_routine;
|
||||||
|
void *_arg;
|
||||||
|
|
||||||
|
enum { WEIGHT = Genode::Cpu_session::Weight::DEFAULT_WEIGHT };
|
||||||
|
|
||||||
|
Thread_object(char const *name, size_t stack_size,
|
||||||
|
Genode::Cpu_session *cpu,
|
||||||
|
Genode::Affinity::Location location,
|
||||||
|
start_routine_t start_routine, void *arg)
|
||||||
|
:
|
||||||
|
Genode::Thread(WEIGHT, name, stack_size, Type::NORMAL, cpu, location),
|
||||||
|
_start_routine(start_routine), _arg(arg)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void entry() override
|
||||||
|
{
|
||||||
|
void *exit_status = _start_routine(_arg);
|
||||||
|
pthread_exit(exit_status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Genode::Constructible<Thread_object> _thread_object;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper to construct '_thread_object' in class initializer
|
||||||
|
*/
|
||||||
|
template <typename... ARGS>
|
||||||
|
Genode::Thread &_construct_thread_object(ARGS &&... args)
|
||||||
|
{
|
||||||
|
_thread_object.construct(args...);
|
||||||
|
return *_thread_object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Refers to '_thread_object' or an external 'Genode::Thread' object
|
||||||
|
*/
|
||||||
|
Genode::Thread &_thread;
|
||||||
|
|
||||||
|
pthread_attr_t _attr;
|
||||||
|
|
||||||
|
void _associate_thread_with_pthread()
|
||||||
|
{
|
||||||
|
if (_attr)
|
||||||
|
_attr->pthread = this;
|
||||||
|
|
||||||
|
Genode::Thread::Tls::Base::tls(_thread, *this);
|
||||||
|
|
||||||
|
pthread_registry().insert(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for threads created via 'pthread_create'
|
||||||
|
*/
|
||||||
|
pthread(pthread_attr_t attr, start_routine_t start_routine,
|
||||||
|
void *arg, size_t stack_size, char const * name,
|
||||||
|
Genode::Cpu_session * cpu, Genode::Affinity::Location location)
|
||||||
|
:
|
||||||
|
_thread(_construct_thread_object(name, stack_size, cpu, location,
|
||||||
|
start_routine, arg)),
|
||||||
|
_attr(attr)
|
||||||
|
{
|
||||||
|
_associate_thread_with_pthread();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to create pthread object out of existing thread,
|
||||||
|
* i.e., the main thread
|
||||||
|
*/
|
||||||
|
pthread(Genode::Thread &existing_thread, pthread_attr_t attr)
|
||||||
|
:
|
||||||
|
_thread(existing_thread),
|
||||||
|
_attr(attr)
|
||||||
|
{
|
||||||
|
_associate_thread_with_pthread();
|
||||||
|
}
|
||||||
|
|
||||||
|
~pthread()
|
||||||
|
{
|
||||||
|
pthread_registry().remove(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() { _thread.start(); }
|
||||||
|
|
||||||
|
void *stack_top() const { return _thread.stack_top(); }
|
||||||
|
void *stack_base() const { return _thread.stack_base(); }
|
||||||
|
|
||||||
|
pthread_attr_t attr() { return _attr; }
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */
|
#endif /* _INCLUDE__SRC_LIB_PTHREAD_THREAD_H_ */
|
||||||
|
|
|
@ -84,22 +84,6 @@ class Vmm::Vcpu_dispatcher : public T
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename X>
|
|
||||||
Vcpu_dispatcher(Genode::Env &env, Genode::size_t stack_size,
|
|
||||||
Cpu_session * cpu_session,
|
|
||||||
Genode::Affinity::Location location,
|
|
||||||
X attr, void *(*start_routine) (void *), void *arg,
|
|
||||||
const char * name = "vCPU dispatcher")
|
|
||||||
: T(attr, start_routine, arg, stack_size, name, nullptr, location),
|
|
||||||
_env(env)
|
|
||||||
{
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
/* request creation of a 'local' EC */
|
|
||||||
T::native_thread().ec_sel = Native_thread::INVALID_INDEX - 1;
|
|
||||||
T::start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register virtualization event handler
|
* Register virtualization event handler
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -313,6 +313,6 @@ bool create_emt_vcpu(pthread_t * pthread, size_t stack,
|
||||||
|
|
||||||
vcpu_handler_list().insert(vcpu_handler);
|
vcpu_handler_list().insert(vcpu_handler);
|
||||||
|
|
||||||
*pthread = vcpu_handler;
|
*pthread = &vcpu_handler->pthread_obj();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,14 +74,21 @@ extern "C" int MMIO2_MAPPED_SYNC(PVM pVM, RTGCPHYS GCPhys, size_t cbWrite,
|
||||||
bool &writeable);
|
bool &writeable);
|
||||||
|
|
||||||
|
|
||||||
class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>,
|
||||||
public Genode::List<Vcpu_handler>::Element
|
public Genode::List<Vcpu_handler>::Element
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
pthread::start_routine_t const _start_routine;
|
||||||
|
void * const _start_routine_arg;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
X86FXSTATE _guest_fpu_state __attribute__((aligned(0x10)));
|
X86FXSTATE _guest_fpu_state __attribute__((aligned(0x10)));
|
||||||
X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10)));
|
X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10)));
|
||||||
|
|
||||||
|
pthread _pthread;
|
||||||
|
|
||||||
Vmm::Vcpu_other_pd _vcpu;
|
Vmm::Vcpu_other_pd _vcpu;
|
||||||
|
|
||||||
Genode::addr_t _ec_sel;
|
Genode::addr_t _ec_sel;
|
||||||
|
@ -767,15 +774,19 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
||||||
unsigned int cpu_id, const char * name,
|
unsigned int cpu_id, const char * name,
|
||||||
Genode::Pd_session_capability pd_vcpu)
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vmm::Vcpu_dispatcher<pthread>(env, stack_size, cpu_session, location,
|
Vmm::Vcpu_dispatcher<Genode::Thread>(env, stack_size, cpu_session,
|
||||||
attr ? *attr : 0, start_routine, arg,
|
location, name),
|
||||||
name),
|
_pthread(*this, attr ? *attr : 0),
|
||||||
|
_start_routine(start_routine),
|
||||||
|
_start_routine_arg(arg),
|
||||||
_vcpu(cpu_session, location, pd_vcpu),
|
_vcpu(cpu_session, location, pd_vcpu),
|
||||||
_ec_sel(Genode::cap_map()->insert()),
|
_ec_sel(Genode::cap_map()->insert()),
|
||||||
_irq_win(false),
|
_irq_win(false),
|
||||||
_cpu_id(cpu_id)
|
_cpu_id(cpu_id)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
pthread &pthread_obj() { return _pthread; }
|
||||||
|
|
||||||
unsigned int cpu_id() { return _cpu_id; }
|
unsigned int cpu_id() { return _cpu_id; }
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
|
|
|
@ -75,7 +75,7 @@ class Vcpu_handler_svm : public Vcpu_handler
|
||||||
| SVM_CTRL2_INTERCEPT_MONITOR
|
| SVM_CTRL2_INTERCEPT_MONITOR
|
||||||
| SVM_CTRL2_INTERCEPT_MWAIT;
|
| SVM_CTRL2_INTERCEPT_MWAIT;
|
||||||
|
|
||||||
void *exit_status = _start_routine(_arg);
|
void *exit_status = _start_routine(_start_routine_arg);
|
||||||
pthread_exit(exit_status);
|
pthread_exit(exit_status);
|
||||||
|
|
||||||
Nova::reply(nullptr);
|
Nova::reply(nullptr);
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Vcpu_handler_vmx : public Vcpu_handler
|
||||||
VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP |
|
VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP |
|
||||||
VMX_VMCS_CTRL_PROC_EXEC2_EPT;
|
VMX_VMCS_CTRL_PROC_EXEC2_EPT;
|
||||||
|
|
||||||
void *exit_status = _start_routine(_arg);
|
void *exit_status = _start_routine(_start_routine_arg);
|
||||||
pthread_exit(exit_status);
|
pthread_exit(exit_status);
|
||||||
|
|
||||||
Nova::reply(nullptr);
|
Nova::reply(nullptr);
|
||||||
|
|
|
@ -799,6 +799,6 @@ bool create_emt_vcpu(pthread_t * pthread, ::size_t stack,
|
||||||
|
|
||||||
vcpu_handler_list().insert(vcpu_handler);
|
vcpu_handler_list().insert(vcpu_handler);
|
||||||
|
|
||||||
*pthread = vcpu_handler;
|
*pthread = &vcpu_handler->pthread_obj();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,14 +73,21 @@ static inline Genode::uint32_t sel_ar_conv_from_nova(Genode::uint16_t v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>,
|
||||||
public Genode::List<Vcpu_handler>::Element
|
public Genode::List<Vcpu_handler>::Element
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
pthread::start_routine_t const _start_routine;
|
||||||
|
void * const _start_routine_arg;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
X86FXSTATE _guest_fpu_state __attribute__((aligned(0x10)));
|
X86FXSTATE _guest_fpu_state __attribute__((aligned(0x10)));
|
||||||
X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10)));
|
X86FXSTATE _emt_fpu_state __attribute__((aligned(0x10)));
|
||||||
|
|
||||||
|
pthread _pthread;
|
||||||
|
|
||||||
Vmm::Vcpu_other_pd _vcpu;
|
Vmm::Vcpu_other_pd _vcpu;
|
||||||
|
|
||||||
Genode::addr_t _ec_sel;
|
Genode::addr_t _ec_sel;
|
||||||
|
@ -92,7 +99,7 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
||||||
|
|
||||||
void fpu_save(char * data) {
|
void fpu_save(char * data) {
|
||||||
Assert(!(reinterpret_cast<Genode::addr_t>(data) & 0xF));
|
Assert(!(reinterpret_cast<Genode::addr_t>(data) & 0xF));
|
||||||
asm volatile ("fxsave %0" : "=m" (*data));
|
asm volatile ("fxsave %0" : "=m" (*data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpu_load(char * data) {
|
void fpu_load(char * data) {
|
||||||
|
@ -782,20 +789,24 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>,
|
||||||
|
|
||||||
|
|
||||||
Vcpu_handler(Genode::Env &env, size_t stack_size, const pthread_attr_t *attr,
|
Vcpu_handler(Genode::Env &env, size_t stack_size, const pthread_attr_t *attr,
|
||||||
void *(*start_routine) (void *), void *arg,
|
pthread::start_routine_t start_routine, void *arg,
|
||||||
Genode::Cpu_session * cpu_session,
|
Genode::Cpu_session * cpu_session,
|
||||||
Genode::Affinity::Location location,
|
Genode::Affinity::Location location,
|
||||||
unsigned int cpu_id, const char * name,
|
unsigned int cpu_id, const char * name,
|
||||||
Genode::Pd_session_capability pd_vcpu)
|
Genode::Pd_session_capability pd_vcpu)
|
||||||
:
|
:
|
||||||
Vmm::Vcpu_dispatcher<pthread>(env, stack_size, cpu_session, location,
|
Vmm::Vcpu_dispatcher<Genode::Thread>(env, stack_size, cpu_session,
|
||||||
attr ? *attr : 0, start_routine, arg,
|
location, name),
|
||||||
name),
|
_pthread(*this, attr ? *attr : 0),
|
||||||
|
_start_routine(start_routine),
|
||||||
|
_start_routine_arg(arg),
|
||||||
_vcpu(cpu_session, location, pd_vcpu),
|
_vcpu(cpu_session, location, pd_vcpu),
|
||||||
_ec_sel(Genode::cap_map()->insert()),
|
_ec_sel(Genode::cap_map()->insert()),
|
||||||
_cpu_id(cpu_id)
|
_cpu_id(cpu_id)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
pthread &pthread_obj() { return _pthread; }
|
||||||
|
|
||||||
unsigned int cpu_id() { return _cpu_id; }
|
unsigned int cpu_id() { return _cpu_id; }
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Vcpu_handler_svm : public Vcpu_handler
|
||||||
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_CPUID;
|
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_CPUID;
|
||||||
next_utcb.ctrl[1] = 0;
|
next_utcb.ctrl[1] = 0;
|
||||||
|
|
||||||
void *exit_status = _start_routine(_arg);
|
void *exit_status = _start_routine(_start_routine_arg);
|
||||||
pthread_exit(exit_status);
|
pthread_exit(exit_status);
|
||||||
|
|
||||||
Nova::reply(nullptr);
|
Nova::reply(nullptr);
|
||||||
|
|
|
@ -92,7 +92,7 @@ class Vcpu_handler_vmx : public Vcpu_handler
|
||||||
VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP |
|
VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP |
|
||||||
VMX_VMCS_CTRL_PROC_EXEC2_EPT;
|
VMX_VMCS_CTRL_PROC_EXEC2_EPT;
|
||||||
|
|
||||||
void *exit_status = _start_routine(_arg);
|
void *exit_status = _start_routine(_start_routine_arg);
|
||||||
pthread_exit(exit_status);
|
pthread_exit(exit_status);
|
||||||
|
|
||||||
Nova::reply(nullptr);
|
Nova::reply(nullptr);
|
||||||
|
|
Loading…
Reference in New Issue