From 73cff5c996d83666983eef798542b3c45c0e3ce6 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 27 Sep 2013 14:47:11 +0200 Subject: [PATCH] nova: don't wait for workers in cpu_session::pause If a local thread is attempted to be 'pause'd via cpu_session, don't wait until it gets into the recalled state. If the caller is lucky it is, if not return only the stack pointer. Avoids deadlocking of the gdb when attached to a process running a server. Issue #478 --- base-nova/include/base/pager.h | 7 +-- base-nova/src/core/include/platform_thread.h | 21 ++++++-- base-nova/src/core/platform_thread.cc | 51 +++++++++++++------- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/base-nova/include/base/pager.h b/base-nova/include/base/pager.h index 72ba9f2be..b218a11fb 100644 --- a/base-nova/include/base/pager.h +++ b/base-nova/include/base/pager.h @@ -135,6 +135,7 @@ namespace Genode { /** * Set initial stack pointer used by the startup handler */ + addr_t initial_esp() { return _initial_esp; } void initial_esp(addr_t esp) { _initial_esp = esp; } /** @@ -183,14 +184,14 @@ namespace Genode { /** * Copy thread state of recalled thread. */ - int copy_thread_state(Thread_state * state_dst) + bool copy_thread_state(Thread_state * state_dst) { if (!state_dst || !_state.is_valid()) - return -1; + return false; *state_dst = _state.thread; - return 0; + return true; } /** diff --git a/base-nova/src/core/include/platform_thread.h b/base-nova/src/core/include/platform_thread.h index 7eb079b51..0f6b58f31 100644 --- a/base-nova/src/core/include/platform_thread.h +++ b/base-nova/src/core/include/platform_thread.h @@ -37,13 +37,24 @@ namespace Genode { addr_t _id_base; addr_t _sel_exc_base; Affinity::Location _location; - bool _is_main_thread; - bool _is_vcpu; + + enum { + MAIN_THREAD = 0x1U, + VCPU = 0x2U, + WORKER = 0x4U, + }; + uint8_t _features; + char _name[Thread_base::Context::NAME_LEN]; addr_t _sel_ec() const { return _id_base; } addr_t _sel_sc() const { return _id_base + 1; } + /* convenience function to access _feature variable */ + inline bool is_main_thread() { return _features & MAIN_THREAD; } + inline bool is_vcpu() { return _features & VCPU; } + inline bool is_worker() { return _features & WORKER; } + public: /* invalid thread number */ @@ -144,9 +155,11 @@ namespace Genode { /** * Associate thread with protection domain */ - void bind_to_pd(Platform_pd *pd, bool is_main_thread) + void bind_to_pd(Platform_pd *pd, bool main_thread) { - _pd = pd, _is_main_thread = is_main_thread; + _pd = pd; + + if (main_thread) _features |= MAIN_THREAD; } void single_step(bool on); diff --git a/base-nova/src/core/platform_thread.cc b/base-nova/src/core/platform_thread.cc index a94b14c29..e58a75610 100644 --- a/base-nova/src/core/platform_thread.cc +++ b/base-nova/src/core/platform_thread.cc @@ -63,9 +63,9 @@ int Platform_thread::start(void *ip, void *sp) return -2; } - if (!_is_main_thread) { + if (!is_main_thread()) { addr_t initial_sp = reinterpret_cast(sp); - addr_t utcb = _is_vcpu ? 0 : round_page(initial_sp); + addr_t utcb = is_vcpu() ? 0 : round_page(initial_sp); if (_sel_exc_base == Native_thread::INVALID_INDEX) { PERR("exception base not specified"); @@ -82,6 +82,13 @@ int Platform_thread::start(void *ip, void *sp) return -4; } + if (!thread_global) { + _features |= WORKER; + + /* local/worker threads do not require a startup portal */ + revoke(Obj_crd(_pager->exc_pt_sel_client() + PT_SEL_STARTUP, 0)); + } + _pager->initial_eip((addr_t)ip); _pager->initial_esp(initial_sp); _pager->client_set_ec(_sel_ec()); @@ -181,18 +188,20 @@ int Platform_thread::start(void *ip, void *sp) Native_capability Platform_thread::pause() { - if (!_pager) - return Native_capability::invalid_cap(); + if (!_pager) return Native_capability(); Native_capability notify_sm = _pager->notify_sm(); if (!notify_sm.valid()) return notify_sm; - if (_pager->client_recall() != Nova::NOVA_OK) - return Native_capability::invalid_cap(); + if (_pager->client_recall() != Nova::NOVA_OK) + return Native_capability(); - /* If the thread is blocked in the its own SM, get him out */ + /* If the thread is blocked in its own SM, get him out */ cancel_blocking(); + /* local thread may never get be canceled if it doesn't receive an IPC */ + if (is_worker()) return Native_capability(); + return notify_sm; } @@ -201,8 +210,10 @@ void Platform_thread::resume() { using namespace Nova; - uint8_t res = create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), Qpd()); - if (res == NOVA_OK) return; + if (!is_worker()) { + uint8_t res = create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), Qpd()); + if (res == NOVA_OK) return; + } if (!_pager) return; @@ -213,9 +224,15 @@ void Platform_thread::resume() Thread_state Platform_thread::state() { - Thread_state s; if (!_pager) throw Cpu_session::State_access_failed(); - _pager->copy_thread_state(&s); + + Thread_state s; + if (_pager->copy_thread_state(&s)) + return s; + + if (is_worker()) + s.sp = _pager->initial_esp(); + return s; } @@ -223,20 +240,20 @@ Thread_state Platform_thread::state() void Platform_thread::state(Thread_state s) { /* not permitted for main thread */ - if (_is_main_thread) throw Cpu_session::State_access_failed(); + if (is_main_thread()) throw Cpu_session::State_access_failed(); /* you can do it only once */ if (_sel_exc_base != Native_thread::INVALID_INDEX) throw Cpu_session::State_access_failed(); /* - * _sel_exc_base exception base of thread in caller + * s.sel_exc_base exception base of thread in caller * protection domain - not in Core ! - * _is_vcpu If true it will run as vCPU, - * otherwise it will be a thread. + * s.is_vcpu If true it will run as vCPU, + * otherwise it will be a thread. */ _sel_exc_base = s.sel_exc_base; - _is_vcpu = s.is_vcpu; + if (s.is_vcpu) _features |= VCPU; } @@ -272,7 +289,7 @@ Platform_thread::Platform_thread(const char *name, unsigned, int thread_id) : _pd(0), _pager(0), _id_base(cap_selector_allocator()->alloc(1)), _sel_exc_base(Native_thread::INVALID_INDEX), _location(boot_cpu(), 0), - _is_main_thread(false), _is_vcpu(false) + _features(0) { strncpy(_name, name, sizeof(_name)); }