Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OS_Services.cpp Source File

OS_Services.cpp

00001 //******************************************************************************
00002 //*
00003 //*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
00004 //*
00005 //*     NICKNAME:  scmRTOS
00006 //*
00007 //*     PURPOSE:  OS Services Source
00008 //*
00009 //*     Version: 3.10
00010 //*
00011 //*     $Revision: 256 $
00012 //*     $Date:: 2010-01-22 #$
00013 //*
00014 //*     Copyright (c) 2003-2010, Harry E. Zhurov
00015 //*
00016 //*     Permission is hereby granted, free of charge, to any person
00017 //*     obtaining  a copy of this software and associated documentation
00018 //*     files (the "Software"), to deal in the Software without restriction,
00019 //*     including without limitation the rights to use, copy, modify, merge,
00020 //*     publish, distribute, sublicense, and/or sell copies of the Software,
00021 //*     and to permit persons to whom the Software is furnished to do so,
00022 //*     subject to the following conditions:
00023 //*
00024 //*     The above copyright notice and this permission notice shall be included
00025 //*     in all copies or substantial portions of the Software.
00026 //*
00027 //*     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00028 //*     EXPRESS  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00029 //*     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00030 //*     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
00031 //*     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00032 //*     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
00033 //*     THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00034 //*
00035 //*     =================================================================
00036 //*     See http://scmrtos.sourceforge.net for documentation, latest
00037 //*     information, license and contact details.
00038 //*     =================================================================
00039 //*
00040 //******************************************************************************
00041 
00042 #include "scmRTOS.h"
00043 
00044 using namespace OS;
00045 
00046 //------------------------------------------------------------------------------
00047 //
00048 //
00049 //      TEventFlag
00050 //
00051 //
00052 bool OS::TEventFlag::Wait(TTimeout timeout)
00053 {
00054     TCritSect cs;
00055 
00056     if(Value)                                           // if flag already signaled
00057     {
00058         Value = efOff;                                  // clear flag
00059         return true;
00060     }
00061     else
00062     {
00063         TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
00064         p->Timeout = timeout;
00065         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00066 
00067         SetPrioTag(ProcessMap, PrioTag);                // put current process to the wait map
00068         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);    // remove current process from the ready map
00069 
00070         Kernel.Scheduler();
00071 
00072         p->Timeout = 0;
00073 
00074         if( !(ProcessMap & PrioTag) )                   // if waked up by signal() or signal_ISR()
00075             return true;
00076 
00077         ClrPrioTag(ProcessMap, PrioTag);                // otherwise waked up by timeout or by
00078         return false;                                   // OS::ForceWakeUpProcess(), remove process from the wait map
00079     }
00080 }
00081 //------------------------------------------------------------------------------
00082 void OS::TEventFlag::Signal()
00083 {
00084     TCritSect cs;
00085     if(ProcessMap)                                          // if any process waits for event
00086     {
00087         TProcessMap Timeouted = Kernel.ReadyProcessMap;     // Process has its tag set in ReadyProcessMap if timeout expired
00088                                                             // or it was waked up by OS::ForceWakeUpProcess()
00089 
00090         if( ProcessMap & ~Timeouted )                       // if any process has to be waked up
00091         {
00092             SetPrioTag(Kernel.ReadyProcessMap, ProcessMap); // place all waiting processes to the ready map
00093             ClrPrioTag(ProcessMap, ~Timeouted);             // remove all non-timeouted processes from the waiting map.
00094                                                             // Used to check that process waked up by signal() or signalISR()
00095                                                             // and not by timeout or OS::ForceWakeUpProcess()
00096             Kernel.Scheduler();
00097             return;
00098         }
00099     }
00100     Value = efOn;
00101 }
00102 //------------------------------------------------------------------------------
00103 
00104 //------------------------------------------------------------------------------
00105 //
00106 //
00107 //      TMutex
00108 //
00109 //
00110 void OS::TMutex::Lock()
00111 {
00112     TCritSect cs;
00113 
00114     TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00115     while(ValueTag)
00116     {
00117         SetPrioTag(ProcessMap, PrioTag);             // mutex already locked by another process, put current process to the wait map
00118         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
00119 
00120         Kernel.Scheduler();
00121     }
00122     ValueTag = PrioTag;                              // mutex has been successfully locked
00123 }
00124 //------------------------------------------------------------------------------
00125 void OS::TMutex::Unlock()
00126 {
00127     TCritSect cs;
00128 
00129     TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00130     if(ValueTag != PrioTag) return;                  // the only process that had locked mutex can unlock the mutex
00131     ValueTag = 0;
00132     if(ProcessMap)
00133     {
00134         byte pr = GetHighPriority(ProcessMap);
00135         PrioTag = GetPrioTag(pr);
00136         ClrPrioTag(ProcessMap, PrioTag);             // remove next ready process from the wait map
00137         SetPrioTag(Kernel.ReadyProcessMap, PrioTag); // place next process to the ready map
00138         Kernel.Scheduler();
00139     }
00140 }
00141 //------------------------------------------------------------------------------
00142 void OS::TMutex::UnlockISR()
00143 {
00144     TCritSect cs;
00145 
00146     ValueTag = 0;
00147     if(ProcessMap)
00148     {
00149         byte pr = GetHighPriority(ProcessMap);
00150         TProcessMap PrioTag = GetPrioTag(pr);
00151         ClrPrioTag(ProcessMap, PrioTag);             // remove next ready process from the wait map
00152         SetPrioTag(Kernel.ReadyProcessMap, PrioTag); // place next process to the ready map
00153     }
00154 }
00155 //------------------------------------------------------------------------------
00156 
00157 
00158 //------------------------------------------------------------------------------
00159 //
00160 //
00161 //      TChannel
00162 //
00163 //
00164 void OS::TChannel::CheckWaiters(TProcessMap& pm)
00165 {
00166     if(pm)
00167     {
00168         byte pr = GetHighPriority(pm);
00169         TProcessMap PrioTag = GetPrioTag(pr);
00170         ClrPrioTag(pm, PrioTag);                     // remove next ready process from the wait map
00171         SetPrioTag(Kernel.ReadyProcessMap, PrioTag); // place next process to the ready map
00172         Kernel.Scheduler();
00173     }
00174 }
00175 //------------------------------------------------------------------------------
00176 void OS::TChannel::Push(byte x)
00177 {
00178     TCritSect cs;
00179 
00180     while (!Cbuf.get_free_size())
00181     {
00182         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00183         SetPrioTag  (ProducersProcessMap, PrioTag);  // channel is full, put current process to the wait map
00184         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
00185         Kernel.Scheduler();                          // wait until waked-up by Pop() or Read()
00186     }
00187 
00188     Cbuf.put(x);
00189     CheckWaiters(ConsumersProcessMap);
00190 }
00191 //------------------------------------------------------------------------------
00192 byte OS::TChannel::Pop()
00193 {
00194     TCritSect cs;
00195     byte x;
00196 
00197     while(!Cbuf.get_count())
00198     {
00199         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00200         SetPrioTag(ConsumersProcessMap, PrioTag);    // channel is empty, put current process to the wait map
00201         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
00202         Kernel.Scheduler();                          // wait until waked up by Push() or Write()
00203     }
00204     x = Cbuf.get();
00205     CheckWaiters(ProducersProcessMap);
00206     return x;
00207 }
00208 //------------------------------------------------------------------------------
00209 void OS::TChannel::Write(const byte* data, const byte count)
00210 {
00211     TCritSect cs;
00212 
00213     while(Cbuf.get_free_size() < count)
00214     {
00215         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00216         SetPrioTag(ProducersProcessMap, PrioTag);    // channel has not enough space, put current process to the wait map
00217         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
00218         Kernel.Scheduler();                          // wait until waked up by Read() or Pop()
00219     }
00220 
00221     Cbuf.write(data, count);
00222     CheckWaiters(ConsumersProcessMap);
00223 }
00224 //------------------------------------------------------------------------------
00225 void OS::TChannel::Read(byte* const data, const byte count)
00226 {
00227     TCritSect cs;
00228 
00229     while(Cbuf.get_count() < count)
00230     {
00231         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00232         SetPrioTag(ConsumersProcessMap, PrioTag);    // channel doesn't contain enough data, put current process to the wait map
00233         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag); // remove current process from the ready map
00234         Kernel.Scheduler();                          // wait until waked up by Write() or Push()
00235     }
00236 
00237     Cbuf.read(data, count);
00238     CheckWaiters(ProducersProcessMap);
00239 }
00240 //------------------------------------------------------------------------------
00241 
00242 //------------------------------------------------------------------------------
00243 //
00244 //              OS::message template
00245 //
00246 //          Function-members implementation
00247 //
00248 //
00249 //------------------------------------------------------------------------------
00250 bool OS::TBaseMessage::wait(TTimeout timeout)
00251 {
00252     TCritSect cs;
00253 
00254     if(NonEmpty)                                                  // message alredy send
00255     {
00256         NonEmpty = false;
00257         return true;
00258     }
00259     else
00260     {
00261         TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
00262         p->Timeout = timeout;
00263         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00264 
00265         SetPrioTag(ProcessMap, PrioTag);                          // put current process to the wait map
00266         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);              // remove current process from the ready map
00267         Kernel.Scheduler();                                       // wait until wake up
00268 
00269         p->Timeout = 0;
00270         if( !(ProcessMap & PrioTag) )                             // if waked up by send() or sendISR()
00271             return true;
00272 
00273         ClrPrioTag(ProcessMap, PrioTag);                          // otherwise waked up by timeout or by
00274             return false;                                         // OS::ForceWakeUpProcess(), remove process from wait map
00275     }
00276 }
00277 //------------------------------------------------------------------------------
00278 void OS::TBaseMessage::send()
00279 {
00280     TCritSect cs;
00281 
00282     if(ProcessMap)
00283     {
00284         TProcessMap Timeouted = Kernel.ReadyProcessMap;         // Process has its tag set in ReadyProcessMap if timeout expired,
00285                                                                 // or it was waked up by OS::ForceWakeUpProcess()
00286         if( ProcessMap & ~Timeouted )                           // if any process has to be waked up
00287         {
00288             SetPrioTag(Kernel.ReadyProcessMap, ProcessMap);     // place all waiting processes to the ready map
00289             ClrPrioTag(ProcessMap, ~Timeouted);                 // remove all non-timeouted processes from the waiting map.
00290             Kernel.Scheduler();
00291             return;
00292         }
00293     }
00294 
00295     NonEmpty = true;
00296 }
00297 //------------------------------------------------------------------------------
00298