Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OS_Kernel.h Source File

OS_Kernel.h

00001 //******************************************************************************
00002 //*
00003 //*     FULLNAME:  Single-Chip Microcontroller Real-Time Operating System
00004 //*
00005 //*     NICKNAME:  scmRTOS
00006 //*
00007 //*     PURPOSE:  OS Kernel 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_KERNEL_H
00043 #define OS_KERNEL_H
00044 
00045 #include <stddef.h>
00046 #include <commdefs.h>
00047 #include <usrlib.h>
00048 
00049 //------------------------------------------------------------------------------
00050 
00051 //==============================================================================
00052 extern "C" void OS_Start(TStackItem* sp);
00053 
00054 #if scmRTOS_CONTEXT_SWITCH_SCHEME == 0
00055     extern "C" void OS_ContextSwitcher(TStackItem** Curr_SP, TStackItem* Next_SP);
00056 #else
00057     extern "C" TStackItem* OS_ContextSwitchHook(TStackItem* sp);
00058 #endif
00059 
00060 //==============================================================================
00061 
00062 //------------------------------------------------------------------------------
00063 //
00064 //
00065 //     NAME       :   OS
00066 //
00067 //     PURPOSE    :   Namespace for all OS stuff
00068 //
00069 //     DESCRIPTION:   Includes:  Kernel,
00070 //                               Processes,
00071 //                               Mutexes,
00072 //                               Event Flags,
00073 //                               Byte-wide Channels,
00074 //                               Arbitrary-type Channels,
00075 //                               Messages
00076 //
00077 namespace OS
00078 {
00079     class TBaseProcess;
00080 
00081     INLINE inline void SetPrioTag(TProcessMap& pm, const TProcessMap PrioTag) { pm |=  PrioTag; }
00082     INLINE inline void ClrPrioTag(TProcessMap& pm, const TProcessMap PrioTag) { pm &= ~PrioTag; }
00083 
00084     //--------------------------------------------------------------------------
00085     //
00086     //     NAME       :   TKernel
00087     //
00088     ///  Implements kernel-level operations such as
00089     ///  process management, process-level scheduling,
00090     ///  ISR-level scheduling, system timing.
00091     //
00092     //     DESCRIPTION:
00093     //
00094     //
00095     class TKernel
00096     {
00097         //-----------------------------------------------------------
00098         //
00099         //     Declarations
00100         //
00101         
00102 
00103         friend class TISRW;
00104         friend class TISRW_SS;
00105         friend class TBaseProcess;
00106         friend class TMutex;
00107         friend class TEventFlag;
00108         friend class TChannel;
00109         friend class TBaseMessage;
00110 
00111         template<typename T, word size, class S> friend class channel;
00112         template<typename T>                     friend class message;
00113 
00114         friend void          Run();
00115         friend void          WakeUpProcess(TBaseProcess& p);
00116         friend void          ForceWakeUpProcess(TBaseProcess& p);
00117         friend inline bool   IsProcessSleeping(const TBaseProcess& p);
00118         friend inline bool   IsProcessSuspended(const TBaseProcess& p);
00119         friend inline dword  GetTickCount();
00120 
00121         //-----------------------------------------------------------
00122         //
00123         //      Data
00124         //
00125     private:
00126         byte CurProcPriority;
00127         TProcessMap ReadyProcessMap;
00128         TBaseProcess* ProcessTable[scmRTOS_PROCESS_COUNT+1];
00129         volatile byte ISR_NestCount;
00130 
00131     #if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
00132         byte SchedProcPriority;
00133     #endif
00134 
00135     #if scmRTOS_SYSTEM_TICKS_ENABLE == 1
00136         volatile dword SysTickCount;
00137     #endif
00138 
00139     //-----------------------------------------------------------
00140     //
00141     //      Functions
00142     //
00143     public:
00144         INLINE TKernel()
00145             : CurProcPriority(pr0)
00146             , ReadyProcessMap( (1 << (scmRTOS_PROCESS_COUNT + 1)) - 1)  // set all processes ready
00147             , ISR_NestCount(0)
00148         {
00149         }
00150 
00151     private:
00152         INLINE inline void RegisterProcess(TBaseProcess* const p);
00153 
00154         void Sched();
00155         INLINE void Scheduler() { if(ISR_NestCount) return; else  Sched(); }
00156         INLINE inline void SchedISR();
00157 
00158     #if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
00159         INLINE inline bool IsContextSwitchDone() const volatile;
00160     #endif
00161         INLINE void SetProcessReady  (const byte pr) { TProcessMap PrioTag = GetPrioTag(pr); SetPrioTag( ReadyProcessMap, PrioTag); }
00162         INLINE void SetProcessUnready(const byte pr) { TProcessMap PrioTag = GetPrioTag(pr); ClrPrioTag( ReadyProcessMap, PrioTag); }
00163 
00164     public:
00165         INLINE inline void SystemTimer();
00166     #if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
00167         INLINE inline TStackItem* ContextSwitchHook(TStackItem* sp);
00168     #endif
00169 
00170     };  // End of TKernel class definition
00171     //--------------------------------------------------------------------------
00172     extern TKernel Kernel;
00173 
00174     //--------------------------------------------------------------------------
00175     //
00176     /// BaseProcess
00177     ///
00178     /// Implements base class-type for application processes
00179     //
00180     //      DESCRIPTION:
00181     //
00182     //
00183     class TBaseProcess
00184     {
00185         friend class TKernel;
00186         friend class TISRW;
00187         friend class TISRW_SS;
00188         friend class TEventFlag;
00189         friend class TMutex;
00190         friend class TBaseMessage;
00191 
00192         template<typename T, word size, class S> friend class channel;
00193         template<typename T>                     friend class message;
00194 
00195 
00196         friend void         Run();
00197         friend void         WakeUpProcess(TBaseProcess& p);
00198         friend void         ForceWakeUpProcess(TBaseProcess& p);
00199         friend bool         IsProcessSleeping(const TBaseProcess& p);
00200         friend bool         IsProcessSuspended(const TBaseProcess& p);
00201 
00202     public:
00203     #if SEPARATE_RETURN_STACK == 0
00204         TBaseProcess( TStackItem* Stack, word stack_size, TPriority pr, void (*exec)() );
00205     #else
00206         TBaseProcess( TStackItem* Stack, TStackItem* RStack, TPriority pr, void (*exec)() );
00207     #endif
00208 
00209         static void Sleep(TTimeout timeout = 0);
00210 
00211     protected:
00212         TStackItem* StackPointer;
00213         word StackSize;
00214         TTimeout Timeout;
00215         TPriority Priority;
00216         
00217     };
00218     //--------------------------------------------------------------------------
00219 
00220     //--------------------------------------------------------------------------
00221     //
00222     ///  process
00223     ///
00224     ///  Implements template for application processes instantiation
00225     //
00226     //      DESCRIPTION:
00227     //
00228     //
00229     #if SEPARATE_RETURN_STACK == 0
00230 
00231         template<TPriority pr, word stack_size>
00232         class process : public TBaseProcess
00233         {
00234         public:
00235             INLINE_PROCESS_CTOR process();
00236 #ifdef DEBUG_STACK
00237 word UsedStackSize();
00238 #endif //DEBUG_STACK
00239             OS_PROCESS static void Exec();
00240 
00241         private:
00242             TStackItem Stack[stack_size/sizeof(TStackItem)];
00243         };
00244 
00245         template<TPriority pr, word stack_size>
00246         OS::process<pr, stack_size>::process() : TBaseProcess( &Stack[stack_size/sizeof(TStackItem)]
00247                                                               , stack_size // debug
00248                                                               , pr
00249                                                               , reinterpret_cast<void (*)()>(Exec) )
00250         {
00251         }
00252 #ifdef DEBUG_STACK
00253 template<TPriority pr, word stack_size>
00254 word process<pr,stack_size>::UsedStackSize()
00255 {
00256 TStackItem* Idx = Stack;
00257 while(*(Idx++) == STACK_FILL_CONST);
00258 return ((Stack + (StackSize/sizeof(TStackItem))) - Idx)*sizeof(TStackItem);
00259 }
00260 #endif //DEBUG_STACK
00261     #else
00262 
00263         template<TPriority pr, word stack_size, word rstack_size>
00264         class process : public TBaseProcess
00265         {
00266         public:
00267             INLINE_PROCESS_CTOR process();
00268 
00269             OS_PROCESS static void Exec();
00270 
00271         private:
00272             TStackItem Stack [stack_size/sizeof(TStackItem)];
00273             TStackItem RStack[rstack_size/sizeof(TStackItem)];
00274         };
00275 
00276         template<TPriority pr, word stack_size, word rstack_size>
00277         process<pr, stack_size, rstack_size>::process() : TBaseProcess( &Stack[stack_size/sizeof(TStackItem)]
00278                                                                       , &RStack[rstack_size/sizeof(TStackItem)]
00279                                                                       , pr
00280                                                                       , reinterpret_cast<void (*)()>(Exec))
00281         {
00282         }
00283 
00284     #endif
00285     //--------------------------------------------------------------------------
00286 
00287     //--------------------------------------------------------------------------
00288     //
00289     //       Miscellaneous
00290     //
00291     //
00292     INLINE inline void Run();
00293     INLINE inline void LockSystemTimer()   { TCritSect cs; LOCK_SYSTEM_TIMER();   }
00294     INLINE inline void UnlockSystemTimer() { TCritSect cs; UNLOCK_SYSTEM_TIMER(); }
00295     void WakeUpProcess(TBaseProcess& p);
00296     void ForceWakeUpProcess(TBaseProcess& p);
00297     INLINE inline void Sleep(TTimeout t = 0) { TBaseProcess::Sleep(t); }
00298 
00299     INLINE inline bool IsProcessSleeping(const TBaseProcess& p)
00300     {
00301         TCritSect cs;
00302         if(p.Timeout)
00303             return true;
00304         else
00305             return false;
00306     }
00307 
00308     INLINE inline bool IsProcessSuspended(const TBaseProcess& p)
00309     {
00310         TCritSect cs;
00311         if(Kernel.ReadyProcessMap & GetPrioTag(p.Priority))
00312             return false;
00313         else
00314             return true;
00315     }
00316     //--------------------------------------------------------------------------
00317 
00318 #if scmRTOS_SYSTEM_TICKS_ENABLE == 1
00319     INLINE inline dword GetTickCount() { TCritSect cs; return Kernel.SysTickCount; }
00320 #endif
00321 
00322 #if scmRTOS_SYSTIMER_HOOK_ENABLE == 1
00323     INLINE_SYS_TIMER_HOOK void  SystemTimerUserHook();
00324 #endif
00325 
00326 #if scmRTOS_CONTEXT_SWITCH_USER_HOOK_ENABLE == 1
00327     INLINE_CONTEXT_SWITCH_HOOK void  ContextSwitchUserHook();
00328 #endif
00329     
00330 }
00331 //------------------------------------------------------------------------------
00332 
00333 //------------------------------------------------------------------------------
00334 //
00335 ///  Register Process
00336 ///
00337 ///  Places pointer to process in kernel's process table
00338 //
00339 void OS::TKernel::RegisterProcess(OS::TBaseProcess* const p)
00340 {
00341     ProcessTable[p->Priority] = p;
00342 }
00343 //------------------------------------------------------------------------------
00344 //
00345 /// System Timer Implementation
00346 ///
00347 /// Performs process's timeouts checking and
00348 ///               moving processes to ready-to-run state
00349 //
00350 void OS::TKernel::SystemTimer()
00351 {
00352     SYS_TIMER_CRIT_SECT();
00353 #if scmRTOS_SYSTEM_TICKS_ENABLE == 1
00354     SysTickCount++;
00355 #endif
00356 
00357 #if scmRTOS_PRIORITY_ORDER == 0
00358     const byte BaseIndex = 0;
00359 #else
00360     const byte BaseIndex = 1;
00361 #endif
00362 
00363     for(byte i = BaseIndex; i < (scmRTOS_PROCESS_COUNT + BaseIndex); i++)
00364     {
00365         TBaseProcess* p = ProcessTable[i];
00366 
00367         if(p->Timeout > 0)
00368         {
00369             if(--p->Timeout == 0)
00370             {
00371                 SetProcessReady(p->Priority);
00372             }
00373         }
00374     }
00375 }
00376 //------------------------------------------------------------------------------
00377 //
00378 ///    ISR optimized scheduler
00379 ///
00380 ///    !!! IMPORTANT: This function must be call from ISR services only !!!
00381 //
00382 //
00383 #if scmRTOS_CONTEXT_SWITCH_SCHEME == 0
00384 void OS::TKernel::SchedISR()
00385 {
00386     byte NextPrty = GetHighPriority(ReadyProcessMap);
00387     if(NextPrty != CurProcPriority)
00388     {
00389         TStackItem*  Next_SP = ProcessTable[NextPrty]->StackPointer;
00390         TStackItem** Curr_SP_addr = &(ProcessTable[CurProcPriority]->StackPointer);
00391         CurProcPriority = NextPrty;
00392         OS_ContextSwitcher(Curr_SP_addr, Next_SP);
00393     }
00394 }
00395 #else
00396 void OS::TKernel::SchedISR()
00397 {
00398     byte NextPrty = GetHighPriority(ReadyProcessMap);
00399     if(NextPrty != CurProcPriority)
00400     {
00401         SchedProcPriority    = NextPrty;
00402         RaiseContextSwitch();
00403     }
00404 }
00405 //------------------------------------------------------------------------------
00406 bool OS::TKernel::IsContextSwitchDone() const volatile
00407 {
00408      byte cur    = CurProcPriority;    ///< reading to temporary vars is performed due to
00409      byte sched  = SchedProcPriority;  ///< suppress warning about order of volatile access
00410      return cur == sched;
00411 }
00412 //------------------------------------------------------------------------------
00413 TStackItem* OS::TKernel::ContextSwitchHook(TStackItem* sp)
00414 {
00415     ProcessTable[CurProcPriority]->StackPointer = sp;
00416     sp = ProcessTable[SchedProcPriority]->StackPointer;
00417 
00418 #if scmRTOS_CONTEXT_SWITCH_USER_HOOK_ENABLE == 1
00419     ContextSwitchUserHook();
00420 #endif 
00421 
00422     CurProcPriority = SchedProcPriority;
00423     return sp;
00424 }
00425 //------------------------------------------------------------------------------
00426 #endif // scmRTOS_CONTEXT_SWITCH_SCHEME
00427 
00428 //-----------------------------------------------------------------------------
00429 /// Start Operation
00430 INLINE inline void OS::Run()
00431 {
00432     TStackItem* sp = Kernel.ProcessTable[pr0]->StackPointer;
00433     OS_Start(sp);
00434 }
00435 
00436 #include <OS_Services.h>
00437 
00438 #endif // OS_KERNEL_H
00439