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
This commit is contained in:
Alexander Boettcher 2013-09-27 14:47:11 +02:00 committed by Norman Feske
parent d8cf17687e
commit 73cff5c996
3 changed files with 55 additions and 24 deletions

View File

@ -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;
}
/**

View File

@ -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);

View File

@ -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<addr_t>(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));
}