diff options
Diffstat (limited to 'include/distortos/internal/scheduler/Scheduler.hpp')
-rw-r--r-- | include/distortos/internal/scheduler/Scheduler.hpp | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/include/distortos/internal/scheduler/Scheduler.hpp b/include/distortos/internal/scheduler/Scheduler.hpp new file mode 100644 index 0000000..42037f2 --- /dev/null +++ b/include/distortos/internal/scheduler/Scheduler.hpp @@ -0,0 +1,351 @@ +/** + * \file + * \brief Scheduler class header + * + * \author Copyright (C) 2014-2016 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info + * + * \par License + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not + * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SCHEDULER_HPP_ +#define INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SCHEDULER_HPP_ + +#include "distortos/internal/scheduler/ThreadControlBlock.hpp" +#include "distortos/internal/scheduler/ThreadList.hpp" +#include "distortos/internal/scheduler/SoftwareTimerSupervisor.hpp" + +namespace distortos +{ + +namespace internal +{ + +class MainThread; + +/// Scheduler class is a system's scheduler +class Scheduler +{ +public: + + /** + * \brief Scheduler's constructor + */ + + constexpr Scheduler() : + currentThreadControlBlock_{}, + runnableList_{}, + suspendedList_{}, + softwareTimerSupervisor_{}, + contextSwitchCount_{}, + tickCount_{} + { + + } + + /** + * \brief Adds new ThreadControlBlock to scheduler. + * + * ThreadControlBlock's state is changed to "runnable". + * + * \param [in] threadControlBlock is a reference to added ThreadControlBlock object + * + * \return 0 on success, error code otherwise: + * - EINVAL - thread is already started; + * - error codes returned by Scheduler::addInternal(); + */ + + int add(ThreadControlBlock& threadControlBlock); + + /** + * \brief Blocks current thread, transferring it to provided container. + * + * \param [in] container is a reference to destination container to which the thread will be transferred + * \param [in] state is the new state of thread that will be blocked + * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in + * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed) + * + * \return 0 on success, error code otherwise: + * - EINTR - thread was unblocked with ThreadControlBlock::UnblockReason::signal; + * - ETIMEDOUT - thread was unblocked with ThreadControlBlock::UnblockReason::timeout; + */ + + int block(ThreadList& container, ThreadState state, const ThreadControlBlock::UnblockFunctor* unblockFunctor = {}); + + /** + * \brief Blocks thread, transferring it to provided container. + * + * The thread must be on "runnable" list - trying to block thread in other state is an error. + * + * \param [in] container is a reference to destination container to which the thread will be transferred + * \param [in] iterator is the iterator to the thread that will be blocked + * \param [in] state is the new state of thread that will be blocked + * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in + * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed) + * + * \return 0 on success, error code otherwise: + * - EINTR - thread was unblocked with ThreadControlBlock::UnblockReason::signal (possible only when blocking + * current thread); + * - EINVAL - provided thread is not on "runnable" list; + * - ETIMEDOUT - thread was unblocked with ThreadControlBlock::UnblockReason::timeout (possible only when blocking + * current thread); + */ + + int block(ThreadList& container, ThreadList::iterator iterator, ThreadState state, + const ThreadControlBlock::UnblockFunctor* unblockFunctor = {}); + + /** + * \brief Blocks current thread with timeout, transferring it to provided container. + * + * \param [in] container is a reference to destination container to which the thread will be transferred + * \param [in] state is the new state of thread that will be blocked + * \param [in] timePoint is the time point at which the thread will be unblocked (if not already unblocked) + * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in + * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed) + * + * \return 0 on success, error code otherwise: + * - EINTR - thread was unblocked with ThreadControlBlock::UnblockReason::signal; + * - ETIMEDOUT - thread was unblocked because timePoint was reached; + */ + + int blockUntil(ThreadList& container, ThreadState state, TickClock::time_point timePoint, + const ThreadControlBlock::UnblockFunctor* unblockFunctor = {}); + + /** + * \return number of context switches + */ + + uint64_t getContextSwitchCount() const; + + /** + * \return reference to currently active ThreadControlBlock + */ + + ThreadControlBlock& getCurrentThreadControlBlock() const + { + return *currentThreadControlBlock_; + } + + /** + * \return reference to internal SoftwareTimerSupervisor object + */ + + SoftwareTimerSupervisor& getSoftwareTimerSupervisor() + { + return softwareTimerSupervisor_; + } + + /** + * \return const reference to internal SoftwareTimerSupervisor object + */ + + const SoftwareTimerSupervisor& getSoftwareTimerSupervisor() const + { + return softwareTimerSupervisor_; + } + + /** + * \return current value of tick count + */ + + uint64_t getTickCount() const; + + /** + * \brief Scheduler's initialization + * + * \attention This must be called after constructor, before enabling any scheduling. Priority of main thread must + * be higher than priority of idle thread + * + * \param [in] mainThread is a reference to main thread + * + * \return 0 on success, error code otherwise: + * - error codes returned by Scheduler::addInternal(); + */ + + int initialize(MainThread& mainThread); + + /** + * \brief Requests context switch if it is needed. + * + * \attention This function must be called with interrupt masking enabled. + */ + + void maybeRequestContextSwitch() const; + + /** + * \brief Removes current thread from Scheduler's control. + * + * Thread's state is changed to "terminated". + * + * \note This function must be called with masked interrupts. + * + * \note This function can be used only after thread's function returns an all cleanup is done. + * + * \return 0 on success, error code otherwise: + * - EINVAL - provided thread is not on "runnable" list and cannot be removed/terminated; + */ + + int remove(); + + /** + * \brief Resumes suspended thread. + * + * The thread must be on the "suspended" list - trying to resume thread that is not suspended is an error. + * + * \param [in] iterator is the iterator to the thread that will be resumed + * + * \return 0 on success, error code otherwise: + * - EINVAL - provided thread is not on "suspended" list; + */ + + int resume(ThreadList::iterator iterator); + + /** + * \brief Suspends current thread. + * + * \return 0 on success, error code otherwise: + * - EINTR - thread was unblocked with ThreadControlBlock::UnblockReason::signal; + */ + + int suspend(); + + /** + * \brief Suspends thread. + * + * The thread must be on "runnable" list - trying to suspend thread in other state is an error. + * + * \param [in] iterator is the iterator to the thread that will be suspended + * + * \return 0 on success, error code otherwise: + * - EINTR - thread was unblocked with ThreadControlBlock::UnblockReason::signal; + * - EINVAL - provided thread is not on "runnable" list; + */ + + int suspend(ThreadList::iterator iterator); + + /** + * \brief Called by architecture-specific code to do final context switch. + * + * Current task is suspended and the next available task is started. + * + * \param [in] stackPointer is the current value of current thread's stack pointer + * + * \return new thread's stack pointer + */ + + void* switchContext(void* stackPointer); + + /** + * \brief Handler of "tick" interrupt. + * + * \note this must not be called by user code + * + * \return true if context switch is required, false otherwise + */ + + bool tickInterruptHandler(); + + /** + * \brief Unblocks provided thread, transferring it from it's current container to "runnable" container. + * + * Current container of the thread is obtained with ThreadControlBlock::getList(). + * + * \param [in] iterator is the iterator which points to unblocked thread + * \param [in] unblockReason is the reason of unblocking of the thread, default - + * ThreadControlBlock::UnblockReason::unblockRequest + */ + + void unblock(ThreadList::iterator iterator, + ThreadControlBlock::UnblockReason unblockReason = ThreadControlBlock::UnblockReason::unblockRequest); + + /** + * \brief Yields time slot of the scheduler to next thread. + */ + + void yield(); + +private: + + /** + * \brief Adds new ThreadControlBlock to scheduler. + * + * Internal version - without interrupt masking and call to Scheduler::maybeRequestContextSwitch() + * + * \param [in] threadControlBlock is a reference to added ThreadControlBlock object + * + * \return 0 on success, error code otherwise: + * - error codes returned by ThreadControlBlock::addHook(); + */ + + int addInternal(ThreadControlBlock& threadControlBlock); + + /** + * \brief Blocks thread, transferring it to provided container. + * + * Internal version - without interrupt masking and forced context switch. + * + * \param [in] container is a reference to destination container to which the thread will be transferred + * \param [in] iterator is the iterator to the thread that will be blocked + * \param [in] state is the new state of thread that will be blocked + * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in + * ThreadControlBlock::unblockHook() + * + * \return 0 on success, error code otherwise: + * - EINVAL - provided thread is not on "runnable" list; + */ + + int blockInternal(ThreadList& container, ThreadList::iterator iterator, ThreadState state, + const ThreadControlBlock::UnblockFunctor* unblockFunctor); + + /** + * \brief Tests whether context switch is required or not. + * + * Context switch is required in following situations: + * - current thread is no longer on "runnable" list, + * - current thread is no longer on the beginning of the "runnable" list (because higher-priority thread is + * available or current thread was "rotated" due to round-robin scheduling policy). + * + * \return true if context switch is required + */ + + bool isContextSwitchRequired() const; + + /** + * \brief Unblocks provided thread, transferring it from it's current container to "runnable" container. + * + * Current container of the thread is obtained with ThreadControlBlock::getList(). Round-robin quantum of thread is + * reset. + * + * \note Internal version - without interrupt masking and yield() + * + * \param [in] iterator is the iterator which points to unblocked thread + * \param [in] unblockReason is the reason of unblocking of the thread + */ + + void unblockInternal(ThreadList::iterator iterator, ThreadControlBlock::UnblockReason unblockReason); + + /// iterator to the currently active ThreadControlBlock + ThreadList::iterator currentThreadControlBlock_; + + /// list of ThreadControlBlock elements in "runnable" state, sorted by priority in descending order + ThreadList runnableList_; + + /// list of ThreadControlBlock elements in "suspended" state, sorted by priority in descending order + ThreadList suspendedList_; + + /// internal SoftwareTimerSupervisor object + SoftwareTimerSupervisor softwareTimerSupervisor_; + + /// number of context switches + uint64_t contextSwitchCount_; + + /// tick count + uint64_t tickCount_; +}; + +} // namespace internal + +} // namespace distortos + +#endif // INCLUDE_DISTORTOS_INTERNAL_SCHEDULER_SCHEDULER_HPP_ |