Files
foc/l4/pkg/l4re-core/l4sys/include/thread
2018-06-25 15:44:17 +02:00

379 lines
13 KiB
C++

// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* Common thread related definitions.
*/
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
#pragma once
#include <l4/sys/capability>
#include <l4/sys/thread.h>
namespace L4 {
/**
* C++ L4 kernel thread interface.
*
* The Thread class defines a thread of execution in the L4 context.
* Usually user-level and kernel threads are mapped 1:1 to each other.
* Thread kernel objects are created using a factory, see the L4::Factory API
* (L4::Factory::create()).
*
* Amongst other things an L4::Thread encapsulates:
* - CPU state
* - General-purpose registers
* - Program counter
* - Stack pointer
* - FPU state
* - Scheduling parameters, see the L4::Scheduler API
* - Execution state
* - Blocked, Runnable, Running
*
* Thread objects provide an API for
* - Thread configuration and manipulation
* - Thread switching.
*
* \includefile{l4/sys/thread}
*
* For the C interface see the \ref l4_thread_api API.
*/
class Thread :
public Kobject_t<Thread, Kobject, L4_PROTO_THREAD,
Type_info::Demand_t<1> >
{
public:
/**
* Exchange basic thread registers.
*
* \param ip New instruction pointer, use ~0UL to leave the
* instruction pointer unchanged.
* \param sp New stack pointer, use ~0UL to leave the stack
* pointer unchanged.
* \param flags Ex-regs flags, see #L4_thread_ex_regs_flags.
* \param utcb UTCB to use for this operation.
*
* \return System call return tag
*
* This method allows to manipulate a thread. The basic functionality is to
* set the instruction pointer and the stack pointer of a thread.
* Additionally, this method allows also to cancel ongoing IPC operations and
* to force the thread to raise an artificial exception (see `flags`).
*
* The thread is started using L4::Scheduler::run_thread(). However, if at
* the time L4::Scheduler::run_thread() is called, the instruction pointer of
* the thread is invalid, a later call to ex_regs() with a valid instruction
* pointer might start the thread.
*/
l4_msgtag_t ex_regs(l4_addr_t ip, l4_addr_t sp,
l4_umword_t flags,
l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_ex_regs_u(cap(), ip, sp, flags, utcb); }
/**
* Exchange basic thread registers and return previous values.
*
* \param[in,out] ip New instruction pointer, use ~0UL to leave the
* instruction pointer unchanged, return previous
* instruction pointer.
* \param[in,out] sp New stack pointer, use ~0UL to leave the stack
* pointer unchanged, returns previous stack pointer.
* \param[in,out] flags Ex-regs flags, see #L4_thread_ex_regs_flags, return
* previous CPU flags of the thread.
* \param utcb UTCB to use for this operation.
*
* \return System call return tag. [out] parameters are only valid if the
* function returns successfully. Use l4_error() to check.
*
* This method allows to manipulate and start a thread. The basic
* functionality is to set the instruction pointer and the stack pointer of a
* thread. Additionally, this method allows also to cancel ongoing IPC
* operations and to force the thread to raise an artificial exception (see
* `flags`).
*/
l4_msgtag_t ex_regs(l4_addr_t *ip, l4_addr_t *sp,
l4_umword_t *flags,
l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_ex_regs_ret_u(cap(), ip, sp, flags, utcb); }
/**
* Thread attributes used for control_commit().
*
* This class is responsible for initializing various attributes of a
* thread in a UTCB for the control_commit() method.
*
* \see \ref l4_thread_control_api for some more details.
*/
class Attr
{
private:
friend class L4::Thread;
l4_utcb_t *_u;
public:
/**
* Create a thread-attribute object with the given UTCB.
*
* \param utcb The UTCB to use for the later L4::Thread::control_commit()
* function. Usually this is the UTCB of the calling thread.
*/
explicit Attr(l4_utcb_t *utcb = l4_utcb()) throw() : _u(utcb)
{ l4_thread_control_start_u(utcb); }
/**
* Set the pager capability selector.
*
* \param pager The capability selector that shall be used for page-fault
* messages. This capability selector must be valid within
* the task the thread is bound to.
*/
void pager(Cap<void> const &pager) throw()
{ l4_thread_control_pager_u(pager.cap(), _u); }
/**
* Get the capability selector used for page-fault messages.
*
* \return The capability selector used to send page-fault messages. The
* selector is valid in the task the thread is bound to.
*/
Cap<void> pager() throw()
{ return Cap<void>(l4_utcb_mr_u(_u)->mr[1]); }
/**
* Set the exception-handler capability selector.
*
* \param exc_handler The capability selector that shall be used for
* exception messages. This capability selector must
* be valid within the task the thread is bound to.
*/
void exc_handler(Cap<void> const &exc_handler) throw()
{ l4_thread_control_exc_handler_u(exc_handler.cap(), _u); }
/**
* Get the capability selector used for exception messages.
*
* \return The capability selector used to send exception messages. The
* selector is valid in the task the thread is bound to.
*/
Cap<void> exc_handler() throw()
{ return Cap<void>(l4_utcb_mr_u(_u)->mr[2]); }
/**
* Bind the thread to a task.
*
* \param thread_utcb The UTCB address of the thread within the task
* specified by `task`.
* \param task The capability selector for the task the thread
* shall be bound to.
*
* Binding a thread to a task means that the thread shall afterwards
* execute in the given task. To actually start execution you need
* to use L4::Thread::ex_regs().
*/
void bind(l4_utcb_t *thread_utcb, Cap<Task> const &task) throw()
{ l4_thread_control_bind_u(thread_utcb, task.cap(), _u); }
/**
* Set the thread to alien mode.
*/
void alien(int on) throw()
{ l4_thread_control_alien_u(_u, on); }
/**
* Allow host system calls on Fiasco-UX.
*
* \pre Running on Fiasco-UX.
*/
void ux_host_syscall(int on) throw()
{ l4_thread_control_ux_host_syscall_u(_u, on); }
};
/**
* Commit the given thread-attributes object.
*
* \param attr the attribute object to commit to the thread.
*/
l4_msgtag_t control(Attr const &attr) throw()
{ return l4_thread_control_commit_u(cap(), attr._u); }
/**
* Switch execution to this thread.
*
* \param utcb the UTCB of the current thread.
*
* \note The current time slice is inherited to this thread.
*/
l4_msgtag_t switch_to(l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_switch_u(cap(), utcb); }
/**
* Get consumed time of thread in us.
*
* \param[out] us Consumed time in µs.
* \param utcb UTCB of the current thread.
*
* \return Syscall return tag.
*/
l4_msgtag_t stats_time(l4_kernel_clock_t *us,
l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_stats_time_u(cap(), us, utcb); }
/**
* vCPU resume, start.
*
* \see l4_thread_vcpu_resume_start
*/
l4_msgtag_t vcpu_resume_start(l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_vcpu_resume_start_u(utcb); }
/**
* vCPU resume, commit.
*
* \see l4_thread_vcpu_resume_commit
*/
l4_msgtag_t vcpu_resume_commit(l4_msgtag_t tag,
l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_vcpu_resume_commit_u(cap(), tag, utcb); }
/**
* Enable or disable the vCPU feature for the thread.
*
* \param vcpu_state The virtual address where the kernel shall store the
* vCPU state in case of vCPU exits. The address must be
* a valid kernel-user-memory address (see
* L4::Task::add_ku_mem()).
* \param utcb UTCB to use for this operation.
*
* \return Syscall return tag.
*
* This function enables the vCPU feature of `this` thread if `vcpu_state`
* is set to a valid kernel-user-memory address, or disables the vCPU
* feature if `vcpu_state` is 0. (Disable: optional, currently unsupported.)
*/
l4_msgtag_t vcpu_control(l4_addr_t vcpu_state, l4_utcb_t *utcb = l4_utcb())
throw()
{ return l4_thread_vcpu_control_u(cap(), vcpu_state, utcb); }
/**
* Enable or disable the extended vCPU feature for the thread.
*
* \param ext_vcpu_state The virtual address where the kernel shall store
* the vCPU state in case of vCPU exits. The address
* must be a valid kernel-user-memory address (see
* L4::Task::add_ku_mem()).
* \param utcb UTCB to use for this operation.
*
* \return Syscall return tag.
*
* The extended vCPU feature allows the use of hardware-virtualization
* features such as Intel's VT or AMD's SVM.
*
* This function enables the extended vCPU feature of `this` thread
* if `ext_vcpu_state` is set to a valid kernel-user-memory address, or
* disables the vCPU feature if `ext_vcpu_state` is 0.
*
* \note The extended vCPU mode includes the normal vCPU mode.
*/
l4_msgtag_t vcpu_control_ext(l4_addr_t ext_vcpu_state,
l4_utcb_t *utcb = l4_utcb()) throw()
{ return l4_thread_vcpu_control_ext_u(cap(), ext_vcpu_state, utcb); }
/**
* Register an IRQ that will trigger upon deletion events.
*
* \param irq Capability selector for the IRQ object to be triggered.
* \utcb{u}
*
* \return System call return tag containing the return code.
*
* An example of a deletion event is the removal of an IPC gate
* that is bound to this thread.
*
* \see l4_thread_register_del_irq
*/
l4_msgtag_t register_del_irq(Cap<Irq> irq, l4_utcb_t *u = l4_utcb()) throw()
{ return l4_thread_register_del_irq_u(cap(), irq.cap(), u); }
/**
* Wrapper class for modifying senders.
*
* Use the add() function to add modification rules, and use
* modify_senders() to commit. Do not use the UTCB inbetween as it is
* used by add() and modify_senders().
*/
class Modify_senders
{
private:
friend class Thread;
l4_utcb_t *utcb;
unsigned cnt;
public:
explicit Modify_senders(l4_utcb_t *u = l4_utcb()) throw()
: utcb(u), cnt(1)
{
l4_utcb_mr_u(utcb)->mr[0] = L4_THREAD_MODIFY_SENDER_OP;
}
/**
* Add a rule.
*
* \param match_mask Bitmask of bits to match the label.
* \param match Bitmask that must be equal to the label after applying
* match_mask.
* \param del_bits Bits to be deleted from the label.
* \param add_bits Bits to be added to the label.
*
* \return 0 on sucess, <0 on error
*
* Only the first match is applied.
*
* \see l4_thread_modify_sender_add()
*/
int add(l4_umword_t match_mask, l4_umword_t match,
l4_umword_t del_bits, l4_umword_t add_bits) throw()
{
l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
if (cnt >= L4_UTCB_GENERIC_DATA_SIZE - 4)
return -L4_ENOMEM;
m->mr[cnt++] = match_mask;
m->mr[cnt++] = match;
m->mr[cnt++] = del_bits;
m->mr[cnt++] = add_bits;
return 0;
}
};
/**
* Apply sender modifiction rules.
*
* \param todo Prepared sender modification rules.
*
* \return System call return tag.
*/
l4_msgtag_t modify_senders(Modify_senders const &todo) throw()
{
return l4_ipc_call(cap(), todo.utcb, l4_msgtag(L4_PROTO_THREAD, todo.cnt, 0, 0), L4_IPC_NEVER);
}
};
}