/* * \brief Kernel backend for execution contexts in userland * \author Martin Stein * \date 2012-11-30 */ /* * Copyright (C) 2012-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _CORE__KERNEL__THREAD_H_ #define _CORE__KERNEL__THREAD_H_ #include #include /* core includes */ #include #include #include #include #include #include namespace Kernel { struct Thread_fault; class Thread; class Core_thread; } struct Kernel::Thread_fault { enum Type { WRITE, EXEC, PAGE_MISSING, UNKNOWN }; addr_t ip = 0; addr_t addr = 0; Type type = UNKNOWN; void print(Genode::Output &out) const; }; /** * Kernel back-end for userland execution-contexts */ class Kernel::Thread : public Kernel::Object, public Cpu_job, public Ipc_node, public Signal_context_killer, public Signal_handler, private Timeout { private: /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); /** * An update of page-table entries that requires architecture-wise * maintainance operations, e.g., a TLB invalidation needs * cross-cpu synchronization */ struct Pd_update : Inter_processor_work { Thread & caller; /* the caller gets blocked until all finished */ Pd & pd; /* the corresponding pd */ unsigned cnt; /* count of cpus left */ Pd_update(Thread & caller, Pd & pd, unsigned cnt); /************************************ ** Inter_processor_work interface ** ************************************/ void execute() override; }; /** * The destruction of a thread still active on another cpu * needs cross-cpu synchronization */ struct Destroy : Inter_processor_work { Thread & caller; /* the caller gets blocked till the end */ Thread & thread_to_destroy; /* thread to be destroyed */ Destroy(Thread & caller, Thread & to_destroy); /************************************ ** Inter_processor_work interface ** ************************************/ void execute() override; }; friend void Pd_update::execute(); friend void Destroy::execute(); protected: enum { START_VERBOSE = 0 }; enum State { ACTIVE = 1, AWAITS_START = 2, AWAITS_IPC = 3, AWAITS_RESTART = 4, AWAITS_SIGNAL = 5, AWAITS_SIGNAL_CONTEXT_KILL = 6, DEAD = 7, }; Signal_context * _pager = nullptr; Thread_fault _fault { }; State _state; Signal_receiver * _signal_receiver; char const * const _label; capid_t _timeout_sigid = 0; bool _paused = false; bool _cancel_next_await_signal = false; bool const _core = false; Genode::Constructible _pd_update {}; Genode::Constructible _destroy {}; /** * Notice that another thread yielded the CPU to this thread */ void _receive_yielded_cpu(); /** * Attach or detach the handler of a thread-triggered event * * \param event_id kernel name of the thread event * \param signal_context_id kernel name signal context or 0 to detach * * \retval 0 succeeded * \retval -1 failed */ int _route_event(unsigned const event_id, Signal_context * const signal_context_id); /** * Switch from an inactive state to the active state */ void _become_active(); /** * Switch from the active state to the inactive state 's' */ void _become_inactive(State const s); /** * Activate our CPU-share and those of our helpers */ void _activate_used_shares(); /** * Deactivate our CPU-share and those of our helpers */ void _deactivate_used_shares(); /** * Suspend unrecoverably from execution */ void _die(); /** * Handle an exception thrown by the memory management unit */ void _mmu_exception(); /** * Handle kernel-call request of the thread */ void _call(); /** * Return amount of timer ticks that 'quota' is worth */ size_t _core_to_kernel_quota(size_t const quota) const; void _cancel_blocking(); bool _restart(); /********************************************************* ** Kernel-call back-ends, see kernel-interface headers ** *********************************************************/ void _call_new_thread(); void _call_new_core_thread(); void _call_thread_quota(); void _call_start_thread(); void _call_stop_thread(); void _call_pause_thread(); void _call_resume_thread(); void _call_cancel_thread_blocking(); void _call_restart_thread(); void _call_yield_thread(); void _call_delete_thread(); void _call_await_request_msg(); void _call_send_request_msg(); void _call_send_reply_msg(); void _call_update_pd(); void _call_update_data_region(); void _call_update_instr_region(); void _call_print_char(); void _call_await_signal(); void _call_cancel_next_await_signal(); void _call_submit_signal(); void _call_ack_signal(); void _call_kill_signal_context(); void _call_new_vm(); void _call_delete_vm(); void _call_run_vm(); void _call_pause_vm(); void _call_pager(); void _call_new_irq(); void _call_ack_irq(); void _call_new_obj(); void _call_delete_obj(); void _call_ack_cap(); void _call_delete_cap(); void _call_timeout(); void _call_timeout_age_us(); void _call_timeout_max_us(); template void _call_new(ARGS &&... args) { using Object = Core_object; void * dst = (void *)user_arg_1(); Object * o = Genode::construct_at(dst, args...); user_arg_0(o->core_capid()); } template void _call_delete() { using Object = Core_object; reinterpret_cast(user_arg_1())->~Object(); } /*************************** ** Signal_context_killer ** ***************************/ void _signal_context_kill_pending() override; void _signal_context_kill_failed() override; void _signal_context_kill_done() override; /******************** ** Signal_handler ** ********************/ void _await_signal(Signal_receiver * const receiver) override; void _receive_signal(void * const base, size_t const size) override; /************** ** Ipc_node ** **************/ void _send_request_succeeded() override; void _send_request_failed() override; void _await_request_succeeded() override; void _await_request_failed() override; public: Genode::Align_at regs; /** * Constructor * * \param priority scheduling priority * \param quota CPU-time quota * \param label debugging label * \param core whether it is a core thread or not */ Thread(unsigned const priority, unsigned const quota, char const * const label, bool core = false); /** * Constructor for core/kernel thread * * \param label debugging label */ Thread(char const * const label) : Thread(Cpu_priority::MIN, 0, label, true) { } /************************** ** Support for syscalls ** **************************/ void user_arg_0(Kernel::Call_arg const arg); void user_arg_1(Kernel::Call_arg const arg); void user_arg_2(Kernel::Call_arg const arg); void user_arg_3(Kernel::Call_arg const arg); void user_arg_4(Kernel::Call_arg const arg); Kernel::Call_arg user_arg_0() const; Kernel::Call_arg user_arg_1() const; Kernel::Call_arg user_arg_2() const; Kernel::Call_arg user_arg_3() const; Kernel::Call_arg user_arg_4() const; /** * Syscall to create a thread * * \param p memory donation for the new kernel thread object * \param priority scheduling priority of the new thread * \param quota CPU quota of the new thread * \param label debugging label of the new thread * * \retval capability id of the new kernel object */ static capid_t syscall_create(void * const p, unsigned const priority, size_t const quota, char const * const label) { return call(call_id_new_thread(), (Call_arg)p, (Call_arg)priority, (Call_arg)quota, (Call_arg)label); } /** * Syscall to create a core thread * * \param p memory donation for the new kernel thread object * \param label debugging label of the new thread * * \retval capability id of the new kernel object */ static capid_t syscall_create(void * const p, char const * const label) { return call(call_id_new_core_thread(), (Call_arg)p, (Call_arg)label); } /** * Syscall to destroy a thread * * \param thread pointer to thread kernel object */ static void syscall_destroy(Thread * thread) { call(call_id_delete_thread(), (Call_arg)thread); } void print(Genode::Output &out) const; /************* ** Cpu_job ** *************/ void exception(Cpu & cpu) override; void proceed(Cpu & cpu) override; Cpu_job * helping_sink() override; /************* ** Timeout ** *************/ void timeout_triggered() override; /*************** ** Accessors ** ***************/ char const * label() const { return _label; } Thread_fault fault() const { return _fault; } }; /** * The first core thread in the system bootstrapped by the Kernel */ struct Kernel::Core_thread : Core_object { Core_thread(); static Thread & singleton(); }; #endif /* _CORE__KERNEL__THREAD_H_ */