base-nova: increment 'pause' semaphore only when recall handler uses it in reply

Fixes #2796
This commit is contained in:
Christian Prochaska 2018-04-27 17:17:56 +02:00 committed by Christian Helmuth
parent e005d966b4
commit f78d856b37
2 changed files with 29 additions and 13 deletions

View File

@ -85,20 +85,24 @@ namespace Genode {
struct Thread_state thread;
addr_t sel_client_ec;
enum {
BLOCKED = 0x1U,
DEAD = 0x2U,
SINGLESTEP = 0x4U,
SIGNAL_SM = 0x8U,
DISSOLVED = 0x10U,
SUBMIT_SIGNAL = 0x20U,
BLOCKED = 0x1U,
DEAD = 0x2U,
SINGLESTEP = 0x4U,
SIGNAL_SM = 0x8U,
DISSOLVED = 0x10U,
SUBMIT_SIGNAL = 0x20U,
BLOCKED_PAUSE_SM = 0x40U,
};
uint8_t _status;
bool modified;
/* convenience function to access pause/recall state */
inline bool blocked() { return _status & BLOCKED;}
inline void block() { _status |= BLOCKED; }
inline void unblock() { _status &= ~BLOCKED; }
inline bool blocked() { return _status & BLOCKED;}
inline void block() { _status |= BLOCKED; }
inline void unblock() { _status &= ~BLOCKED; }
inline bool blocked_pause_sm() { return _status & BLOCKED_PAUSE_SM;}
inline void block_pause_sm() { _status |= BLOCKED_PAUSE_SM; }
inline void unblock_pause_sm() { _status &= ~BLOCKED_PAUSE_SM; }
inline void mark_dead() { _status |= DEAD; }
inline bool is_dead() { return _status & DEAD; }

View File

@ -156,6 +156,7 @@ void Pager_object::_page_fault_handler(addr_t pager_obj)
obj->_state.thread.trapno = PT_SEL_PAGE_FAULT;
obj->_state.block();
obj->_state.block_pause_sm();
obj->_state_lock.unlock();
@ -261,7 +262,12 @@ void Pager_object::_recall_handler(addr_t pager_obj)
/* block until cpu_session()->resume() respectively wake_up() call */
unsigned long sm = obj->_state.blocked() ? obj->sel_sm_block_pause() : 0;
unsigned long sm = 0;
if (obj->_state.blocked()) {
sm = obj->sel_sm_block_pause();
obj->_state.block_pause_sm();
}
obj->_state_lock.unlock();
@ -405,9 +411,15 @@ void Pager_object::wake_up()
_state.unblock();
uint8_t res = sm_ctrl(sel_sm_block_pause(), SEMAPHORE_UP);
if (res != NOVA_OK)
warning("canceling blocked client failed (thread sm)");
if (_state.blocked_pause_sm()) {
uint8_t res = sm_ctrl(sel_sm_block_pause(), SEMAPHORE_UP);
if (res == NOVA_OK)
_state.unblock_pause_sm();
else
warning("canceling blocked client failed (thread sm)");
}
}