os.h

Go to the documentation of this file.
00001 #ifndef _OS_H_
00002 #define _OS_H_
00003 /**
00004  * \file os.h
00005  * \brief A simple RTOS interface
00006  *
00007  * \mainpage A Simple RTOS
00008  * This is a simple RTOS that supports pre-emptive multithreading, and
00009  * interprocess synchronization using Events.
00010  *
00011  * \b Note: Please don't edit the interface file "os.h".
00012  *
00013  * \author Dr. Mantis Cheng
00014  * \date 26 September 2007
00015  *
00016  * \section assumptions GLOBAL ASSUMPTIONS
00017  *
00018  *    (ATMEL specific)
00019  *  - Counter1 Timer and SWI interrupts are reserved.
00020  *
00021  *  - All runtime exceptions (where assumptions are violated) or other
00022  *    unrecoverable errors get handled by calling OS_Abort().
00023  *  - Each valid entry in PPP[] must be non-zero except IDLE.
00024  *  - All unspecified runtime errors have undefined behaviours, e.g., stack overflow.
00025  *  - PPP[] \b cannot be modified once the application starts running.
00026  *
00027  * \section policy SCHEDULING POLICY
00028  *
00029  *   There are three scheduling levels: SYSTEM, PERIODIC and RR.
00030  *   These levels are prioritized with SYSTEM being the highest, and RR being
00031  *   the lowest.
00032  *
00033  *   Preemption occurs immediately. Whenever preemption is feasible, it takes
00034  *   place instantly. As soon as a higher priority task becomes ready, it
00035  *   preempts all lower priority tasks.
00036  *
00037  * \section system SYSTEM TASKS
00038  *
00039  *   SYSTEM (level) tasks are FCFS; they run to completion, i.e., until they
00040  *   terminate, block or yield. Thus, they are non-preemptible, not even by
00041  *   other SYSTEM tasks. They should only be used for critical system level
00042  *   activities, e.g., error or fault recovery. Running too many SYSTEM tasks
00043  *   could affect the real time performance  of all other low level tasks.
00044  *
00045  *
00046  * \section periodic PERIODIC TASKS
00047  *
00048  *   PERIODIC tasks are scheduled based on a fixed cyclic scheduling plan;
00049  *   they are time-based. (See below about PPP[].) Since they are time-critical,
00050  *   they are \b NOT allowed to block (i.e., wait on an event).
00051  *   When a PERIODIC task is created, it is assigned a "name",
00052  *   a non-zero user-defined constant between 1 and MAXPROCESS.
00053  *   This name is fixed and can NEVER be changed again.
00054  *   No two PERIODIC tasks have the same name. All names are unique.
00055  *   Since tasks may terminate and be created again over time,
00056  *   the same name may be reused over time for different PERIODIC task
00057  *   instance.
00058  *
00059  *   The PPP[] array is essentially a linear representation of a Gantt diagram.
00060  *   It is an array of [Name1, Interval1, Name2, Interval 2, ... ].
00061  *   The name of every PERIODIC task must appear in PPP[] array at least once,
00062  *   but may be more than once.
00063  *
00064  *   For example, if we create three PERIODIC tasks with names A, B and
00065  *   C out of three functions P(), Q() and R() respectively. Then,
00066  *   PPP[] = { A, 2, B, 3, A, 5, C, 1 } means executing A for 2 ticks,
00067  *   then B for 3 ticks, then A again for 5 ticks, then C for 1 tick,
00068  *   then A again, and so on. The total cycle time is 2+3+5+1=11 ticks.
00069  *   That is, within 11 ticks, A executes twice, B once and C once.
00070  *   If P() terminates, but the name A is later assigned to another function U(),
00071  *   then A will be executed again according to PPP[] order using U().
00072  *   In a sense, PPP[] specifies at least a single execution cycle
00073  *   of all PERIODIC tasks. IDLE is a special PERIODIC task name, which means
00074  *   do nothing during this task's assigned interval.
00075  *
00076  *   A PERIODIC task may yield (calling Task_Next()) to relinquish
00077  *   the processor before its assigned interval. In this case, it has completed
00078  *   its current execution interval and is waiting for its next interval.
00079  *
00080  *   It is a runtime error if a PERIODIC task executes longer than the
00081  *   currently assigned interval. It is important NOT to underestimate
00082  *   the execution time requirement of a PERIODIC task. Choosing the appropriate
00083  *   execution order and intervals for all PERIODIC tasks is the responsibility
00084  *   of the Application Design Engineer(s), not our RTOS. Hence, all timing
00085  *   violations should be caught and then reported.
00086  *
00087  *   By specifying PPP[] and scheduling our PERIODIC tasks accordingly,
00088  *   we shall know precisely the execution "cycle" time of all such tasks,
00089  *   thus their best execution frequency/rate and response time. This is how
00090  *   we guarantee the predictability of timing and ordering all critical
00091  *   activities.
00092  *
00093  *  \section rr RR TASKS
00094  *
00095  *   RR tasks are scheduled in a round-robin fashion, i.e., each RR
00096  *   task runs for one TICK approximately and yields to the next RR task. They
00097  *   don't have any time critical schedule to follow, thus they share the
00098  *   processor cycles fairly.
00099  *
00100  *   RR tasks are allowed to run \a only when no PERIODIC or SYSTEM tasks
00101  *   are executing. When an RR task resumes after pre-emption,
00102  *   it re-enters its RR level at the end. When an RR task
00103  *   yields, or resumes after being unblocked, it re-enters its level
00104  *   at the end as well.
00105  *
00106  *
00107  *  \section boot OS BOOTING
00108  *     Our RTOS is compiled together with an application. It doesn't provide
00109  *     a "main()" function, which is a part of the application. By convention,
00110  *     the "main()" is the first function to be called by the C runtime code,
00111  *     "crt0.S". For our RTOS, we shall change this convention as follows:
00112  *     -# OS_Init() is called from crt0.S as the very first C function to be
00113  *        executed instead of main().
00114  *     -# Upon completion of OS_Init(), the application's main() is then
00115  *        created as the first and only SYSTEM level task.
00116  *     -# In main(), the rest of the application tasks are then created.
00117  *     -# In order for all other application tasks to run, our main() task
00118  *        must either terminate or block on an event. (For example, main()
00119  *        may become a "watchdog" task to reset the entire application.)
00120  *
00121  *
00122  * \section ipc INTERPROCESS COMMUNICATION
00123  *
00124  *    Events are one-way synchronization signals. They don't have any "memory"
00125  *    (i.e., values); thus, they are NOT semaphores. Any SYSTEM or RR task may
00126  *    wait on an event; PERIODIC tasks \b MUST \b NOT wait on any event.
00127  *    However, any task may signal/broadcast an event.
00128  *    A waiting task is resumed when the associated event is signalled.
00129  *    All waiting tasks are resumed when the associated event is broadcasted.
00130  *    When an event is signalled (or broadcasted) but there are no waiting tasks,
00131  *    this is a \a no-op; hence, events have \b no memory.
00132  *
00133  */
00134 
00135 
00136 /*==================================================================
00137  *             T Y P E S   &   C O N S T A N T S
00138  *==================================================================
00139  */
00140 
00141 /*================
00142   *    C O N S T A N T S
00143   *================
00144   */
00145 /* limits */
00146 
00147 /** max. number of processes supported */
00148 #define MAXPROCESS     8
00149 
00150 /** max. number of Events supported */
00151 #define MAXEVENT    8
00152 
00153 /** workspace size of each process in bytes */
00154 #define WORKSPACE      256
00155 
00156 /** milliseconds, or something close to this value
00157  * \sa \ref periodic.
00158  */
00159 #define TICK                    5
00160 
00161 /* scheduling levels */
00162 
00163 /** a scheduling level: system tasks with first-come-first-served policy
00164  * \sa \ref system, Task_Create().
00165  */
00166 #define SYSTEM            3
00167 
00168 /** a scheduling level: periodic tasks with predefined intervals
00169  * \sa \ref periodic, Task_Create().
00170  */
00171 #define PERIODIC            2
00172 
00173 /** A scheduling level: first-come-first-served cooperative tasks
00174  * \sa \ref rr, Task_Create().
00175  */
00176 #define RR                   1
00177 
00178 #define NULL     0   /* undefined */
00179 #define IDLE     0   /* a well-known PERIODIC task name */
00180 
00181 /*================
00182   *    T Y P E S
00183   *================
00184   */
00185 /** An Event descriptor
00186  * \sa Event_Init().
00187  */
00188 typedef struct event EVENT;
00189 
00190 /*================
00191   *    G L O B A L S
00192   *================
00193   */
00194  /**
00195    *  A periodic task scheduling plan (read-only, defined by the application).
00196    *
00197    *  This is specified by the application. The scheduling ordering and duration
00198    *  of all PERIODIC tasks are specified by this plan. The total number of
00199    *  occurrences of all PERIODIC tasks, including IDLE, is given by PT.
00200    *  e.g., PPP[] = { A, 2, IDLE, 5, B, 1, A, 2, C, 4 };
00201    *        PT = 5;
00202    *  \sa \ref periodic.
00203    */
00204 extern const unsigned char PPP[];
00205 extern const unsigned int PT;
00206 
00207 /*==================================================================
00208  *             A C C E S S    P R O C E D U R E S
00209  *==================================================================
00210  */
00211 
00212   /*=====  OS   Initialization ===== */
00213 
00214 /** Initialize this RTOS; must be called first.
00215  * \sa \ref boot.
00216  */
00217 void OS_Init(void);
00218 
00219 /** Abort the execution of this RTOS due to an unrecoverable erorr.
00220  * \sa \ref assumptions.
00221  */
00222 void OS_Abort(void);
00223 
00224   /*=====  Task API ===== */
00225 
00226  /**
00227    * \param f  a parameterless function to be created as a process instance
00228    * \param arg an integer argument to be assigned to this process instanace
00229    * \param level assigned scheduling level: SYSTEM, PERIODIC or RR
00230    * \param name assigned PERIODIC process name
00231    * \return 0 if not successful; otherwise non-zero.
00232    * \sa Task_GetArg(), PPP[].
00233    *
00234    *  A new process  is created to execute the parameterless
00235    *  function \a f with an initial parameter \a arg, which is retrieved
00236    *  by a call to Task_GetArg().  If a new process cannot be
00237    *  created, 0 is returned; otherwise, it returns non-zero.
00238    *  The created process will belong to its scheduling \a level.
00239    *  If the process is PERIODIC, then its \a name is a user-specified name
00240    *  to be used in the PPP[] array. Otherwise, \a name is ignored.
00241    * \sa \ref policy
00242    */
00243 int   Task_Create(void (*f)(void), int arg, unsigned int level, unsigned int name);
00244 
00245 /**
00246  * Terminate the calling process
00247  *
00248  *  When a process returns, i.e., it executes its last instruction in
00249  *  the associated function/code, it is automatically terminated.
00250  */
00251 void Task_Terminate(void);
00252 
00253 /** Voluntarily relinquish the processor. */
00254 void Task_Next(void);
00255 
00256 /** Retrieve the assigned parameter.
00257   * \sa Task_Create().
00258   */
00259 int Task_GetArg(void);
00260 
00261   /*=====  Events API ===== */
00262 
00263 /**
00264  * \return a non-NULL Event descriptor if successful; NULL otherwise.
00265  *
00266  *  Initialize a new, non-NULL Event descriptor.
00267  */
00268 EVENT *Event_Init(void);
00269 
00270 /**
00271   * \param e  an Even descriptor
00272   *
00273   * Wait for the next occurrence of a signal on \a e. The calling process always blocks.
00274   */
00275 void Event_Wait( EVENT *e );
00276 
00277 /**
00278   * \param e an Event descriptor
00279   *
00280   * Resume a \b single waiting task on \a e. It is a \a no-op if there is no waiting process.
00281   * \sa Event_Wait()
00282   */
00283 void Event_Signal( EVENT *e );
00284 
00285 /**
00286   * \param e  an Event descriptor
00287   *
00288   * Resume \b ALL waiting tasks on \a e. It is a \a no-op if there is no waiting process.
00289   * \sa Event_Wait()
00290   */
00291 void Event_Broadcast( EVENT *e );
00292 
00293 
00294 /**
00295   * \param e  an Event descriptor
00296   *
00297   * Resume a waiting task on \a e and at the same time relinquish the processor.
00298   * This is equivalent to "Event_Signal( e ); Task_Next()" in concept. The
00299   * fundamental difference is that these two operations are performed as
00300   * an indivisible unit. So conceptually, the calling task resumes another
00301   * waiting task and gives up its share of the processor simultaneously.
00302   * \sa Event_Signal(), Task_Next()
00303   */
00304 void  Signal_And_Next( EVENT *e );
00305 
00306 /**
00307   * \param e  an Event descriptor
00308   *
00309   * Resume \b ALL waiting tasks on \a e and at the same time relinquish the processor.
00310   * This is equivalent to "Event_Broadcast( e ); Task_Next()" in concept.
00311   * \sa Event_Broadcast(), Task_Next()
00312   */
00313 void  Broadcast_And_Next( EVENT *e );
00314 
00315 #endif /* _OS_H_ */

Generated on Tue Oct 23 21:49:51 2007 for RTOS by  doxygen 1.5.1