Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OS_Services.h Source File

OS_Services.h

00001 //******************************************************************************
00002 //*
00003 //*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
00004 //*
00005 //*     NICKNAME:  scmRTOS
00006 //*
00007 //*     PURPOSE:  OS Services Header. Declarations And Definitions
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 #ifndef OS_SERVICES_H
00043 #define OS_SERVICES_H
00044 
00045 namespace OS
00046 {
00047     //--------------------------------------------------------------------------
00048     //
00049     //       NAME       :   Mutex
00050     //
00051     /// Binary semaphore for support of mutual exclusion
00052     //
00053     //       DESCRIPTION:
00054     //
00055     //
00056     class TMutex
00057     {
00058     public:
00059         INLINE TMutex() : ProcessMap(0), ValueTag(0) { }
00060         void Lock();
00061         void Unlock();
00062         void UnlockISR();
00063 
00064         INLINE bool LockSoftly()     { TCritSect cs; if(ValueTag) return false; else Lock(); return true; }
00065         INLINE bool IsLocked() const { TCritSect cs; if(ValueTag) return true; else return false; }
00066 
00067     private:
00068         TProcessMap ProcessMap;
00069         TProcessMap ValueTag;
00070 
00071     };
00072     //--------------------------------------------------------------------------
00073 
00074     //--------------------------------------------------------------------------
00075     //
00076     ///  Event Flag
00077     ///
00078     ///  Intended for processes synchronization and
00079     ///  event notification one (or more) process by another
00080     //
00081     //       DESCRIPTION:
00082     //
00083     //
00084     class TEventFlag
00085     {
00086     public:
00087         enum TValue { efOn = 1, efOff= 0 };     // prefix 'ef' means: "Event Flag"
00088 
00089     public:
00090         INLINE TEventFlag(TValue init_val = efOff) : ProcessMap(0), Value(init_val) { }
00091 
00092         bool Wait(TTimeout timeout = 0);
00093         void Signal();
00094         INLINE void Clear() { TCritSect cs; Value = efOff; }
00095         INLINE inline void SignalISR();
00096         INLINE bool IsSignaled() { TCritSect cs; if(Value == efOn) return true; else return false; }
00097 
00098     private:
00099         TProcessMap ProcessMap;
00100         TValue      Value;
00101     };
00102     //--------------------------------------------------------------------------
00103 
00104     //--------------------------------------------------------------------------
00105     //
00106     ///  TChannel
00107     ///
00108     ///  Byte-wide data channel for transferring "raw" data
00109     //
00110     //       DESCRIPTION:
00111     //
00112     //
00113     class TChannel
00114     {
00115     public:
00116         INLINE TChannel(byte* buf, byte size) : Cbuf(buf, size) { }
00117         void Push(byte x);
00118         byte Pop();
00119         void Write(const byte* data, const byte count);
00120         void Read(byte* const data, const byte count);
00121 
00122         INLINE byte GetCount() const { TCritSect cs; return Cbuf.get_count(); }
00123 
00124     private:
00125         TProcessMap ProducersProcessMap;
00126         TProcessMap ConsumersProcessMap;
00127         usr::TCbuf Cbuf;
00128 
00129     private:
00130         void CheckWaiters(TProcessMap& pm);
00131     };
00132     //--------------------------------------------------------------------------
00133 
00134 
00135     //--------------------------------------------------------------------------
00136     //
00137     //       NAME       :  channel
00138     //
00139     //       PURPOSE    :  Data channel for transferring data
00140     //                     objects of arbitrary type
00141     //
00142     //       DESCRIPTION:
00143     //
00144     //
00145     template<typename T, word Size, typename S = byte>
00146     ///  channel
00147     ///
00148     ///  Data channel for transferring data objects of arbitrary type
00149     class channel
00150     {
00151     public:
00152         INLINE channel() : ProducersProcessMap(0)
00153                          , ConsumersProcessMap(0)
00154                          , pool()
00155         {
00156         }
00157 
00158         //----------------------------------------------------------------
00159         //
00160         //    Data transfer functions
00161         //
00162         void write(const T* data, const S cnt);
00163         bool read (T* const data, const S cnt, TTimeout timeout = 0);
00164 
00165         void push      (const T& item);
00166         void push_front(const T& item);
00167 
00168         bool pop     (T& item, TTimeout timeout = 0);
00169         bool pop_back(T& item, TTimeout timeout = 0);
00170 
00171 
00172         //----------------------------------------------------------------
00173         //
00174         //    Service functions
00175         //
00176         INLINE S get_count()     const { TCritSect cs; return pool.get_count();     }
00177         INLINE S get_free_size() const { TCritSect cs; return pool.get_free_size(); }
00178         void flush();
00179         //const T& operator[](const S index) { TCritSect cs; return pool[index]; }
00180 
00181 
00182     private:
00183         TProcessMap ProducersProcessMap;
00184         TProcessMap ConsumersProcessMap;
00185         usr::ring_buffer<T, Size, S> pool;
00186 
00187     private:
00188         void CheckWaiters(TProcessMap& pm);
00189     };
00190 
00191     //--------------------------------------------------------------------------
00192 
00193     //--------------------------------------------------------------------------
00194     //
00195     /// message
00196     ///
00197     /// Template for messages
00198     //
00199     //       DESCRIPTION:
00200     //
00201     //
00202     class TBaseMessage
00203     {
00204     public:
00205         INLINE TBaseMessage() : ProcessMap(0), NonEmpty(false) { }
00206 
00207         bool wait  (TTimeout timeout = 0);
00208         void send();
00209         INLINE inline void sendISR();
00210         INLINE bool is_non_empty() const { TCritSect cs; return NonEmpty;  }
00211         INLINE void reset       ()       { TCritSect cs; NonEmpty = false; }
00212 
00213     private:
00214         TProcessMap ProcessMap;
00215         bool NonEmpty;
00216     };
00217     //--------------------------------------------------------------------------
00218     template<typename T>
00219     class message : public TBaseMessage
00220     {
00221     public:
00222         INLINE message() : TBaseMessage()   { }
00223         INLINE const T& operator=(const T& msg) { TCritSect cs; Msg = msg; return Msg; }
00224         INLINE operator     T() const       { TCritSect cs; return Msg; }
00225 
00226     private:
00227         T Msg;
00228     };
00229     //--------------------------------------------------------------------------
00230 }
00231 //------------------------------------------------------------------------------
00232 //
00233 //          Function-members implementation
00234 //
00235 //------------------------------------------------------------------------------
00236 void OS::TEventFlag::SignalISR()
00237 {
00238     TCritSect cs;
00239     if(ProcessMap)                                          // if any process waits for event
00240     {
00241         TProcessMap Timeouted = Kernel.ReadyProcessMap;     // Process has its tag set in ReadyProcessMap if timeout
00242                                                             // expired, or it was waked up by OS::ForceWakeUpProcess()
00243         if( ProcessMap & ~Timeouted )                       // if any process has to be waked up
00244         {
00245             SetPrioTag(Kernel.ReadyProcessMap, ProcessMap); // place all waiting processes to the ready map
00246             ClrPrioTag(ProcessMap, ~Timeouted);             // remove all non-timeouted processes from the waiting map.
00247             return;
00248         }
00249     }
00250     Value = efOn;
00251 }
00252 //------------------------------------------------------------------------------
00253 template<typename T, word Size, typename S>
00254 void OS::channel<T, Size, S>::CheckWaiters(TProcessMap& pm)
00255 {
00256     if(pm)
00257     {
00258         TProcessMap Timeouted = Kernel.ReadyProcessMap;
00259 
00260         SetPrioTag(Kernel.ReadyProcessMap, pm);       // place all waiting processes to the ready map
00261         ClrPrioTag(pm, ~Timeouted);                   // remove waiting processes from the wait map
00262         Kernel.Scheduler();
00263     }
00264 }
00265 //------------------------------------------------------------------------------
00266 template<typename T, word Size, typename S>
00267 void OS::channel<T, Size, S>::push(const T& item)
00268 {
00269     TCritSect cs;
00270 
00271     while(!pool.get_free_size())
00272     {
00273         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00274         SetPrioTag(ProducersProcessMap, PrioTag);     // channel is full, put current process to the wait map
00275         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);  // remove current process from the ready map
00276         Kernel.Scheduler();
00277     }
00278 
00279     pool.push_back(item);
00280     CheckWaiters(ConsumersProcessMap);
00281 }
00282 //------------------------------------------------------------------------------
00283 template<typename T, word Size, typename S>
00284 void OS::channel<T, Size, S>::push_front(const T& item)
00285 {
00286     TCritSect cs;
00287 
00288     while(!pool.get_free_size())
00289     {
00290         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00291         SetPrioTag(ProducersProcessMap, PrioTag);     // channel is full, put current process to the wait map
00292         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);  // remove current process from the ready map
00293         Kernel.Scheduler();
00294     }
00295 
00296     pool.push_front(item);
00297     CheckWaiters(ConsumersProcessMap);
00298 }
00299 //------------------------------------------------------------------------------
00300 template<typename T, word Size, typename S>
00301 bool OS::channel<T, Size, S>::pop(T& item, TTimeout timeout)
00302 {
00303     TCritSect cs;
00304 
00305     if(pool.get_count())
00306     {
00307         item = pool.pop();
00308         CheckWaiters(ProducersProcessMap);
00309         return true;
00310     }
00311     else
00312     {
00313         TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
00314         p->Timeout = timeout;
00315 
00316         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00317         for(;;)
00318         {
00319             SetPrioTag(ConsumersProcessMap, PrioTag);     // channel is empty, put current process to the wait map
00320             ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);  // remove current process from the ready map
00321             Kernel.Scheduler();
00322 
00323             if(pool.get_count())
00324             {
00325                 p->Timeout = 0;
00326                 item = pool.pop();
00327                 CheckWaiters(ProducersProcessMap);
00328                 return true;
00329             }
00330 
00331             if(ConsumersProcessMap & PrioTag)             // waked up by timer when timeout expired
00332             {                                             // or by OS::ForceWakeUpProcess()
00333 
00334                 p->Timeout = 0;                           // non-zero if waked up by ForceWakeUpProcess()
00335                 ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map
00336                 return false;
00337             }
00338         }
00339     }
00340 }
00341 //------------------------------------------------------------------------------
00342 template<typename T, word Size, typename S>
00343 bool OS::channel<T, Size, S>::pop_back(T& item, TTimeout timeout)
00344 {
00345     TCritSect cs;
00346 
00347     if(pool.get_count())
00348     {
00349         item = pool.pop_back();
00350         CheckWaiters(ProducersProcessMap);
00351         return true;
00352     }
00353     else
00354     {
00355         TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
00356         p->Timeout = timeout;
00357 
00358         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00359         for(;;)
00360         {
00361             SetPrioTag(ConsumersProcessMap, PrioTag);     // channel is empty, put current process to the wait map
00362             ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);  // remove current process from the ready map
00363             Kernel.Scheduler();
00364 
00365             if(pool.get_count())
00366             {
00367                 p->Timeout = 0;
00368                 item = pool.pop_back();
00369                 CheckWaiters(ProducersProcessMap);
00370                 return true;
00371             }
00372 
00373             if(ConsumersProcessMap & PrioTag)             // waked up by timer when timeout expired
00374             {                                             // or by OS::ForceWakeUpProcess()
00375 
00376                 p->Timeout = 0;                           // non-zero if waked up by ForceWakeUpProcess()
00377                 ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map
00378                 return false;
00379             }
00380         }
00381     }
00382 }
00383 //------------------------------------------------------------------------------
00384 template<typename T, word Size, typename S>
00385 void OS::channel<T, Size, S>::flush()
00386 {
00387     TCritSect cs;
00388     pool.flush();
00389     CheckWaiters(ProducersProcessMap);
00390 }
00391 //------------------------------------------------------------------------------
00392 template<typename T, word Size, typename S>
00393 void OS::channel<T, Size, S>::write(const T* data, const S count)
00394 {
00395     TCritSect cs;
00396 
00397     while(pool.get_free_size() < count)
00398     {
00399         TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00400         SetPrioTag(ProducersProcessMap, PrioTag);     // channel does not have enough space, put current process to the wait map
00401         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);  // remove current process from the ready map
00402         Kernel.Scheduler();
00403     }
00404 
00405     pool.write(data, count);
00406     CheckWaiters(ConsumersProcessMap);
00407 }
00408 //------------------------------------------------------------------------------
00409 template<typename T, word Size, typename S>
00410 bool OS::channel<T, Size, S>::read(T* const data, const S count, TTimeout timeout)
00411 {
00412     TCritSect cs;
00413 
00414     TBaseProcess* p = Kernel.ProcessTable[Kernel.CurProcPriority];
00415     p->Timeout = timeout;
00416 
00417     TProcessMap PrioTag = GetPrioTag(Kernel.CurProcPriority);
00418     while(pool.get_count() < count)
00419     {
00420         SetPrioTag(ConsumersProcessMap, PrioTag);     // channel doesn't contain enough data, put current process to the wait map
00421         ClrPrioTag(Kernel.ReadyProcessMap, PrioTag);  // remove current process from the ready map
00422         Kernel.Scheduler();
00423 
00424         if(ConsumersProcessMap & PrioTag)             // waked up by timer when timeout expired
00425         {                                             // or by OS::ForceWakeUpProcess()
00426 
00427             p->Timeout = 0;                           // non-zero if waked up by ForceWakeUpProcess()
00428             ClrPrioTag(ConsumersProcessMap, PrioTag); // remove current process from the wait map
00429             return false;
00430         }
00431     }
00432 
00433     p->Timeout = 0;
00434     pool.read(data, count);
00435     CheckWaiters(ProducersProcessMap);
00436 
00437     return true;
00438 }
00439 //------------------------------------------------------------------------------
00440 
00441 //------------------------------------------------------------------------------
00442 //
00443 //              OS::message template
00444 //
00445 //          Function-members implementation
00446 //
00447 //
00448 //------------------------------------------------------------------------------
00449 void OS::TBaseMessage::sendISR()
00450 {
00451     TCritSect cs;
00452 
00453     if(ProcessMap)
00454     {
00455         TProcessMap Timeouted = OS::Kernel.ReadyProcessMap;     // Process has it's tag set in ReadyProcessMap if timeout
00456                                                                 // expired, or it was waked up by  OS::ForceWakeUpProcess()
00457         if( ProcessMap & ~Timeouted )                           // if any process has to be waked up
00458         {
00459             SetPrioTag(Kernel.ReadyProcessMap, ProcessMap);     // place all waiting processes to the ready map
00460             ClrPrioTag(ProcessMap, ~Timeouted);                 // remove all non-timeouted processes from the waiting map.
00461             return;
00462         }
00463     }
00464     NonEmpty = true;
00465 }
00466 //------------------------------------------------------------------------------
00467 #endif // OS_SERVICES_H