/* * \brief Thread interface * \author Norman Feske * \date 2006-04-28 */ /* * Copyright (C) 2006-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 _INCLUDE__BASE__THREAD_H_ #define _INCLUDE__BASE__THREAD_H_ /* Genode includes */ #include #include #include #include #include #include /* for 'Thread_capability' type */ namespace Genode { struct Native_utcb; struct Native_thread; class Thread; class Stack; class Env; template class Thread_deprecated; } /** * Concurrent flow of control * * A 'Thread' object corresponds to a physical thread. The execution * starts at the 'entry()' method as soon as 'start()' is called. */ class Genode::Thread { public: class Out_of_stack_space : public Exception { }; class Stack_too_large : public Exception { }; class Stack_alloc_failed : public Exception { }; typedef Affinity::Location Location; typedef Cpu_session::Name Name; typedef Cpu_session::Weight Weight; struct Stack_info { addr_t base; addr_t top; }; struct Tls { struct Base; Base *ptr; }; private: /** * Allocate and locally attach a new stack * * \param stack_size size of this threads stack * \param main_thread wether this is the main thread */ Stack *_alloc_stack(size_t stack_size, char const *name, bool main_thread); /** * Detach and release stack of the thread */ void _free_stack(Stack *stack); /** * Platform-specific thread-startup code * * On some platforms, each new thread has to perform a startup * protocol, e.g., waiting for a message from the kernel. This hook * method allows for the implementation of such protocols. */ void _thread_bootstrap(); /** * Helper for thread startup */ static void _thread_start(); /** * Hook for platform-specific destructor supplements */ void _deinit_platform_thread(); /* * Noncopyable */ Thread(Thread const &); Thread &operator = (Thread const &); protected: /** * Capability for this thread (set by _start()) * * Used if thread creation involves core's CPU service. */ Thread_capability _thread_cap { }; /** * Pointer to cpu session used for this thread */ Cpu_session *_cpu_session = nullptr; /** * Session-local thread affinity */ Affinity::Location _affinity; /** * Base pointer to Trace::Control area used by this thread */ Trace::Control *_trace_control = nullptr; /** * Pointer to primary stack */ Stack *_stack = nullptr; /** * Pointer to kernel-specific meta data */ Native_thread *_native_thread = nullptr; /** * Blockade used for synchronizing the finalization of the thread */ Blockade _join { }; /** * Thread type * * Some threads need special treatment at construction. This enum * is solely used to distinguish them at construction. */ enum Type { NORMAL, MAIN, REINITIALIZED_MAIN }; private: Trace::Logger _trace_logger { }; /** * Return 'Trace::Logger' instance of calling thread * * This method is used by the tracing framework internally. */ static Trace::Logger *_logger(); /** * Base pointer to thread-local storage * * The opaque pointer allows higher-level thread libraries (i.e., * pthread) to implement TLS. It should never be used outside such * libraries. */ Tls _tls { }; friend class Tls::Base; /** * Hook for platform-specific constructor supplements * * \param weight weighting regarding the CPU session quota * \param type enables selection of special initialization */ void _init_platform_thread(size_t weight, Type type); void _init_cpu_session_and_trace_control(); public: /** * Constructor * * \noapi * * FIXME: With type = Forked_main_thread the stack allocation * gets skipped but we should at least set Stack::ds_cap in a * way that it references the dataspace of the already attached * stack. * * \deprecated superseded by the 'Thread(Env &...' constructor */ Thread(size_t weight, const char *name, size_t stack_size, Type type, Affinity::Location affinity = Affinity::Location()); /** * Constructor * * \noapi * * \param weight weighting regarding the CPU session quota * \param name thread name (for debugging) * \param stack_size stack size * * \throw Stack_too_large * \throw Stack_alloc_failed * \throw Out_of_stack_space * * The stack for the new thread will be allocated from the RAM session * of the component environment. A small portion of the stack size is * internally used by the framework for storing thread-specific * information such as the thread's name. * * \deprecated superseded by the 'Thread(Env &...' constructor */ Thread(size_t weight, const char *name, size_t stack_size, Affinity::Location affinity = Affinity::Location()) : Thread(weight, name, stack_size, NORMAL, affinity) { } /** * Constructor * * Variant of the constructor that allows the use of a different * CPU session. * * \noapi Using multiple CPU sessions within a single component is * an experimental feature. * * \param weight weighting regarding the CPU session quota * \param name thread name (for debugging) * \param stack_size stack size * \param type enables selection of special construction * \param cpu_session capability to cpu session used for construction * * \throw Stack_too_large * \throw Stack_alloc_failed * \throw Out_of_stack_space * * \deprecated superseded by the 'Thread(Env &...' constructor */ Thread(size_t weight, const char *name, size_t stack_size, Type type, Cpu_session *, Affinity::Location affinity = Affinity::Location()); /** * Constructor * * \param env component environment * \param name thread name, used for debugging * \param stack_size stack size * \param location CPU affinity relative to the CPU-session's * affinity space * \param weight scheduling weight relative to the other threads * sharing the same CPU session * \param cpu_session CPU session used to create the thread. Normally * 'env.cpu()' should be specified. * * The 'env' argument is needed because the thread creation procedure * needs to interact with the environment for attaching the thread's * stack, the trace-control dataspace, and the thread's trace buffer * and policy. * * \throw Stack_too_large * \throw Stack_alloc_failed * \throw Out_of_stack_space */ Thread(Env &env, Name const &name, size_t stack_size, Location location, Weight weight, Cpu_session &cpu); /** * Constructor * * This is a shortcut for the common case of creating a thread via * the environment's CPU session, at the default affinity location, and * with the default weight. */ Thread(Env &env, Name const &name, size_t stack_size); /** * Destructor */ virtual ~Thread(); /** * Entry method of the thread */ virtual void entry() = 0; /** * Start execution of the thread * * This method is virtual to enable the customization of threads * used as server activation. */ virtual void start(); /** * Request name of thread * * \noapi * \deprecated use the 'Name name() const' method instead */ void name(char *dst, size_t dst_len); /** * Request name of thread */ Name name() const; /** * Add an additional stack to the thread * * \throw Stack_too_large * \throw Stack_alloc_failed * \throw Out_of_stack_space * * The stack for the new thread will be allocated from the RAM * session of the component environment. A small portion of the * stack size is internally used by the framework for storing * thread-specific information such as the thread's name. * * \return pointer to the new stack's top */ void* alloc_secondary_stack(char const *name, size_t stack_size); /** * Remove a secondary stack from the thread */ void free_secondary_stack(void* stack_addr); /** * Request capability of thread */ Thread_capability cap() const { return _thread_cap; } /** * Cancel currently blocking operation * * \deprecated * \noapi */ void cancel_blocking(); /** * Return kernel-specific thread meta data */ Native_thread &native_thread(); /** * Return top of primary stack * * \return pointer just after first stack element */ void *stack_top() const; /** * Return base of primary stack * * \return pointer to last stack element */ void *stack_base() const; /** * Return virtual size reserved for each stack within the stack area */ static size_t stack_virtual_size(); /** * Return the local base address of the stack area */ static addr_t stack_area_virtual_base(); /** * Return total size of the stack area */ static size_t stack_area_virtual_size(); /** * Return 'Thread' object corresponding to the calling thread * * \return pointer to caller's 'Thread' object */ static Thread *myself(); /** * Return information about the current stack */ static Stack_info mystack(); /** * Ensure that the stack has a given size at the minimum * * \param size minimum stack size * * \throw Stack_too_large * \throw Stack_alloc_failed */ void stack_size(size_t const size); /** * Return user-level thread control block * * Note that it is safe to call this method on the result of the * 'myself' class function. It handles the special case of 'myself' * being 0 when called by the main thread during the component * initialization phase. */ Native_utcb *utcb(); /** * Block until the thread leaves the 'entry' method * * Join must not be called more than once. Subsequent calls have * undefined behaviour. */ void join(); /** * Log null-terminated string as trace event */ static void trace(char const *cstring) { _logger()->log(cstring, strlen(cstring)); } /** * Log null-terminated string as trace event using log_output policy * * \return true if trace is really put to buffer */ static bool trace_captured(char const *cstring) { return _logger()->log_captured(cstring, strlen(cstring)); } /** * Log binary data as trace event */ static void trace(char const *data, size_t len) { _logger()->log(data, len); } /** * Log trace event as defined in base/trace/events.h */ template static void trace(EVENT const *event) { _logger()->log(event); } /** * Thread affinity */ Affinity::Location affinity() const { return _affinity; } }; template class Genode::Thread_deprecated : public Thread { public: /** * Constructor * * \param weight weighting regarding the CPU session quota * \param name thread name (for debugging) * \param type enables selection of special construction */ explicit Thread_deprecated(size_t weight, const char *name) : Thread(weight, name, STACK_SIZE, Type::NORMAL) { } /** * Constructor * * \param weight weighting regarding the CPU session quota * \param name thread name (for debugging) * \param type enables selection of special construction * * \noapi */ explicit Thread_deprecated(size_t weight, const char *name, Type type) : Thread(weight, name, STACK_SIZE, type) { } /** * Constructor * * \param weight weighting regarding the CPU session quota * \param name thread name (for debugging) * \param cpu_session thread created via specific cpu session * * \noapi */ explicit Thread_deprecated(size_t weight, const char *name, Cpu_session * cpu_session) : Thread(weight, name, STACK_SIZE, Type::NORMAL, cpu_session) { } /** * Shortcut for 'Thread(DEFAULT_WEIGHT, name, type)' * * \noapi */ explicit Thread_deprecated(const char *name, Type type = NORMAL) : Thread(Weight::DEFAULT_WEIGHT, name, STACK_SIZE, type) { } /** * Shortcut for 'Thread(DEFAULT_WEIGHT, name, cpu_session)' * * \noapi */ explicit Thread_deprecated(const char *name, Cpu_session * cpu_session) : Thread(Weight::DEFAULT_WEIGHT, name, STACK_SIZE, Type::NORMAL, cpu_session) { } }; #endif /* _INCLUDE__BASE__THREAD_H_ */