NOVA: let thread die if SM cap is invalid

Patch prevents following bugs:

* In sleep_forever the thread return from semaphore down if cap is revoked
  during destruction of a thread. This causes an endless loop consuming time
  not available for other threads.
* In lock_helper and cap_sel_alloc the thread return from the lock() method
  even if the semaphore down call failed because of an revoked semaphore.

  This lead to the situation that a thread subject to de-construction returns
  from the lock method, but not holding the lock, entering the critical section
  and modifying state inside the critical section. Another thread in parallel
  already in the critical section or entering the critical section also
  modifies the state. This lead to curious bugs ...
* thread_nova, thread_start, irq_session
  Detect early bugs if the SM is gone unexpectedly where it should never
  happen.
This commit is contained in:
Alexander Boettcher 2012-08-03 10:56:08 +02:00 committed by Norman Feske
parent 650a1d47f0
commit 4342d0d234
9 changed files with 47 additions and 15 deletions

View File

@ -20,6 +20,7 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
extern int main_thread_running_semaphore();
@ -32,7 +33,10 @@ namespace Genode {
Thread_base *myself = Thread_base::myself();
addr_t sem = myself ? myself->tid().exc_pt_sel + SM_SEL_EC :
main_thread_running_semaphore();
while (1) { Nova::sm_ctrl(sem, Nova::SEMAPHORE_DOWNZERO); }
while (1) {
if (Nova::sm_ctrl(sem, SEMAPHORE_DOWNZERO))
nova_die();
}
}
}

View File

@ -17,6 +17,17 @@
#include <base/printf.h>
#include <base/thread.h>
__attribute__((always_inline))
inline void nova_die(const char * text = 0)
{
/*
* If thread is de-constructed the sessions are already gone.
* Be careful when enabling printf here.
*/
while (1)
asm volatile ("ud2a" : : "a"(text));
}
inline void request_event_portal(Genode::Native_capability cap,
Genode::addr_t exc_base, Genode::addr_t event)
{
@ -31,7 +42,7 @@ inline void request_event_portal(Genode::Native_capability cap,
utcb->msg[0] = event;
utcb->set_msg_word(1);
uint8_t res = call(pager_cap.local_name());
uint8_t res = call(cap.local_name());
if (res)
PERR("request of event (%lu) capability selector failed",
event);

View File

@ -21,11 +21,12 @@
#ifndef _INCLUDE__SIGNAL_SESSION__SOURCE_CLIENT_H_
#define _INCLUDE__SIGNAL_SESSION__SOURCE_CLIENT_H_
#include <nova/syscalls.h>
#include <base/rpc_client.h>
#include <signal_session/nova_source.h>
#include <base/nova_util.h>
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
namespace Genode {
@ -34,7 +35,7 @@ namespace Genode {
private:
/**
* Capability with 'pt_sel' referring to a NOVA semaphore
* Capability referring to a NOVA semaphore
*/
Native_capability _sem;
@ -78,7 +79,7 @@ namespace Genode {
*/
if (Nova::sm_ctrl(_sem.local_name(),
Nova::SEMAPHORE_DOWN))
nova_die(__FILE__, __LINE__);
nova_die();
/*
* Now that the server has unblocked the semaphore, we are sure

View File

@ -20,6 +20,7 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
using namespace Genode;
@ -52,9 +53,17 @@ class Alloc_lock
*/
Alloc_lock() : _sm_cap(Nova::PD_SEL_CAP_LOCK) { }
void lock() { Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_DOWN); }
void lock()
{
if (Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_DOWN))
nova_die();
}
void unlock() { Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_UP); }
void unlock()
{
if (Nova::sm_ctrl(_sm_cap, Nova::SEMAPHORE_UP))
nova_die();
}
};

View File

@ -22,6 +22,7 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
extern int main_thread_running_semaphore();
@ -100,5 +101,6 @@ static inline void thread_stop_myself()
else
sem = main_thread_running_semaphore();
sm_ctrl(sem, SEMAPHORE_DOWNZERO);
if (sm_ctrl(sem, SEMAPHORE_DOWNZERO))
nova_die();
}

View File

@ -21,9 +21,8 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <base/nova_util.h>
#include <nova_cpu_session/connection.h>
#include <nova/util.h>
using namespace Genode;

View File

@ -25,7 +25,7 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <base/nova_util.h>
#include <nova/util.h>
#include <nova_cpu_session/connection.h>
using namespace Genode;
@ -139,5 +139,8 @@ void Thread_base::start()
void Thread_base::cancel_blocking()
{
Nova::sm_ctrl(_tid.exc_pt_sel + Nova::SM_SEL_EC, Nova::SEMAPHORE_UP);
using namespace Nova;
if (sm_ctrl(_tid.exc_pt_sel + SM_SEL_EC, SEMAPHORE_UP))
nova_die();
}

View File

@ -21,6 +21,7 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova/util.h>
#include <nova_util.h>
using namespace Genode;
@ -28,7 +29,8 @@ using namespace Genode;
void Irq_session_component::wait_for_irq()
{
Nova::sm_ctrl(_irq_number, Nova::SEMAPHORE_DOWN);
if (Nova::sm_ctrl(_irq_number, Nova::SEMAPHORE_DOWN))
nova_die();
}

View File

@ -92,5 +92,6 @@ void Thread_base::cancel_blocking()
{
using namespace Nova;
sm_ctrl(_tid.exc_pt_sel + SM_SEL_EC, SEMAPHORE_UP);
if (sm_ctrl(_tid.exc_pt_sel + SM_SEL_EC, SEMAPHORE_UP))
nova_die();
}