Quick and dirty port of scmRTOS demo to mbed 1768. scmRTOS is a small RTOS written using C++. Offers (static) processes, critical sections, mutexes, messages, channels.
Diff: scmRTOS/Common/OS_Services.h
- Revision:
- 0:a405220cf420
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scmRTOS/Common/OS_Services.h Thu Sep 09 21:19:01 2010 +0000 @@ -0,0 +1,467 @@ +//****************************************************************************** +//* +//* FULLNAME: Single-Chip Microcontroller Real-Time Operating System +//* +//* NICKNAME: scmRTOS +//* +//* PURPOSE: OS Services Header. Declarations And Definitions +//* +//* Version: 3.10 +//* +//* $Revision: 256 $ +//* $Date:: 2010-01-22 #$ +//* +//* Copyright (c) 2003-2010, Harry E. Zhurov +//* +//* Permission is hereby granted, free of charge, to any person +//* obtaining a copy of this software and associated documentation +//* files (the "Software"), to deal in the Software without restriction, +//* including without limitation the rights to use, copy, modify, merge, +//* publish, distribute, sublicense, and/or sell copies of the Software, +//* and to permit persons to whom the Software is furnished to do so, +//* subject to the following conditions: +//* +//* The above copyright notice and this permission notice shall be included +//* in all copies or substantial portions of the Software. +//* +//* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +//* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +//* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +//* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +//* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +//* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +//* THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//* +//* ================================================================= +//* See http://scmrtos.sourceforge.net for documentation, latest +//* information, license and contact details. +//* ================================================================= +//* +//****************************************************************************** + +#ifndef OS_SERVICES_H +#define OS_SERVICES_H + +namespace OS +{ + //-------------------------------------------------------------------------- + // + // NAME : Mutex + // + /// Binary semaphore for support of mutual exclusion + // + // DESCRIPTION: + // + // + class TMutex + { + public: + INLINE TMutex() : ProcessMap(0), ValueTag(0) { } + void Lock(); + void Unlock(); + void UnlockISR(); + + INLINE bool LockSoftly() { TCritSect cs; if(ValueTag) return false; else Lock(); return true; } + INLINE bool IsLocked() const { TCritSect cs; if(ValueTag) return true; else return false; } + + private: + TProcessMap ProcessMap; + TProcessMap ValueTag; + + }; + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // + /// Event Flag + /// + /// Intended for processes synchronization and + /// event notification one (or more) process by another + // + // DESCRIPTION: + // + // + class TEventFlag + { + public: + enum TValue { efOn = 1, efOff= 0 }; // prefix 'ef' means: "Event Flag" + + public: + INLINE TEventFlag(TValue init_val = efOff) : ProcessMap(0), Value(init_val) { } + + bool Wait(TTimeout timeout = 0); + void Signal(); + INLINE void Clear() { TCritSect cs; Value = efOff; } + INLINE inline void SignalISR(); + INLINE bool IsSignaled() { TCritSect cs; if(Value == efOn) return true; else return false; } + + private: + TProcessMap ProcessMap; + TValue Value; + }; + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // + /// TChannel + /// + /// Byte-wide data channel for transferring "raw" data + // + // DESCRIPTION: + // + // + class TChannel + { + public: + INLINE TChannel(byte* buf, byte size) : Cbuf(buf, size) { } + void Push(byte x); + byte Pop(); + void Write(const byte* data, const byte count); + void Read(byte* const data, const byte count); + + INLINE byte GetCount() const { TCritSect cs; return Cbuf.get_count(); } + + private: + TProcessMap ProducersProcessMap; + TProcessMap ConsumersProcessMap; + usr::TCbuf Cbuf; + + private: + void CheckWaiters(TProcessMap& pm); + }; + //-------------------------------------------------------------------------- + + + //-------------------------------------------------------------------------- + // + // NAME : channel + // + // PURPOSE : Data channel for transferring data + // objects of arbitrary type + // + // DESCRIPTION: + // + // + template<typename T, word Size, typename S = byte> + /// channel + /// + /// Data channel for transferring data objects of arbitrary type + class channel + { + public: + INLINE channel() : ProducersProcessMap(0) + , ConsumersProcessMap(0) + , pool() + { + } + + //---------------------------------------------------------------- + // + // Data transfer functions + // + void write(const T* data, const S cnt); + bool read (T* const data, const S cnt, TTimeout timeout = 0); + + void push (const T& item); + void push_front(const T& item); + + bool pop (T& item, TTimeout timeout = 0); + bool pop_back(T& item, TTimeout timeout = 0); + + + //---------------------------------------------------------------- + // + // Service functions + // + INLINE S get_count() const { TCritSect cs; return pool.get_count(); } + INLINE S get_free_size() const { TCritSect cs; return pool.get_free_size(); } + void flush(); + //const T& operator[](const S index) { TCritSect cs; return pool[index]; } + + + private: + TProcessMap ProducersProcessMap; + TProcessMap ConsumersProcessMap; + usr::ring_buffer<T, Size, S> pool; + + private: + void CheckWaiters(TProcessMap& pm); + }; + + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // + /// message + /// + /// Template for messages + // + // DESCRIPTION: + // + // + class TBaseMessage + { + public: + INLINE TBaseMessage() : ProcessMap(0), NonEmpty(false) { } + + bool wait (TTimeout timeout = 0); + void send(); + INLINE inline void sendISR(); + INLINE bool is_non_empty() const { TCritSect cs; return NonEmpty; } + INLINE void reset () { TCritSect cs; NonEmpty = false; } + + private: + TProcessMap ProcessMap; + bool NonEmpty; + }; + //-------------------------------------------------------------------------- + template<typename T> + class message : public TBaseMessage + { + public: + INLINE message() : TBaseMessage() { } + INLINE const T& operator=(const T& msg) { TCritSect cs; Msg = msg; return Msg; } + INLINE operator T() const { TCritSect cs; return Msg; } + + private: + T Msg; + }; + //-------------------------------------------------------------------------- +} +//------------------------------------------------------------------------------ +// +// Function-members implementation +// +//------------------------------------------------------------------------------ +void OS::TEventFlag::SignalISR() +{ + TCritSect cs; + if(ProcessMap) // if any process waits for event + { + TProcessMap Timeouted = Kernel.ReadyProcessMap; // Process has its tag set in ReadyProcessMap if timeout + // expired, or it was waked up by OS::ForceWakeUpProcess() + if( ProcessMap & ~Timeouted ) // if any process has to be waked up + { + SetPrioTag(Kernel.ReadyProcessMap, ProcessMap); // place all waiting processes to the ready map + ClrPrioTag(ProcessMap, ~Timeouted); // remove all non-timeouted processes from the waiting map. + return; + } + } + Value = efOn; +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +void OS::channel<T, Size, S>::CheckWaiters(TProcessMap& pm) +{ + if(pm) + { + TProcessMap Timeouted = Kernel.ReadyProcessMap; + + SetPrioTag(Kernel.ReadyProcessMap, pm); // place all waiting processes to the ready map + ClrPrioTag(pm, ~Timeouted); // remove waiting processes from the wait map + Kernel.Scheduler(); + } +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +void OS::channel<T, Size, S>::push(const T& item) +{ + TCritSect cs; + + while(!pool.get_free_size()) + { + TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority); + SetPrioTag(ProducersProcessMap, PrioTag); // channel is full, put current process to the wait map + ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map + Kernel.Scheduler(); + } + + pool.push_back(item); + CheckWaiters(ConsumersProcessMap); +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +void OS::channel<T, Size, S>::push_front(const T& item) +{ + TCritSect cs; + + while(!pool.get_free_size()) + { + TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority); + SetPrioTag(ProducersProcessMap, PrioTag); // channel is full, put current process to the wait map + ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map + Kernel.Scheduler(); + } + + pool.push_front(item); + CheckWaiters(ConsumersProcessMap); +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +bool OS::channel<T, Size, S>::pop(T& item, TTimeout timeout) +{ + TCritSect cs; + + if(pool.get_count()) + { + item = pool.pop(); + CheckWaiters(ProducersProcessMap); + return true; + } + else + { + TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority]; + p->Timeout = timeout; + + TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority); + for(;;) + { + SetPrioTag(ConsumersProcessMap, PrioTag); // channel is empty, put current process to the wait map + ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map + Kernel.Scheduler(); + + if(pool.get_count()) + { + p->Timeout = 0; + item = pool.pop(); + CheckWaiters(ProducersProcessMap); + return true; + } + + if(ConsumersProcessMap & PrioTag) // waked up by timer when timeout expired + { // or by OS::ForceWakeUpProcess() + + p->Timeout = 0; // non-zero if waked up by ForceWakeUpProcess() + ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map + return false; + } + } + } +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +bool OS::channel<T, Size, S>::pop_back(T& item, TTimeout timeout) +{ + TCritSect cs; + + if(pool.get_count()) + { + item = pool.pop_back(); + CheckWaiters(ProducersProcessMap); + return true; + } + else + { + TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority]; + p->Timeout = timeout; + + TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority); + for(;;) + { + SetPrioTag(ConsumersProcessMap, PrioTag); // channel is empty, put current process to the wait map + ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map + Kernel.Scheduler(); + + if(pool.get_count()) + { + p->Timeout = 0; + item = pool.pop_back(); + CheckWaiters(ProducersProcessMap); + return true; + } + + if(ConsumersProcessMap & PrioTag) // waked up by timer when timeout expired + { // or by OS::ForceWakeUpProcess() + + p->Timeout = 0; // non-zero if waked up by ForceWakeUpProcess() + ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map + return false; + } + } + } +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +void OS::channel<T, Size, S>::flush() +{ + TCritSect cs; + pool.flush(); + CheckWaiters(ProducersProcessMap); +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +void OS::channel<T, Size, S>::write(const T* data, const S count) +{ + TCritSect cs; + + while(pool.get_free_size() < count) + { + TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority); + SetPrioTag(ProducersProcessMap, PrioTag); // channel does not have enough space, put current process to the wait map + ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map + Kernel.Scheduler(); + } + + pool.write(data, count); + CheckWaiters(ConsumersProcessMap); +} +//------------------------------------------------------------------------------ +template<typename T, word Size, typename S> +bool OS::channel<T, Size, S>::read(T* const data, const S count, TTimeout timeout) +{ + TCritSect cs; + + TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority]; + p->Timeout = timeout; + + TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority); + while(pool.get_count() < count) + { + SetPrioTag(ConsumersProcessMap, PrioTag); // channel doesn't contain enough data, put current process to the wait map + ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map + Kernel.Scheduler(); + + if(ConsumersProcessMap & PrioTag) // waked up by timer when timeout expired + { // or by OS::ForceWakeUpProcess() + + p->Timeout = 0; // non-zero if waked up by ForceWakeUpProcess() + ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map + return false; + } + } + + p->Timeout = 0; + pool.read(data, count); + CheckWaiters(ProducersProcessMap); + + return true; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// +// OS::message template +// +// Function-members implementation +// +// +//------------------------------------------------------------------------------ +void OS::TBaseMessage::sendISR() +{ + TCritSect cs; + + if(ProcessMap) + { + TProcessMap Timeouted = OS::Kernel.ReadyProcessMap; // Process has it's tag set in ReadyProcessMap if timeout + // expired, or it was waked up by OS::ForceWakeUpProcess() + if( ProcessMap & ~Timeouted ) // if any process has to be waked up + { + SetPrioTag(Kernel.ReadyProcessMap, ProcessMap); // place all waiting processes to the ready map + ClrPrioTag(ProcessMap, ~Timeouted); // remove all non-timeouted processes from the waiting map. + return; + } + } + NonEmpty = true; +} +//------------------------------------------------------------------------------ +#endif // OS_SERVICES_H