Dependencies:   mbed

Revision:
0:331db0b44b67
diff -r 000000000000 -r 331db0b44b67 scmRTOS/Common/OS_Services.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scmRTOS/Common/OS_Services.h	Tue Sep 21 19:48:05 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