Dependencies:   mbed

Revision:
0:331db0b44b67
diff -r 000000000000 -r 331db0b44b67 scmRTOS/Common/OS_Services.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scmRTOS/Common/OS_Services.cpp	Tue Sep 21 19:48:05 2010 +0000
@@ -0,0 +1,298 @@
+//******************************************************************************
+//*
+//*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
+//*
+//*     NICKNAME:  scmRTOS
+//*
+//*     PURPOSE:  OS Services Source
+//*
+//*     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.
+//*     =================================================================
+//*
+//******************************************************************************
+
+#include "scmRTOS.h"
+
+using namespace OS;
+
+//------------------------------------------------------------------------------
+//
+//
+//      TEventFlag
+//
+//
+bool OS::TEventFlag::Wait(TTimeout timeout)
+{
+    TCritSect cs;
+
+    if(Value)                                           // if flag already signaled
+    {
+        Value = efOff;                                  // clear flag
+        return true;
+    }
+    else
+    {
+        TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
+        p->Timeout = timeout;
+        TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+
+        SetPrioTag(ProcessMap, PrioTag);                // put current process to the wait map
+        ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);    // remove current process from the ready map
+
+        Kernel.Scheduler();
+
+        p->Timeout = 0;
+
+        if( !(ProcessMap & PrioTag) )                   // if waked up by signal() or signal_ISR()
+            return true;
+
+        ClrPrioTag(ProcessMap, PrioTag);                // otherwise waked up by timeout or by
+        return false;                                   // OS::ForceWakeUpProcess(), remove process from the wait map
+    }
+}
+//------------------------------------------------------------------------------
+void OS::TEventFlag::Signal()
+{
+    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.
+                                                            // Used to check that process waked up by signal() or signalISR()
+                                                            // and not by timeout or OS::ForceWakeUpProcess()
+            Kernel.Scheduler();
+            return;
+        }
+    }
+    Value = efOn;
+}
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+//
+//
+//      TMutex
+//
+//
+void OS::TMutex::Lock()
+{
+    TCritSect cs;
+
+    TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+    while(ValueTag)
+    {
+        SetPrioTag(ProcessMap, PrioTag);             // mutex already locked by another process, put current process to the wait map
+        ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
+
+        Kernel.Scheduler();
+    }
+    ValueTag = PrioTag;                              // mutex has been successfully locked
+}
+//------------------------------------------------------------------------------
+void OS::TMutex::Unlock()
+{
+    TCritSect cs;
+
+    TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+    if(ValueTag != PrioTag) return;                  // the only process that had locked mutex can unlock the mutex
+    ValueTag = 0;
+    if(ProcessMap)
+    {
+        byte pr = GetHighPriority(ProcessMap);
+        PrioTag = GetPrioTag(pr);
+        ClrPrioTag(ProcessMap, PrioTag);             // remove next ready process from the wait map
+        SetPrioTag(Kernel.ReadyProcessMap, PrioTag); // place next process to the ready map
+        Kernel.Scheduler();
+    }
+}
+//------------------------------------------------------------------------------
+void OS::TMutex::UnlockISR()
+{
+    TCritSect cs;
+
+    ValueTag = 0;
+    if(ProcessMap)
+    {
+        byte pr = GetHighPriority(ProcessMap);
+        TProcessMap PrioTag = GetPrioTag(pr);
+        ClrPrioTag(ProcessMap, PrioTag);             // remove next ready process from the wait map
+        SetPrioTag(Kernel.ReadyProcessMap, PrioTag); // place next process to the ready map
+    }
+}
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+//
+//
+//      TChannel
+//
+//
+void OS::TChannel::CheckWaiters(TProcessMap& pm)
+{
+    if(pm)
+    {
+        byte pr = GetHighPriority(pm);
+        TProcessMap PrioTag = GetPrioTag(pr);
+        ClrPrioTag(pm, PrioTag);                     // remove next ready process from the wait map
+        SetPrioTag(Kernel.ReadyProcessMap, PrioTag); // place next process to the ready map
+        Kernel.Scheduler();
+    }
+}
+//------------------------------------------------------------------------------
+void OS::TChannel::Push(byte x)
+{
+    TCritSect cs;
+
+    while (!Cbuf.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();                          // wait until waked-up by Pop() or Read()
+    }
+
+    Cbuf.put(x);
+    CheckWaiters(ConsumersProcessMap);
+}
+//------------------------------------------------------------------------------
+byte OS::TChannel::Pop()
+{
+    TCritSect cs;
+    byte x;
+
+    while(!Cbuf.get_count())
+    {
+        TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+        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();                          // wait until waked up by Push() or Write()
+    }
+    x = Cbuf.get();
+    CheckWaiters(ProducersProcessMap);
+    return x;
+}
+//------------------------------------------------------------------------------
+void OS::TChannel::Write(const byte* data, const byte count)
+{
+    TCritSect cs;
+
+    while(Cbuf.get_free_size() < count)
+    {
+        TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+        SetPrioTag(ProducersProcessMap, PrioTag);    // channel has not enough space, put current process to the wait map
+        ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
+        Kernel.Scheduler();                          // wait until waked up by Read() or Pop()
+    }
+
+    Cbuf.write(data, count);
+    CheckWaiters(ConsumersProcessMap);
+}
+//------------------------------------------------------------------------------
+void OS::TChannel::Read(byte* const data, const byte count)
+{
+    TCritSect cs;
+
+    while(Cbuf.get_count() < count)
+    {
+        TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+        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();                          // wait until waked up by Write() or Push()
+    }
+
+    Cbuf.read(data, count);
+    CheckWaiters(ProducersProcessMap);
+}
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+//
+//              OS::message template
+//
+//          Function-members implementation
+//
+//
+//------------------------------------------------------------------------------
+bool OS::TBaseMessage::wait(TTimeout timeout)
+{
+    TCritSect cs;
+
+    if(NonEmpty)                                                  // message alredy send
+    {
+        NonEmpty = false;
+        return true;
+    }
+    else
+    {
+        TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
+        p->Timeout = timeout;
+        TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
+
+        SetPrioTag(ProcessMap, PrioTag);                          // put current process to the wait map
+        ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);              // remove current process from the ready map
+        Kernel.Scheduler();                                       // wait until wake up
+
+        p->Timeout = 0;
+        if( !(ProcessMap & PrioTag) )                             // if waked up by send() or sendISR()
+            return true;
+
+        ClrPrioTag(ProcessMap, PrioTag);                          // otherwise waked up by timeout or by
+            return false;                                         // OS::ForceWakeUpProcess(), remove process from wait map
+    }
+}
+//------------------------------------------------------------------------------
+void OS::TBaseMessage::send()
+{
+    TCritSect cs;
+
+    if(ProcessMap)
+    {
+        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.
+            Kernel.Scheduler();
+            return;
+        }
+    }
+
+    NonEmpty = true;
+}
+//------------------------------------------------------------------------------
+