/*************************************************************************** * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 * * by Terraneo Federico * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * As a special exception, if other files instantiate templates or use * * macros or inline functions from this file, or you compile this file * * and link it with other works to produce a work based on this file, * * this file does not by itself cause the resulting work to be covered * * by the GNU General Public License. However the source code for this * * file must still be made available in accordance with the GNU General * * Public License. This exception does not invalidate any other reasons * * why a work based on this file might be covered by the GNU General * * Public License. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see * ***************************************************************************/ //Miosix kernel #ifndef SYNC_H #define SYNC_H #include "kernel.h" #include namespace miosix { /** * \addtogroup Sync * \{ */ /** * Fast mutex without support for priority inheritance */ class FastMutex { public: /** * Mutex options, passed to the constructor to set additional options.
* The DEFAULT option indicates the default Mutex type. */ enum Options { DEFAULT, ///< Default mutex RECURSIVE ///< Mutex is recursive }; /** * Constructor, initializes the mutex. */ FastMutex(Options opt=DEFAULT) { if(opt==RECURSIVE) { pthread_mutexattr_t temp; pthread_mutexattr_init(&temp); pthread_mutexattr_settype(&temp,PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&impl,&temp); pthread_mutexattr_destroy(&temp); } else pthread_mutex_init(&impl,NULL); } /** * Locks the critical section. If the critical section is already locked, * the thread will be queued in a wait list. */ void lock() { pthread_mutex_lock(&impl); } /** * Acquires the lock only if the critical section is not already locked by * other threads. Attempting to lock again a recursive mutex will fail, and * the mutex' lock count will not be incremented. * \return true if the lock was acquired */ bool tryLock() { return pthread_mutex_trylock(&impl)==0; } /** * Unlocks the critical section. */ void unlock() { pthread_mutex_unlock(&impl); } /** * \internal * \return the FastMutex implementation defined mutex type */ pthread_mutex_t *get() { return &impl; } /** * Destructor */ ~FastMutex() { pthread_mutex_destroy(&impl); } private: FastMutex(const FastMutex&); FastMutex& operator= (const FastMutex&); pthread_mutex_t impl; }; //Forward declaration class ConditionVariable; /** * A mutex class with support for priority inheritance. If a thread tries to * enter a critical section which is not free, it will be put to sleep and * added to a queue of sleeping threads, ordered by priority. The thread that * is into the critical section inherits the highest priority among the threads * that are waiting if it is higher than its original priority.
* This mutex is meant to be a static or global class. Dynamically creating a * mutex with new or on the stack must be done with care, to avoid deleting a * locked mutex, and to avoid situations where a thread tries to lock a * deleted mutex.
*/ class Mutex { public: /** * Mutex options, passed to the constructor to set additional options.
* The DEFAULT option indicates the default Mutex type. */ enum Options { DEFAULT, ///< Default mutex RECURSIVE ///< Mutex is recursive }; /** * Constructor, initializes the mutex. */ Mutex(Options opt=DEFAULT); /** * Locks the critical section. If the critical section is already locked, * the thread will be queued in a wait list. */ void lock() { PauseKernelLock dLock; PKlock(dLock); } /** * Acquires the lock only if the critical section is not already locked by * other threads. Attempting to lock again a recursive mutex will fail, and * the mutex' lock count will not be incremented. * \return true if the lock was acquired */ bool tryLock() { PauseKernelLock dLock; return PKtryLock(dLock); } /** * Unlocks the critical section. */ void unlock() { #ifdef SCHED_TYPE_EDF bool hppw; { PauseKernelLock dLock; hppw=PKunlock(dLock); } if(hppw) Thread::yield();//The other thread might have a closer deadline #else { PauseKernelLock dLock; PKunlock(dLock); } #endif //SCHED_TYPE_EDF } private: //Unwanted methods Mutex(const Mutex& s);///< No public copy constructor Mutex& operator = (const Mutex& s);///< No publc operator = //Uses default destructor /** * Lock mutex, can be called only with kernel paused one level deep * (pauseKernel calls can be nested). If another thread holds the mutex, * this call will restart the kernel and wait (that's why the kernel must * be paused one level deep).
* \param dLock the PauseKernelLock instance that paused the kernel. */ void PKlock(PauseKernelLock& dLock); /** * Lock mutex to a given depth, can be called only with kernel paused one * level deep (pauseKernel calls can be nested). If another thread holds the * mutex, this call will restart the kernel and wait (that's why the kernel * must be paused one level deep).
* If the mutex is not recursive the mutex is locked only one level deep * regardless of the depth value. * \param dLock the PauseKernelLock instance that paused the kernel. * \param depth recursive depth at which the mutex will be locked. Zero * means the mutex is locked one level deep (as if lock() was called once), * one means two levels deep, etc. */ void PKlockToDepth(PauseKernelLock& dLock, unsigned int depth); /** * Acquires the lock only if the critical section is not already locked by * other threads. Attempting to lock again a recursive mutex will fail, and * the mutex' lock count will not be incremented.
* Can be called only with kernel paused one level deep. * (pauseKernel calls can be nested). * \param dLock the PauseKernelLock instance that paused the kernel. * \return true if the lock was acquired */ bool PKtryLock(PauseKernelLock& dLock); /** * Unlock mutex, can be called only with kernel paused one level deep * (pauseKernel calls can be nested).
* \param dLock the PauseKernelLock instance that paused the kernel. * \return true if a higher priority thread was woken */ bool PKunlock(PauseKernelLock& dLock); /** * Unlock mutex all levels of a recursive mutex, can be called only with * kernel paused one level deep (pauseKernel calls can be nested).
* \param dLock the PauseKernelLock instance that paused the kernel. * \return the mutex recursive depth (how many times it was locked by the * owner). Zero means the mutex is locked one level deep (lock() was called * once), one means two levels deep, etc. */ unsigned int PKunlockAllDepthLevels(PauseKernelLock& dLock); /// Thread currently inside critical section, if NULL the critical section /// is free Thread *owner; /// If this mutex is locked, it is added to a list of mutexes held by the /// thread that owns this mutex. This field is necessary to make the list. Mutex *next; /// Waiting thread are stored in this min-heap, sorted by priority std::vector waiting; /// Used to hold nesting depth for recursive mutexes, -1 if not recursive int recursiveDepth; //Friends friend class ConditionVariable; friend class Thread; }; /** * Very simple RAII style class to lock a mutex in an exception-safe way. * Mutex is acquired by the constructor and released by the destructor. */ template class Lock { public: /** * Constructor: locks the mutex * \param m mutex to lock */ explicit Lock(T& m): mutex(m) { mutex.lock(); } /** * Destructor: unlocks the mutex */ ~Lock() { mutex.unlock(); } /** * \return the locked mutex */ T& get() { return mutex; } private: //Unwanted methods Lock(const Lock& l);///< No public copy constructor Lock& operator = (const Lock& l);///< No publc operator = T& mutex;///< Reference to locked mutex }; /** * This class allows to temporarily re unlock a mutex in a scope where * it is locked
* Example: * \code * Mutex m; * * //Mutex unlocked * { * Lock dLock(m); * * //Now mutex locked * * { * Unlock eLock(dLock); * * //Now mutex back unlocked * } * * //Now mutex again locked * } * //Finally mutex unlocked * \endcode */ template class Unlock { public: /** * Constructor, unlock mutex. * \param l the Lock that locked the mutex. */ explicit Unlock(Lock& l): mutex(l.get()) { mutex.unlock(); } /** * Constructor, unlock mutex. * \param m a locked mutex. */ Unlock(T& m): mutex(m) { mutex.unlock(); } /** * Destructor. * Disable back interrupts. */ ~Unlock() { mutex.lock(); } /** * \return the unlocked mutex */ T& get() { return mutex; } private: //Unwanted methods Unlock(const Unlock& l); Unlock& operator= (const Unlock& l); T& mutex;///< Reference to locked mutex }; /** * A condition variable class for thread synchronization, available from * Miosix 1.53.
* One or more threads can wait on the condition variable, and the signal() * and broadcast() allow to wake ne or all the waiting threads.
* This class is meant to be a static or global class. Dynamically creating a * ConditionVariable with new or on the stack must be done with care, to avoid * deleting a ConditionVariable while some threads are waiting, and to avoid * situations where a thread tries to wait on a deleted ConditionVariable.
*/ class ConditionVariable { public: /** * Constructor, initializes the ConditionVariable. */ ConditionVariable(); /** * Unlock the mutex and wait. * If more threads call wait() they must do so specifying the same mutex, * otherwise the behaviour is undefined. * \param l A Lock instance that locked a Mutex */ template void wait(Lock& l) { wait(l.get()); } /** * Unlock the Mutex and wait. * If more threads call wait() they must do so specifying the same mutex, * otherwise the behaviour is undefined. * \param m a locked Mutex */ void wait(Mutex& m); /** * Unlock the FastMutex and wait. * If more threads call wait() they must do so specifying the same mutex, * otherwise the behaviour is undefined. * \param m a locked Mutex */ void wait(FastMutex& m); /** * Wakeup one waiting thread. * Currently implemented policy is fifo. */ void signal(); /** * Wakeup all waiting threads. */ void broadcast(); private: //Unwanted methods ConditionVariable(const ConditionVariable& ); ConditionVariable& operator= (const ConditionVariable& ); /** * \internal * \struct WaitingData * This struct is used to make a list of waiting threads. */ struct WaitingData { Thread *p;///<\internal Thread that is waiting WaitingData *next;///<\internal Next thread in the list }; WaitingData *first;///Its resolution equals * the kernel tick.
Maximum interval is 2^31-1 ticks. */ class Timer { public: /** * Constructor. Timer is initialized in stopped status. */ Timer(); /** * Start the timer */ void start(); /** * Stop the timer. After stop, Timer can be started and stopped again to * count non-contiguous timer intervals. */ void stop(); /** * \return true if timer is running */ bool isRunning() const; /** * get the interval, in kernel ticks. * \return the number of tick between start and stop. Returns -1 if the * timer was never started, if interval is called after start but before * stop, or if it overflowed. * * To read the vaue of a timer without stopping it, you can use its copy * constructor to create another timer, and stop it while the first timer * keeps running. */ int interval() const; /** * Clear the timer and set it to not running state. */ void clear(); //Using default copy constructor, operator = and destructor private: //Timer data bool first;///< True if start has never been called bool running;///< True if timer is running long long start_tick;///< The kernel tick when start was called. long long tick_count;///< The tick count }; /** * \} */ } //namespace miosix #endif //SYNC_H