mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-12 13:48:30 +00:00
hw: fully functional Thread_base::cancel_blocking
Thread_base::cancel_blocking brings a thread back to execution from every state, except the thread is created but not started yet. Fix #745
This commit is contained in:
parent
89a8c2c211
commit
ee28a69c98
@ -268,6 +268,9 @@ namespace Kernel
|
||||
* \retval >0 if syscall was successful and thread were already active
|
||||
* \retval <0 if targeted thread doesn't participate in CPU
|
||||
* scheduling after
|
||||
*
|
||||
* If the targeted thread blocks for any event except a 'start_thread'
|
||||
* call this call cancels the blocking.
|
||||
*/
|
||||
inline int resume_thread(unsigned const id = 0) {
|
||||
return syscall(RESUME_THREAD, id); }
|
||||
@ -524,12 +527,14 @@ namespace Kernel
|
||||
*
|
||||
* \param context_id kernel name of the targeted signal context
|
||||
*
|
||||
* \return wether the context could be destructed
|
||||
*
|
||||
* Blocks the caller until the last delivered signal of the targeted
|
||||
* context is acknowledged. Then the context gets destructed, losing
|
||||
* all submits that were not delivered when this syscall occured.
|
||||
*/
|
||||
inline void kill_signal_context(unsigned context_id) {
|
||||
syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
|
||||
inline bool kill_signal_context(unsigned context_id) {
|
||||
return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
|
||||
|
||||
/**
|
||||
* Create a new virtual-machine that is stopped initially
|
||||
|
@ -115,8 +115,12 @@ void Signal_receiver::_unsynchronized_dissolve(Signal_context * c)
|
||||
* that no delivered but unacked signals of this context exist
|
||||
* in userland anymore.
|
||||
*/
|
||||
Kernel::kill_signal_context(c->_cap.dst());
|
||||
if (!Kernel::kill_signal_context(c->_cap.dst())) {
|
||||
PERR("failed to kill signal context");
|
||||
|
||||
/* we have to keep the signal context alive for other */
|
||||
while (1) ;
|
||||
}
|
||||
/*
|
||||
* Now we can tell core to regain the memory of the
|
||||
* destructed kernel object.
|
||||
|
@ -99,6 +99,6 @@ void Thread_base::start()
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::cancel_blocking()
|
||||
{ env()->cpu_session()->cancel_blocking(_thread_cap); }
|
||||
void Thread_base::cancel_blocking() {
|
||||
env()->cpu_session()->cancel_blocking(_thread_cap); }
|
||||
|
||||
|
@ -60,6 +60,14 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Ipc_node::cancel_waiting()
|
||||
{
|
||||
if (_state == PREPARE_AND_AWAIT_REPLY) _state = PREPARE_REPLY;
|
||||
if (_state == AWAIT_REPLY || _state == AWAIT_REQUEST) _state = INACTIVE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Ipc_node::_receive_request(Message_buf * const r)
|
||||
{
|
||||
/* assertions */
|
||||
@ -79,9 +87,11 @@ void Kernel::Ipc_node::_receive_request(Message_buf * const r)
|
||||
void Kernel::Ipc_node::_receive_reply(void * const base, size_t const size)
|
||||
{
|
||||
/* assertions */
|
||||
assert(_awaits_reply());
|
||||
assert(size <= _inbuf.size);
|
||||
|
||||
if (!_awaits_reply()) {
|
||||
PDBG("discard unexpected IPC reply");
|
||||
return;
|
||||
}
|
||||
/* receive reply */
|
||||
Genode::memcpy(_inbuf.base, base, size);
|
||||
_inbuf.size = size;
|
||||
@ -373,6 +383,10 @@ void Kernel::Irq_owner::await_irq()
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Irq_owner::cancel_waiting() {
|
||||
if (_id) pic()->mask(id_to_irq(_id)); }
|
||||
|
||||
|
||||
void Kernel::Irq_owner::receive_irq(unsigned const irq)
|
||||
{
|
||||
assert(_id == irq_to_id(irq));
|
||||
@ -433,16 +447,16 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_activate()
|
||||
void Kernel::Thread::_schedule()
|
||||
{
|
||||
cpu_scheduler()->insert(this);
|
||||
_state = ACTIVE;
|
||||
_state = SCHEDULED;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::pause()
|
||||
{
|
||||
assert(_state == AWAIT_RESUMPTION || _state == ACTIVE);
|
||||
assert(_state == AWAIT_RESUMPTION || _state == SCHEDULED);
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_RESUMPTION;
|
||||
}
|
||||
@ -451,20 +465,7 @@ void Kernel::Thread::pause()
|
||||
void Kernel::Thread::stop()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = STOPPED;
|
||||
}
|
||||
|
||||
|
||||
int Kernel::Thread::resume()
|
||||
{
|
||||
if (_state != AWAIT_RESUMPTION && _state != ACTIVE) {
|
||||
PDBG("Unexpected thread state");
|
||||
return -1;
|
||||
}
|
||||
cpu_scheduler()->insert(this);
|
||||
if (_state == ACTIVE) return 1;
|
||||
_state = ACTIVE;
|
||||
return 0;
|
||||
_state = AWAIT_START;
|
||||
}
|
||||
|
||||
|
||||
@ -489,17 +490,25 @@ void Kernel::Thread::reply(size_t const size, bool const await_request)
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::await_signal()
|
||||
void Kernel::Thread::await_signal(Kernel::Signal_receiver * receiver)
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = AWAIT_IRQ;
|
||||
_state = AWAIT_SIGNAL;
|
||||
_signal_receiver = receiver;
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::received_signal()
|
||||
{
|
||||
assert(_state == AWAIT_SIGNAL);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_received_irq()
|
||||
{
|
||||
assert(_state == AWAIT_IRQ);
|
||||
_activate();
|
||||
_schedule();
|
||||
}
|
||||
|
||||
|
||||
@ -533,7 +542,7 @@ void Kernel::Thread::scheduled_next()
|
||||
void Kernel::Thread::_has_received(size_t const s)
|
||||
{
|
||||
user_arg_0(s);
|
||||
if (_state != ACTIVE) _activate();
|
||||
if (_state != SCHEDULED) _schedule();
|
||||
}
|
||||
|
||||
|
||||
@ -598,16 +607,19 @@ namespace Kernel
|
||||
|
||||
/**
|
||||
* Destruct or prepare to do it at next call of 'ack'
|
||||
*
|
||||
* \return wether destruction is done
|
||||
*/
|
||||
void kill(Thread * const killer)
|
||||
bool kill(Thread * const killer)
|
||||
{
|
||||
assert(!_killer);
|
||||
_killer = killer;
|
||||
if (_await_ack) {
|
||||
_killer->kill_signal_context_blocks();
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
this->~Signal_context();
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
@ -655,11 +667,17 @@ namespace Kernel
|
||||
*/
|
||||
void add_listener(Thread * const t)
|
||||
{
|
||||
t->await_signal();
|
||||
t->await_signal(this);
|
||||
_listeners.enqueue(t);
|
||||
_listen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a thread from listening to our contexts
|
||||
*/
|
||||
void remove_listener(Thread * const t) {
|
||||
_listeners.remove(t); }
|
||||
|
||||
/**
|
||||
* If any of our contexts is pending
|
||||
*/
|
||||
@ -1279,7 +1297,7 @@ namespace Kernel
|
||||
Signal_context * const c =
|
||||
Signal_context::pool()->object(user->user_arg_1());
|
||||
assert(c);
|
||||
c->kill(user);
|
||||
user->user_arg_0(c->kill(user));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1476,13 +1494,48 @@ extern "C" void kernel()
|
||||
** Kernel::Thread **
|
||||
********************/
|
||||
|
||||
int Kernel::Thread::resume()
|
||||
{
|
||||
switch (_state) {
|
||||
case AWAIT_RESUMPTION:
|
||||
_schedule();
|
||||
return 0;
|
||||
case SCHEDULED:
|
||||
return 1;
|
||||
case AWAIT_IPC:
|
||||
PDBG("cancel IPC receipt");
|
||||
Ipc_node::cancel_waiting();
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_IRQ:
|
||||
PDBG("cancel IRQ receipt");
|
||||
Irq_owner::cancel_waiting();
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL:
|
||||
PDBG("cancel signal receipt");
|
||||
_signal_receiver->remove_listener(this);
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_SIGNAL_CONTEXT_DESTRUCT:
|
||||
PDBG("cancel signal context destruction");
|
||||
_schedule();
|
||||
return 0;
|
||||
case AWAIT_START:
|
||||
default:
|
||||
PERR("unresumable state");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Thread::start(void *ip, void *sp, unsigned cpu_no,
|
||||
unsigned const pd_id,
|
||||
Native_utcb * const phys_utcb,
|
||||
Native_utcb * const virt_utcb)
|
||||
{
|
||||
/* check state and arguments */
|
||||
assert(_state == STOPPED)
|
||||
assert(_state == AWAIT_START)
|
||||
assert(!cpu_no);
|
||||
|
||||
/* apply thread configuration */
|
||||
@ -1494,7 +1547,7 @@ int Thread::start(void *ip, void *sp, unsigned cpu_no,
|
||||
user_arg_0((unsigned)_virt_utcb);
|
||||
|
||||
/* start thread */
|
||||
_activate();
|
||||
_schedule();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1531,14 +1584,18 @@ void Thread::pagefault(addr_t const va, bool const w)
|
||||
void Thread::kill_signal_context_blocks()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = KILL_SIGNAL_CONTEXT_BLOCKS;
|
||||
_state = AWAIT_SIGNAL_CONTEXT_DESTRUCT;
|
||||
}
|
||||
|
||||
|
||||
void Thread::kill_signal_context_done()
|
||||
{
|
||||
assert(_state == KILL_SIGNAL_CONTEXT_BLOCKS)
|
||||
_activate();
|
||||
if (_state != AWAIT_SIGNAL_CONTEXT_DESTRUCT) {
|
||||
PDBG("ignore unexpected signal-context destruction");
|
||||
return;
|
||||
}
|
||||
user_arg_0(1);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
|
||||
|
@ -532,23 +532,26 @@ namespace Kernel
|
||||
* IPC node states:
|
||||
*
|
||||
* +----------+ +---------------+ +---------------+
|
||||
* --new-->| inactive |--send-request-await-reply---->| await reply | +--send-note--| prepare reply |
|
||||
* --new-->| inactive |---send-request-await-reply--->| await reply | +--send-note--| prepare reply |
|
||||
* | |<--receive-reply---------------| | | | |
|
||||
* | |<--cancel-waiting--------------| | | | |
|
||||
* | | +---------------+ +------------>| |
|
||||
* | |<--request-is-a-note-------+---request-is-not-a-note------------------------>| |
|
||||
* | |<--------------------------(---not-await-request-----+ | |
|
||||
* | | | +---------------+ | | |
|
||||
* | |--await-request------------+-->| await request |<----+--send-reply-----------| |
|
||||
* | |--send-reply---------+-----+-->| |--announce-request-+-------->| |
|
||||
* | |--send-note--+ | | +---------------+ | | |
|
||||
* | | | | request available | | |
|
||||
* | |<------------+ | | | | |
|
||||
* | |<--not-await-request-+ | | | |
|
||||
* | |<--request-is-a-note-------+---request-is-not-a-note---------------|-------->| |
|
||||
* | |<--request-is-a-note-----------------------------------------------+ | |
|
||||
* | |<--------------------------(---not-await-request---+ | |
|
||||
* | | | +---------------+ | | |
|
||||
* | |---await-request-----------+-->| await request |<--+--send-reply-------------| |
|
||||
* | |<--cancel-waiting--------------| |------announce-request--+--->| |
|
||||
* | |---send-reply---------+----+-->| | | | |
|
||||
* | |---send-note--+ | | +---------------+ | | |
|
||||
* | | | | | | | |
|
||||
* | |<-------------+ | request available | | |
|
||||
* | |<--not-await-request--+ | | | |
|
||||
* | |<--request-is-a-note-------+-------------------request-is-not-a-note----(--->| |
|
||||
* | |<--request-is-a-note----------------------------------------------------+ | |
|
||||
* +----------+ +-------------------------+ | |
|
||||
* | prepare and await reply |<--send-request-and-await-reply--| |
|
||||
* | |--receive-reply----------------->| |
|
||||
* | |---receive-reply---------------->| |
|
||||
* | |---cancel-waiting--------------->| |
|
||||
* +-------------------------+ +---------------+
|
||||
*
|
||||
* State model propagated to deriving classes:
|
||||
@ -565,6 +568,7 @@ namespace Kernel
|
||||
* | |<--request-available-or-not-await-request--+ | |
|
||||
* | |<--announce-request----------------------------| |
|
||||
* | |<--receive-reply-------------------------------| |
|
||||
* | |<--cancel-waiting------------------------------| |
|
||||
* +--------------+ +----------------+
|
||||
*/
|
||||
class Ipc_node
|
||||
@ -593,9 +597,9 @@ namespace Kernel
|
||||
|
||||
Fifo<Message_buf> _request_queue; /* requests that waits to be
|
||||
* received by us */
|
||||
Message_buf _inbuf; /* buffers message we have received lastly */
|
||||
Message_buf _inbuf; /* buffers message we have received lastly */
|
||||
Message_buf _outbuf; /* buffers the message we aim to send */
|
||||
State _state; /* current node state */
|
||||
State _state; /* current node state */
|
||||
|
||||
/**
|
||||
* Buffer next request from request queue in 'r' to handle it
|
||||
@ -690,6 +694,11 @@ namespace Kernel
|
||||
void send_note(Ipc_node * const dest,
|
||||
void * const note_base,
|
||||
size_t const note_size);
|
||||
|
||||
/**
|
||||
* Stop waiting for a receipt if in a waiting state
|
||||
*/
|
||||
void cancel_waiting();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -754,6 +763,11 @@ namespace Kernel
|
||||
*/
|
||||
void await_irq();
|
||||
|
||||
/**
|
||||
* Stop waiting for an IRQ if in a waiting state
|
||||
*/
|
||||
void cancel_waiting();
|
||||
|
||||
/**
|
||||
* Denote occurence of an IRQ if we own it and awaited it
|
||||
*/
|
||||
@ -775,8 +789,16 @@ namespace Kernel
|
||||
public Ipc_node,
|
||||
public Irq_owner
|
||||
{
|
||||
enum State { STOPPED, ACTIVE, AWAIT_IPC, AWAIT_RESUMPTION,
|
||||
AWAIT_IRQ, AWAIT_SIGNAL, KILL_SIGNAL_CONTEXT_BLOCKS };
|
||||
enum State
|
||||
{
|
||||
SCHEDULED,
|
||||
AWAIT_START,
|
||||
AWAIT_IPC,
|
||||
AWAIT_RESUMPTION,
|
||||
AWAIT_IRQ,
|
||||
AWAIT_SIGNAL,
|
||||
AWAIT_SIGNAL_CONTEXT_DESTRUCT,
|
||||
};
|
||||
|
||||
Platform_thread * const _platform_thread; /* userland object wich
|
||||
* addresses this thread */
|
||||
@ -786,11 +808,13 @@ namespace Kernel
|
||||
unsigned _pd_id; /* ID of the PD this thread runs on */
|
||||
Native_utcb * _phys_utcb; /* physical UTCB base */
|
||||
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
||||
Signal_receiver * _signal_receiver; /* receiver we are currently
|
||||
* listen to */
|
||||
|
||||
/**
|
||||
* Resume execution
|
||||
*/
|
||||
void _activate();
|
||||
void _schedule();
|
||||
|
||||
|
||||
/**************
|
||||
@ -806,7 +830,7 @@ namespace Kernel
|
||||
** Irq_owner **
|
||||
***************/
|
||||
|
||||
void _received_irq() { _activate(); }
|
||||
void _received_irq();
|
||||
|
||||
void _awaits_irq();
|
||||
|
||||
@ -819,8 +843,8 @@ namespace Kernel
|
||||
*/
|
||||
Thread(Platform_thread * const platform_thread) :
|
||||
_platform_thread(platform_thread),
|
||||
_state(STOPPED), _pager(0), _pd_id(0),
|
||||
_phys_utcb(0), _virt_utcb(0)
|
||||
_state(AWAIT_START), _pager(0), _pd_id(0),
|
||||
_phys_utcb(0), _virt_utcb(0), _signal_receiver(0)
|
||||
{ }
|
||||
|
||||
/**
|
||||
@ -891,9 +915,9 @@ namespace Kernel
|
||||
unsigned id() const { return Object::id(); }
|
||||
|
||||
/**
|
||||
* Gets called when we await a signal at a signal receiver
|
||||
* Gets called when we await a signal at 'receiver'
|
||||
*/
|
||||
void await_signal();
|
||||
void await_signal(Kernel::Signal_receiver * receiver);
|
||||
|
||||
/**
|
||||
* Gets called when we have received a signal at a signal receiver
|
||||
|
@ -91,9 +91,5 @@ void Thread_base::join()
|
||||
}
|
||||
|
||||
|
||||
void Thread_base::cancel_blocking()
|
||||
{
|
||||
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
|
||||
while (1) ;
|
||||
}
|
||||
void Thread_base::cancel_blocking() { _tid.pt->cancel_blocking(); }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user