Diff: Common/OS_Services.h
- Revision:
- 0:d7810ff946c1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Common/OS_Services.h Thu Nov 11 09:47:38 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