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 syscall was successful and thread were already active
|
||||||
* \retval <0 if targeted thread doesn't participate in CPU
|
* \retval <0 if targeted thread doesn't participate in CPU
|
||||||
* scheduling after
|
* 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) {
|
inline int resume_thread(unsigned const id = 0) {
|
||||||
return syscall(RESUME_THREAD, id); }
|
return syscall(RESUME_THREAD, id); }
|
||||||
|
@ -524,12 +527,14 @@ namespace Kernel
|
||||||
*
|
*
|
||||||
* \param context_id kernel name of the targeted signal context
|
* \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
|
* Blocks the caller until the last delivered signal of the targeted
|
||||||
* context is acknowledged. Then the context gets destructed, losing
|
* context is acknowledged. Then the context gets destructed, losing
|
||||||
* all submits that were not delivered when this syscall occured.
|
* all submits that were not delivered when this syscall occured.
|
||||||
*/
|
*/
|
||||||
inline void kill_signal_context(unsigned context_id) {
|
inline bool kill_signal_context(unsigned context_id) {
|
||||||
syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
|
return syscall(KILL_SIGNAL_CONTEXT, (Syscall_arg)context_id); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new virtual-machine that is stopped initially
|
* 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
|
* that no delivered but unacked signals of this context exist
|
||||||
* in userland anymore.
|
* 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
|
* Now we can tell core to regain the memory of the
|
||||||
* destructed kernel object.
|
* destructed kernel object.
|
||||||
|
|
|
@ -99,6 +99,6 @@ void Thread_base::start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::cancel_blocking()
|
void Thread_base::cancel_blocking() {
|
||||||
{ env()->cpu_session()->cancel_blocking(_thread_cap); }
|
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)
|
void Kernel::Ipc_node::_receive_request(Message_buf * const r)
|
||||||
{
|
{
|
||||||
/* assertions */
|
/* 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)
|
void Kernel::Ipc_node::_receive_reply(void * const base, size_t const size)
|
||||||
{
|
{
|
||||||
/* assertions */
|
/* assertions */
|
||||||
assert(_awaits_reply());
|
|
||||||
assert(size <= _inbuf.size);
|
assert(size <= _inbuf.size);
|
||||||
|
if (!_awaits_reply()) {
|
||||||
|
PDBG("discard unexpected IPC reply");
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* receive reply */
|
/* receive reply */
|
||||||
Genode::memcpy(_inbuf.base, base, size);
|
Genode::memcpy(_inbuf.base, base, size);
|
||||||
_inbuf.size = 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)
|
void Kernel::Irq_owner::receive_irq(unsigned const irq)
|
||||||
{
|
{
|
||||||
assert(_id == irq_to_id(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);
|
cpu_scheduler()->insert(this);
|
||||||
_state = ACTIVE;
|
_state = SCHEDULED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::pause()
|
void Kernel::Thread::pause()
|
||||||
{
|
{
|
||||||
assert(_state == AWAIT_RESUMPTION || _state == ACTIVE);
|
assert(_state == AWAIT_RESUMPTION || _state == SCHEDULED);
|
||||||
cpu_scheduler()->remove(this);
|
cpu_scheduler()->remove(this);
|
||||||
_state = AWAIT_RESUMPTION;
|
_state = AWAIT_RESUMPTION;
|
||||||
}
|
}
|
||||||
|
@ -451,20 +465,7 @@ void Kernel::Thread::pause()
|
||||||
void Kernel::Thread::stop()
|
void Kernel::Thread::stop()
|
||||||
{
|
{
|
||||||
cpu_scheduler()->remove(this);
|
cpu_scheduler()->remove(this);
|
||||||
_state = STOPPED;
|
_state = AWAIT_START;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
cpu_scheduler()->remove(this);
|
||||||
_state = AWAIT_IRQ;
|
_state = AWAIT_SIGNAL;
|
||||||
|
_signal_receiver = receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::received_signal()
|
void Kernel::Thread::received_signal()
|
||||||
|
{
|
||||||
|
assert(_state == AWAIT_SIGNAL);
|
||||||
|
_schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Kernel::Thread::_received_irq()
|
||||||
{
|
{
|
||||||
assert(_state == AWAIT_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)
|
void Kernel::Thread::_has_received(size_t const s)
|
||||||
{
|
{
|
||||||
user_arg_0(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'
|
* 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);
|
assert(!_killer);
|
||||||
_killer = killer;
|
_killer = killer;
|
||||||
if (_await_ack) {
|
if (_await_ack) {
|
||||||
_killer->kill_signal_context_blocks();
|
_killer->kill_signal_context_blocks();
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
this->~Signal_context();
|
this->~Signal_context();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -655,11 +667,17 @@ namespace Kernel
|
||||||
*/
|
*/
|
||||||
void add_listener(Thread * const t)
|
void add_listener(Thread * const t)
|
||||||
{
|
{
|
||||||
t->await_signal();
|
t->await_signal(this);
|
||||||
_listeners.enqueue(t);
|
_listeners.enqueue(t);
|
||||||
_listen();
|
_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
|
* If any of our contexts is pending
|
||||||
*/
|
*/
|
||||||
|
@ -1279,7 +1297,7 @@ namespace Kernel
|
||||||
Signal_context * const c =
|
Signal_context * const c =
|
||||||
Signal_context::pool()->object(user->user_arg_1());
|
Signal_context::pool()->object(user->user_arg_1());
|
||||||
assert(c);
|
assert(c);
|
||||||
c->kill(user);
|
user->user_arg_0(c->kill(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1476,13 +1494,48 @@ extern "C" void kernel()
|
||||||
** Kernel::Thread **
|
** 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,
|
int Thread::start(void *ip, void *sp, unsigned cpu_no,
|
||||||
unsigned const pd_id,
|
unsigned const pd_id,
|
||||||
Native_utcb * const phys_utcb,
|
Native_utcb * const phys_utcb,
|
||||||
Native_utcb * const virt_utcb)
|
Native_utcb * const virt_utcb)
|
||||||
{
|
{
|
||||||
/* check state and arguments */
|
/* check state and arguments */
|
||||||
assert(_state == STOPPED)
|
assert(_state == AWAIT_START)
|
||||||
assert(!cpu_no);
|
assert(!cpu_no);
|
||||||
|
|
||||||
/* apply thread configuration */
|
/* apply thread configuration */
|
||||||
|
@ -1494,7 +1547,7 @@ int Thread::start(void *ip, void *sp, unsigned cpu_no,
|
||||||
user_arg_0((unsigned)_virt_utcb);
|
user_arg_0((unsigned)_virt_utcb);
|
||||||
|
|
||||||
/* start thread */
|
/* start thread */
|
||||||
_activate();
|
_schedule();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1531,14 +1584,18 @@ void Thread::pagefault(addr_t const va, bool const w)
|
||||||
void Thread::kill_signal_context_blocks()
|
void Thread::kill_signal_context_blocks()
|
||||||
{
|
{
|
||||||
cpu_scheduler()->remove(this);
|
cpu_scheduler()->remove(this);
|
||||||
_state = KILL_SIGNAL_CONTEXT_BLOCKS;
|
_state = AWAIT_SIGNAL_CONTEXT_DESTRUCT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread::kill_signal_context_done()
|
void Thread::kill_signal_context_done()
|
||||||
{
|
{
|
||||||
assert(_state == KILL_SIGNAL_CONTEXT_BLOCKS)
|
if (_state != AWAIT_SIGNAL_CONTEXT_DESTRUCT) {
|
||||||
_activate();
|
PDBG("ignore unexpected signal-context destruction");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
user_arg_0(1);
|
||||||
|
_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -532,23 +532,26 @@ namespace Kernel
|
||||||
* IPC node states:
|
* 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---------------| | | | |
|
* | |<--receive-reply---------------| | | | |
|
||||||
|
* | |<--cancel-waiting--------------| | | | |
|
||||||
* | | +---------------+ +------------>| |
|
* | | +---------------+ +------------>| |
|
||||||
* | |<--request-is-a-note-------+---request-is-not-a-note------------------------>| |
|
* | |<--request-is-a-note-------+---request-is-not-a-note------------------------>| |
|
||||||
* | |<--------------------------(---not-await-request-----+ | |
|
* | |<--------------------------(---not-await-request---+ | |
|
||||||
* | | | +---------------+ | | |
|
* | | | +---------------+ | | |
|
||||||
* | |--await-request------------+-->| await request |<----+--send-reply-----------| |
|
* | |---await-request-----------+-->| await request |<--+--send-reply-------------| |
|
||||||
* | |--send-reply---------+-----+-->| |--announce-request-+-------->| |
|
* | |<--cancel-waiting--------------| |------announce-request--+--->| |
|
||||||
* | |--send-note--+ | | +---------------+ | | |
|
* | |---send-reply---------+----+-->| | | | |
|
||||||
* | | | | request available | | |
|
* | |---send-note--+ | | +---------------+ | | |
|
||||||
* | |<------------+ | | | | |
|
* | | | | | | | |
|
||||||
* | |<--not-await-request-+ | | | |
|
* | |<-------------+ | request available | | |
|
||||||
* | |<--request-is-a-note-------+---request-is-not-a-note---------------|-------->| |
|
* | |<--not-await-request--+ | | | |
|
||||||
* | |<--request-is-a-note-----------------------------------------------+ | |
|
* | |<--request-is-a-note-------+-------------------request-is-not-a-note----(--->| |
|
||||||
|
* | |<--request-is-a-note----------------------------------------------------+ | |
|
||||||
* +----------+ +-------------------------+ | |
|
* +----------+ +-------------------------+ | |
|
||||||
* | prepare and await reply |<--send-request-and-await-reply--| |
|
* | prepare and await reply |<--send-request-and-await-reply--| |
|
||||||
* | |--receive-reply----------------->| |
|
* | |---receive-reply---------------->| |
|
||||||
|
* | |---cancel-waiting--------------->| |
|
||||||
* +-------------------------+ +---------------+
|
* +-------------------------+ +---------------+
|
||||||
*
|
*
|
||||||
* State model propagated to deriving classes:
|
* State model propagated to deriving classes:
|
||||||
|
@ -565,6 +568,7 @@ namespace Kernel
|
||||||
* | |<--request-available-or-not-await-request--+ | |
|
* | |<--request-available-or-not-await-request--+ | |
|
||||||
* | |<--announce-request----------------------------| |
|
* | |<--announce-request----------------------------| |
|
||||||
* | |<--receive-reply-------------------------------| |
|
* | |<--receive-reply-------------------------------| |
|
||||||
|
* | |<--cancel-waiting------------------------------| |
|
||||||
* +--------------+ +----------------+
|
* +--------------+ +----------------+
|
||||||
*/
|
*/
|
||||||
class Ipc_node
|
class Ipc_node
|
||||||
|
@ -690,6 +694,11 @@ namespace Kernel
|
||||||
void send_note(Ipc_node * const dest,
|
void send_note(Ipc_node * const dest,
|
||||||
void * const note_base,
|
void * const note_base,
|
||||||
size_t const note_size);
|
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();
|
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
|
* Denote occurence of an IRQ if we own it and awaited it
|
||||||
*/
|
*/
|
||||||
|
@ -775,8 +789,16 @@ namespace Kernel
|
||||||
public Ipc_node,
|
public Ipc_node,
|
||||||
public Irq_owner
|
public Irq_owner
|
||||||
{
|
{
|
||||||
enum State { STOPPED, ACTIVE, AWAIT_IPC, AWAIT_RESUMPTION,
|
enum State
|
||||||
AWAIT_IRQ, AWAIT_SIGNAL, KILL_SIGNAL_CONTEXT_BLOCKS };
|
{
|
||||||
|
SCHEDULED,
|
||||||
|
AWAIT_START,
|
||||||
|
AWAIT_IPC,
|
||||||
|
AWAIT_RESUMPTION,
|
||||||
|
AWAIT_IRQ,
|
||||||
|
AWAIT_SIGNAL,
|
||||||
|
AWAIT_SIGNAL_CONTEXT_DESTRUCT,
|
||||||
|
};
|
||||||
|
|
||||||
Platform_thread * const _platform_thread; /* userland object wich
|
Platform_thread * const _platform_thread; /* userland object wich
|
||||||
* addresses this thread */
|
* addresses this thread */
|
||||||
|
@ -786,11 +808,13 @@ namespace Kernel
|
||||||
unsigned _pd_id; /* ID of the PD this thread runs on */
|
unsigned _pd_id; /* ID of the PD this thread runs on */
|
||||||
Native_utcb * _phys_utcb; /* physical UTCB base */
|
Native_utcb * _phys_utcb; /* physical UTCB base */
|
||||||
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
||||||
|
Signal_receiver * _signal_receiver; /* receiver we are currently
|
||||||
|
* listen to */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume execution
|
* Resume execution
|
||||||
*/
|
*/
|
||||||
void _activate();
|
void _schedule();
|
||||||
|
|
||||||
|
|
||||||
/**************
|
/**************
|
||||||
|
@ -806,7 +830,7 @@ namespace Kernel
|
||||||
** Irq_owner **
|
** Irq_owner **
|
||||||
***************/
|
***************/
|
||||||
|
|
||||||
void _received_irq() { _activate(); }
|
void _received_irq();
|
||||||
|
|
||||||
void _awaits_irq();
|
void _awaits_irq();
|
||||||
|
|
||||||
|
@ -819,8 +843,8 @@ namespace Kernel
|
||||||
*/
|
*/
|
||||||
Thread(Platform_thread * const platform_thread) :
|
Thread(Platform_thread * const platform_thread) :
|
||||||
_platform_thread(platform_thread),
|
_platform_thread(platform_thread),
|
||||||
_state(STOPPED), _pager(0), _pd_id(0),
|
_state(AWAIT_START), _pager(0), _pd_id(0),
|
||||||
_phys_utcb(0), _virt_utcb(0)
|
_phys_utcb(0), _virt_utcb(0), _signal_receiver(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -891,9 +915,9 @@ namespace Kernel
|
||||||
unsigned id() const { return Object::id(); }
|
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
|
* 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()
|
void Thread_base::cancel_blocking() { _tid.pt->cancel_blocking(); }
|
||||||
{
|
|
||||||
kernel_log() << __PRETTY_FUNCTION__ << ": Not implemented\n";
|
|
||||||
while (1) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue