chokchai Hantanong
/
RtosTest
LED Fork
Fork of RtosTest by
Diff: scmRTOS/Common/OS_Services.cpp
- Revision:
- 0:331db0b44b67
--- /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; +} +//------------------------------------------------------------------------------ +