Documente Academic
Documente Profesional
Documente Cultură
3;5269HUVLRQ
9HUVLRQ
Users Guide
7DEOH2I&RQWHQWV
1 Introduction.................................................................................................................9
1.1 PXROS................................................................................................................9
1.2 The Users Guide...............................................................................................10
2 PXROS.....................................................................................................................13
2.1 Structures and Mechanisms..............................................................................14
2.2 PXROS Objects.................................................................................................16
2.2.1 Tasks..........................................................................................................16
2.2.2 Messages...................................................................................................17
2.2.3 Mailboxes...................................................................................................17
2.2.4 Memory Classes.........................................................................................17
2.2.5 Object Pools...............................................................................................18
2.2.6 Delay Objects.............................................................................................18
2.3 Name Conventions............................................................................................18
2.3.1 PXROS Services........................................................................................18
2.3.2 PXROS Data Types, Macros, ....................................................................20
3 Tasks........................................................................................................................21
3.1 Creating Tasks with a Standard Function..........................................................22
3.2 Task Code.........................................................................................................23
3.3 Task Communication.........................................................................................25
3.3.1 Data Communication via Messages...........................................................25
3.3.2 Signalling Events........................................................................................25
3.4 Killing Tasks......................................................................................................26
4 Building the Sample Programs.................................................................................27
4.1 Process.............................................................................................................27
4.2 Initialization Phase............................................................................................28
5 Communication through Messages..........................................................................29
5.1 Summary...........................................................................................................29
5.2 Generating Messages.......................................................................................30
5.3 Writing and Evaluating Message Data..............................................................31
5.4 Sending and Receiving Messages....................................................................32
5.5 Releasing Messages.........................................................................................33
5.6 Using an Existing Data Area..............................................................................36
5.7 Message Pools..................................................................................................38
5.8 Examples...........................................................................................................40
5.8.1 ex1.c...........................................................................................................40
5.8.2 ex2.c...........................................................................................................43
5.8.3 ex3.c...........................................................................................................45
5.8.4 ex4.c...........................................................................................................48
6 Events.......................................................................................................................51
6.1 Summary...........................................................................................................51
6.2 Signalling Events...............................................................................................52
6.3 Waiting for Events.............................................................................................52
6.4 Resetting Events...............................................................................................53
6.5 Other Functions.................................................................................................54
6.5.1 Parallel Waiting..........................................................................................54
6.5.2 Aborting Functions with Events..................................................................54
6.6 Examples...........................................................................................................55
6.6.1 ex.c.............................................................................................................55
6.6.2 ex2.c...........................................................................................................57
7 Memory Management...............................................................................................59
7.1 Summary...........................................................................................................59
7.2 Memory Requests.............................................................................................59
7.3 Memory Classes................................................................................................60
7.3.1 Creating Memory Classes..........................................................................60
7.3.2 Memory Classes with a Variable Block Size..............................................61
7.3.3 Memory Classes with a Fixed Block Size...................................................62
7.3.4 Allocating and Releasing Memory..............................................................62
7.4 Use of Different Memory Classes in the System...............................................63
7.5 Tips for Developers...........................................................................................64
7.6 Examples...........................................................................................................64
7.6.1 ex1.c...........................................................................................................64
7.6.2 ex2.c...........................................................................................................65
8 PXROS Time............................................................................................................67
8.1 Summary...........................................................................................................67
8.2 PXROS Time Base............................................................................................67
8.3 Standard Services.............................................................................................68
8.3.1 Timeouts....................................................................................................68
8.3.2 Periodic Events..........................................................................................69
8.4 Delay Jobs.........................................................................................................70
8.4.1 Delay Job Resources.................................................................................70
8.4.2 Starting a Delay Job...................................................................................71
8.4.3 Cancelling a Delay Job...............................................................................73
8.5 Examples...........................................................................................................74
8.5.1 ex1.c...........................................................................................................74
8.5.2 ex2.c...........................................................................................................76
8.5.3 ex3.c...........................................................................................................77
8.5.4 ex4.c...........................................................................................................79
8.5.5 ex5.c...........................................................................................................80
9 Mailboxes..................................................................................................................83
9.1 Summary...........................................................................................................83
9.2 Creating Mailboxes............................................................................................83
9.3 Mailbox Handlers...............................................................................................84
9.4 Examples...........................................................................................................85
9.4.1 ex1.c...........................................................................................................86
10 Objects and Object Pools.......................................................................................89
10.1 Summary.........................................................................................................89
10.2 Generating Object Pools.................................................................................90
10.2.1 Virtual Object Pools..................................................................................91
10.2.2 Real Object Pools....................................................................................91
10.3 Generating Additional Objects.........................................................................92
10.4 Using Different Object Pools in the System....................................................92
10.5 Other Services.................................................................................................93
10.6 Examples.........................................................................................................93
10.6.1 ex1.c.........................................................................................................93
10.6.2 ex2.c.........................................................................................................95
11 Interrupt Interface...................................................................................................97
12 Error Handling.........................................................................................................99
12.1 Summary.........................................................................................................99
12.2 Runtime Errors................................................................................................99
12.3 Application Errors..........................................................................................100
12.4 Example........................................................................................................100
12.4.1 ex1.c.......................................................................................................101
13 Scheduling............................................................................................................103
13.1 Summary.......................................................................................................103
13.2 Hardware Interrupt Handlers.........................................................................103
13.3 Software Interrupt Handlers..........................................................................104
13.4 Task Scheduling............................................................................................104
13.4.1 Tasks of Equal Priority...........................................................................105
13.4.2 Special Types.........................................................................................105
13.5 Example........................................................................................................105
14 Creating Tasks......................................................................................................107
14.1 ts_name.........................................................................................................108
14.2 ts_fun.............................................................................................................108
14.3 ts_mc.............................................................................................................108
14.4 ts_opool.........................................................................................................109
14.5 ts_taskstack...................................................................................................109
14.5.1 Automatic Stack Request.......................................................................110
14.5.2 Explicit Stack Allocation.........................................................................110
14.5.3 Choosing a Stack Size...........................................................................110
14.6 ts_tblimit........................................................................................................111
14.7 ts_prio............................................................................................................111
14.8 ts_actevents..................................................................................................112
14.9 ts_timeslices..................................................................................................112
14.10 ts_abortstack, ts_abortstacksize.................................................................112
14.11 ts_sched_extension, ts_sched_initarg........................................................114
14.12 ts_privileges.................................................................................................114
14.13 ts_int_dummies...........................................................................................114
14.14 ts_context....................................................................................................114
14.15 ts_addr_dummies........................................................................................114
14.16 Features of the Initialization Task................................................................114
14.17 Example......................................................................................................115
15 PXROS Initialization.............................................................................................117
15.1 A Standard Initialization.................................................................................117
15.2 Initialization Details........................................................................................118
15.2.1 is_sysmc_type,is_sysmc_size................................................................119
15.2.2 is_sysmc_blk, is_sysmc_blksize............................................................119
15.2.3 is_obj_number, is_obj_namelength.......................................................119
15.2.4 is_inittask...............................................................................................119
15.2.5 is_monitoring..........................................................................................120
15.2.6 is_int_dummies......................................................................................120
15.2.7 is_schedext............................................................................................120
15.2.8 is_addr_dummies...................................................................................121
15.3 Example........................................................................................................121
16 Common Task Data..............................................................................................123
16.1 Example........................................................................................................124
16.1.1 Ex1.c......................................................................................................124
17 Abort Mechanism..................................................................................................127
17.1 Summary.......................................................................................................127
17.2 Using the Abort Mechanism..........................................................................127
17.3 Activation and Deactivation of the Abort Mechanism ....................................128
17.4 Implicit deactivation with PXROS Services...................................................129
,QWURGXFWLRQ
3;526
PXROS (pronounced pixros), is the acronym and stands for 3ortable e;tendible
5 ealtime 2perating 6ystem. It is a realtime operating system kernel and may be used
as a platform for a variety of realtime applications. PXROS services are provided in
libraries. This means the the code corresponds largely to the functionality needed.
Two libraries are used for developing applications: the GHEXJ library, used in the
development stage, and the SURGXFWLRQ library, which is used for the completed project.
Both libraries offer the application the same interface and functionality, the difference
lying in the service testing perfomed. To detect errors in the early stages of
development, PXROS conducts extensive checks and tests when executing services
from the debug library. These tests however, increase the run time and the code
requirements; therefore, the production library is used once development is completed.
The production library does not perform these tests, thus providing better run time
performance and lower code requirements.
In addition to standard PXROS, other versions exist with extended functionality. These
include a multiprocessor communication version, a version that provides priority-based
semaphores, and a version extends the normal scheduling with time slicing. Most of
these extended services are not described in this Users Guide.
PXROScompact is another PXROS variation. It differs from the standard version mainly in
that tasks and PXROS objects can not be generated dynamically. The applications
structure must be defined statically. Fewer services means less code, thereby reducing
the size of the final application. PXROScompact is useful in small applications with very
limited space for code. The Users Guide describes the full-featured PXROS services
and does not deal with PXROS compacts features specifically.
3;PRQ is a debugging tool used in conjunction with PXROS. It allows the developer to
examine and alter memory locations and variables while UXQQLQJ the application.
PXmon recognizes internal PXROS structures and provides specific PXROS
information about resource consumption, the state of tasks, or the scheduling of the
system. The extended version, 3[PRQ57 offers UHDOWLPH GHEXJJLQJ during final
testing, including task-specific breakpoints and single-stepping tasks (i.e. without
stopping the whole system). PXmon is described in detail in chapter 21.
7KH8VHU
V*XLGH
The next two chapters briefly introduce PXROS structures and its underlying
mechanisms, as well as some of the more important terms used. This introduction is
intended to prepare you for the following chapters and should not be ignored.
Individual PXROS mechanisms and the services related to them, are explained later in
the corresponding chapters. Each chapter begins with a summary of the most
important information. Processes and various services are briefly described, followed
by detailed explanations of the subject and a full-length description of the relevant
services. At the end of most chapters, the Users Guide contains a description of
sample programs related specifically to the subjects at hand. Their source code can be
found on the accompanying disk. These programs should illustrate specific aspects of
use in relation to the services concerned. The starting phase and the basic execution of
all of the sample programs are similar. For this reason, they are explained in a separate
chapter.
Beginning with chapter 16, information not absolutely necessary to become acquainted
with PXROS is presented. These chapters are intended for advanced PXROS users.
They explain services that make use of processor-specific properties, as well as
services generally considered beyond PXROS standard usage.
As reader of the Users Guide, you should try to implement your own applications as
soon as possible. To do so, one should obtain a general overview of the structures and
mechanisms used in PXROS applications. Users are advised to read the summary at
the beginning of each chapter, and examples at the end. It is also advisable to compile
and run the sample programs on a target system. In this way, the description of the
program flow can be more easily understood, especially when using a debugger (e.g.
JGE). Afterwards, one might implement and experiment with smaller applications. At
this point, one generally runs across questions that can usually be answerd by reading
the detailed service descriptions.
Beginners can generally ignore the subjects at the end of the Users Guide as they
describe concepts only important in more complex applications.
An additional utility library disk, including source code, is also available from HighTec
and can be used to help implement PXROS applications. The utility services are
explained in the final chapter. Together with the source code, these explanations can
provide you with further hints for using PXROS functions.
The Users Guide is intended to help you work your way into PXROS. It can only do so
if it meets the readers needs. For this reason, we depend on your assistance in
improving the Users Guide: please report any mistakes you might find, and let us know
if explanations are insufficient or lead to misunderstandings. We would appreciate any
suggestions or ideas you might have.
3;526
PXROS encourages a modular software design with its task concept: different parts of
the application are implemented independently from one another. PXROS allows these
programs to run in quasi-parallel in units called WDVNV. Each task runs within its own
execution context, and thus inherits all associated administrative problems (e.g. the
allocation of processor time, and the reconstruction of the execution context for the
running task).
In summary, PXROS works with a series of small, manageable functional units called
tasks. In addition to coordinating the tasks, the operating system provides the
foundation upon which the application runs. Finally, PXROS offers a number of
services for managing the application and the interaction of its inividual components.
6WUXFWXUHVDQG0HFKDQLVPV
The scheduling principle dictates that higher priority tasks may always interrupt lower
priority tasks to execute their functions.
Priorities
high priority
Tasks
(mutually interrupting based on their respective task priorities)
low priority
Tasks do not make up all of the applications functions. Highly critical functions (with
respect to time) are performed by functional units called KDQGOHUV.
These include, for example, interrupt routines that intercept hardware interrupts and
periodically-activated regulator routines. Handlers are processed at a higher priority
than tasks, i.e. a handler may always interrupt a running task; in contrast however,
hardware interrupt handlers not only interrupt tasks, but software interrupt handlers as
well. In fact, hardware interrupt handlers even interrupt the operating system itself!
Handlers interrupt other handlers based on the priority level of their respective
hardware interrupts. In other words, a higher priority handler may interrupt a lower
priority handler. This hierarchy does not exist among software interrupt handlers, which
may not interrupt one another. Software interrupt handlers run in parallel as "equals"
and are scheduled according to a "first come, first served" algorithm.
A task rarely works in isolation; rather, it is usually associated with other tasks or
handlers. For example, tasks may cooperate with other tasks by requesting information
from them, a handler may inform the task that a hardware signal has been intercepted,
or a task may regulate a handlers work. PXROS provides the two important
mechanisms for transferring data between tasks and handlers: PHVVDJHV and VLJQDOV.
During PHVVDJH H[FKDQJH, one tasks data are prepared as a message, which is then
sent to a mailbox. A second task receives the message, at which point the message is
evaluated. PXROS provides the necessary services to create, send and receive
messages. Except in special versions of PXROS, the mailbox services are only
available to tasks (i.e. they may not be used by handlers).
$VDPSOHDSSOLFDWLRQ
Implement a system control program which receives instructions via a PCs serial
interface:
System requirements:
R eceive-Interrupt
U ser Interfacer (S erial Interface)
T ask 1
T ransm it-Interrupt
(S erial Interface)
Job R equests
and
R esponses
While Task2 processes jobs and the periodic handler, Task1 is able to continue
receiving messages, thus allowing jobs to be cancelled. Allocating two separate tasks
allows one to logically implement the control and communication modules separately.
Also, by changing the software interface to the PC (or other hardware device), the task
can be used in other applications without modification.
PXROS not only offers services for exchanging data, it administers dynamically
allocatable memory. Furthermore, PXROS is equipped with a system clock for time-
based routines. The use of RQO\ RQH periodic interrupt source (e.g. the hardware timer)
allows the application to fulfill the systems realtime requirements. The application fixes
the system clocks frequency, thus keeping the system load to a minimum.
3;5262EMHFWV
Most PXROS services are associated with either related a task or a PXROS REMHFW
PXROS services FUHDWH or GHOHWH all PXROS objects. Additionally, PXROS provides
other special services for using the different object types. To ensure security, all
changes to objects must be performed via PXROS services. When an object is
created, it receives an LGHQWLILHU from PXROS which clearly sets it apart from other
PXROS objects.
Certain special objects are available in special PXROS versions, such as priority-based
VHPDSKRUHV , which provide communication via semaphores, or FKDQQHOV which permit
communication with PXROS objects residing on other processor. These object types
are not provided with the standard version of PXROS and are therefore not dealt with in
the Users Guide.
7DVNV
0HVVDJHV
0DLOER[HV
A mailbox stores messages in the order they arrive, until they are withdrawn and
evaluated. A task always receives the message that has been stored in the mailbox the
longest (one exception: SULRULWL]HG PHVVDJHV are released before other messages). If
the queried mailbox is empty, the task has the option to wait until a message arrives. In
some cases, a a number of tasks may wait at the same mailbox for a message to
become available. The task with the longest waiting period receives any message
arriving. One can not specify which message a task receives upon arrival at the
mailbox.
0HPRU\&ODVVHV
Memory classes are classified as either YDULDEOH or IL[HGVL]H memory classes. Using
fixed size memory classes improves the processing speed for memory administration.
In contrast, variable size memory classes are more flexible, but can lead to PHPRU\
IUDJPHQWDWLRQ. This occurs when the memory is divided into a number of little blocks
2EMHFW3RROV
All unused PXROS objects are kept in object pools. Objects can be
distributed to different object pools, from where they are in turn
assigned to certain parts of the application. In this way, resource can
be contained locally. Every PXROS application uses a V\VWHP SRRO,
which initially contains all objects generated, and from which objects
for other object pools can be drawn.
PXROS differentiates between two types of object pools: UHDO and YLUWXDO object pools.
Real object pools serve to physically divide objects into different pools. Virtual object
pools on the other hand, are merely an abstraction useful for restricting and controlling
access to objects.
When the application requests objects, it must always specify the object pool from
which the object is to be taken. The macro
3;2SRRO6\VWHPGHIDXOW indicates the system pool.
'HOD\2EMHFWV
1DPH&RQYHQWLRQV
3;5266HUYLFHV
Px[class][verb][object][extension]
PXROS services can be easily recognized by the prefix 3[ . This avoids confusion
between these and other routines.
>FODVV@ defines the type of object the service operates on. Service classes include:
7DVN : task
0VJ : messages
0E[ : mailboxes
0F : memory classes
2SRRO : object pools
'HOD\ : delay objects
If a name does not specify a class, the service usually operates on the calling task.
>REMHFW@ indicates which part of the service is concerned and is dependent on the class.
For example, B+QG indicates that the service variant can only be used by handlers.
Certain PXROS services may only be called by tasks, others by both handlers and
tasks. In the latter case, the services often have two variants: one for use by tasks, and
the other specially optimized for use on handler level. In this case, the names
extension is BB+QG, and the service may only be used by handlers, otherwise PXROS
will report an error.
B(Y:DLW is another extension that indicates a service that can enter a ZDLW VWDWH to e.g.
receive an object. The wait state is cancelled if e.g. certain user-defined events occur.
The functions return value contains the events that led to termination of the wait state.
([DPSOHV
3;526'DWD7\SHV0DFURV
Important data types defined by PXROS are called LGHQWLILHUV, or simply ,Gs. Upon their
creation, PXROS assigns all tasks and objects a specific Id. A data type name is
recognized by its form form:
3[>FODVV@BW
3[7DVNBW task Id
3[0VJBW message Id
3[0E[BW mailbox Id
3[0FBW memory class Id
3[2SRROBW object pool Id
3['HOD\BW delay object Id
In general, a data type with a lower case "t" (i.e 3[BW) indicates a "small" data type
(<= 8 bytes), while "large" data types (> 8 bytes) are specifed by the upper case "T"
(3[B7. For example, PXROS defines a structure called PxTaskSpec_T. A pointer to
this structure is of the type 3[7DVN6SHFBW 3[7DVN6SHFB7
The prefix 3; indicates a macro, and serves to distinguish the macro from function
calls, which use the prefix 3[. For example, the system memory class can always be
accessed via the macro 3;0F6\VWHPGHIDXOW
7DVNV
Each task is always in one of two states: ZDLWLQJ or UHDG\. The tasks that are ready
compete for control over the processor (i.e. to execute their program code). PXROS
activates the task with highest priority. This task retains control until it returns to a wait
state, or until a task with a higher priority becomes ready. Normally tasks are only
active for a relatively short time, as high-priority tasks interrupt lower-priority tasks.
PXROS scheduling mechanism is explained in detail in chapter 13.
A tasks change of state is DOZD\V related to PXROS services. An active task stops and
waits when directed to do so by certain services. For example, a task will switch to a
wait state to wait for a PXROS object to become available, or to wait for a signal that an
event has occurred. The task resumes processing e.g. once the event has been
signalled or the expected object becomes available.This will only happen if another
task or handler calls an applicable PXROS service.
&UHDWLQJ7DVNVZLWKD6WDQGDUG)XQFWLRQ
Tasks are created dynamically and receive an individual task Id from PXROS.
Various parameters can influence the creation of a task, although usually only a few of
these parameters are generally important. If this is the case the function
&UHDWH6WGWDVN can be used. When applied, this function automatically creates a task.
It only requires a few specific parameters, while default values are used to configurate
the remaining parameters.
7DVN,G is the functions output parameter. If the task is created successfully, this
parameter specifies the newly created tasks Id; otherwise, TaskId is .
The parameter QDPH specifies the tasks name. This parameter is employeded by the
debugger when the realtime monitor 3;PRQ is used. name can not be used to specify
the task within an application.
7DVNIXQF is a function that is assigned to the task. This is given as code to be executed
and must fulfill specific requirements, e.g. it has a fixed prototype. Section 3.2
describes this parameter in greater detail.
SULR specifies the tasks priority. The highest possible priority is and the lowest
depends on the processor and the PXROS variant used (usually or ). Only the
tasks relative priorities are important for PXROS scheduling; their absolute values are
irrelevant. There are no strict guidelines for assigning task priorities. The following may
serve as a rough guide. Tasks with a small buffer, tasks that perform time-based or
hardware-related duties, and tasks that are used as servers for other tasks should
generally receive relatively high priorities. Tasks that perform hardware independent
duties, e.g. evaluating data for statistics, operating displays or permanent safety checks
(ROM check) usually receive lower priorities.
As previously mentioned, each task has its own stack. The parameter VWNVL]H fixes the
stack size in the size of an LQWHJHU. The stack size depends on the task code: each
function in a nested call increases the tasks demand for stack space. For example,
space in the stack is required for the function prologue. All local variables and (if
necessary) parameters are placed on the stack as well. This can make it difficult to
estimate stack size requirements at the beginning of development.
If the task stack is too small, it can lead to run time errors that are difficult to locate. For
example, this may cause arbitrary memory locations to be overwritten. Although
PXROS checks for stack overflow (in the debug library) whenever a PXROS service is
called, this does not ensure that every stack overflow will be detected. With this in
mind, VWNVL]H should be allocated generously if there is sufficient memory available. As
the final development phase is reached, the developer can always optimize these
values.
A tasks maximum stack requirements can be determined with the help of the PXmon,
and VWNVL]H can be modified accordingly.
7DVN&RGH
PXROS starts this function when newly created tasks are activated. The parameters
are set by PXROS and have the following meaning:
P\LG is the task Id generated during task creation. This can be important information in
a message inteded for another task. The service 3[*HW,G shows the Id of the running
task.
Once created, a mailbox is automatically created to serve as the tasks SULYDWH PDLOER[,
i.e. P\PE[. This contains the private mailboxs ,G, where the task usually waits to
receive messages from other tasks. 3[7DVN*HW0E[ shows the Id of a tasks private
mailbox.
After its creation, a task is usually UHDG\ to execute its code. If it has a higher priority
than the creating task, the created task immediately becomes active. One might also
specify DFWLYDWLQJ HYHQWV when creating a task. In this case, the task begins in a wait
state and becomes ready as soon as one of these events is signalled. P\HYHQWV
contain events through which the task is started. Tasks that are created by
CreateStdtask do not have activating events, i.e. they always begin in a ready state and
their parameter P\HYHQWV LVVHWWR.
The task code itself has a typical PXROS task design. The task initializes itself and
finds itself in what can be said to be an endless loop. This starts with the task waiting
for messages from other tasks, and/or the signalling of events to it. Once they are
received, the messages and/or events are evaluated and processed. Afterwards, the
task returns to a wait state.
for (;;)
{
WAIT_FOR_MESSAGES_AND_EVENTS;
PROCESS_EVENTS;
PROCESS_MESSAGE;
CLEANUP;
}
}
A task (or group of tasks) will generally make up only part of the whole system (e.g. the
hardware involved). This should always be initialized during the respective tasks
initialization phase, for example during a central initialization. In this way, changes are
contained locally to the respective tasks.
TaskFunc may QHYHU be left, meaning it must not reach the closing brace at the end of
the task code. Tasks are not usually terminated; rather, tasks normally remain active to
complete jobs. However, there are ways to terminate tasks (see section 3.4).
The most simple PXROS task (i.e. with no function) has the following form:
If such a task becomes active, it blocks all tasks with lower or equal priorities. Only
handlers or high priority tasks can become active!
7DVN&RPPXQLFDWLRQ
A task usually does not exist in isolation within an application. It requires information
from other tasks or handlers, and it often must pass data on to other tasks. Information
is exchanged via the PHVVDJH WUDQVIHU or HYHQW VLJQDOOLQJ. This will be covered in detail
in chapters 5 and 6, which describe the principle working methods used. In addition to
messages and signals, tasks can swap data over shared memory locations; however,
PXROS has no control over this method of communication. Using shared memory
places the responsibility for synchronization and data integrity entirely in the
applications hands.
'DWD&RPPXQLFDWLRQYLD0HVVDJHV
To VHQG data, a task needs a message. A task can either create it itself, or it can reuse
a message it has already received. Data will be written to the message and the
message can then be sent. Remember, a message is always sent to a mailbox, i.e. it is
never sent directly to a task.
6LJQDOOLQJ(YHQWV
A task waits for specific events when a corresponding PXROS service is called, for
HighTec EDV-Systeme GmbH 24 20. Mai 1996
PXROS V4 Users Guide Version 1.0
example 3[$ZDLW (YHQWV. This call places the task into a ZDLWLQJ state. Once one of
the expected events has been signalled, the task is made UHDG\ again, the function
returns and the task can evaluate the event.
.LOOLQJ7DVNV
,PSRUWDQW When killing a task, the task code must QRW be exited using UHWXUQ.
When a task is killed, it releases all memory and/or PXROS objects it may have used,
such that they are again at the systems disposal. By calling 3['LH, the task is
terminated by the GLH VHUYHU (a special task). Furthermore, the die server releases
system resources that were used while creating the task. In this way, a task can be
killed without the system losing resources.
In order to kill a task, the die server must permanently occupy system resources itself,
i.e. it is implemented as a task. For this reason, using a die server in an application only
makes sense if several tasks must be killed. If only one task is to be killed within the
system, we recommend placing task into a permanent wait state. This can be achieved
by calling the function 3[$ZDLW(YHQWV (see chapter 6). The system resources for
that task will remain unavailable, but the task is out of operation.
%XLOGLQJWKH6DPSOH3URJUDPV
This chapter describes PXROS individual mechanisms and services. There are sample
programs located throughout the Users Guide. These are quite useful for introducing
various concepts and services, and to demonstrate how they are applied. At the end of
most chapters, the execution of a sample program is described to illustrate various
services. All of the sample programs are structured similarly:
At the beginning of these examples, PXROS is initialized, two tasks are created and,
with the help of a hardware timer, the system clock is installed. The initialization is then
completed and the tasks created become active. The starting phase is the same for all
sample programs. They differ only in their respective task functions, each of which uses
services described in chapter being read. The descriptions in future chapters are
confined to the two tasks created in the relevant sample program, as these tasks
underscore the use of the concepts defined in each chapter. This chapter describes the
starting phase and initial processes performed in the examples.
3URFHVV
The task priorities in the sample programs are set such that the initialization task has
the highest priority, and Task1 has a higher priority than Task2. As implied, the
initialization task stays active after the other two tasks have been created.
Once the initialization phase is completed, the initialization task automatically lowers its
priority. At this point, Task1 has the highest priority and is in a ready state. This task
runs its code until it passes into a wait state, at which point Task2 becomes active.
Once Task1 is ready again (i.e. its wait condition has been fulfilled), the task is
reactivated and Task2 is interrupted. After lowering its priority, the initialization task is
only run if both Task1 and Task2 are waiting.
,QLWLDOL]DWLRQ3KDVH
The C-code for the starting phase is the same for all sample programs:
void main ()
{
/*Initialize PXROS and create 2 tasks */
if (BspInit (&Task1Id, &Task2Id))
{
PxPanic ();
}
/* Stack PXROS Time Base */
TicksInit ();
/* Idle Loop */
for (;;) ;
}
In the examples, initialization is performed withhin the function %VS,QLW. The source
code is in EVSLQLWF, which can be found in the directory LQLW on the accompanying disk.
%VS,QLW is described in detail in the section 15.1. This chapter assumes a greater
After PXROS has been initialized, two tasks are created in %VS,QLW. Their task codes
are two C-functions called 7DVN)XQF and 7DVN)XQF respectively. Each contains the
functions required by the sample programs. After the tasks have been created, their Ids
are passed by reference as 7DVN,G and 7DVN,G respectively.
Once initialization is completed in %VS,QLW, the system clock is installed with 7LFNV,QLW.
It is reactivated at regular intervals through periodic incrementations from the function
3[7LFN'HILQHB+QG . Operating the system clock requires programming a processor
timer. For this reason, 7LFNV,QLW is dependent on the processor used. The hardware
dependent variants for this function can be found on the accompanying disk in the
directory WLPHGHI. These variants are called WLFNVQDPH!F, where <name> refers to
the respective processor. WLFNVF contains the 7LFNV,QLW program code for a
Siemens C166 processor, WLFNVF is the variant for a C167 and 7LFNV,QLW is written
for an 80386 processor in WLFNVF.
At the end of the starting phase, the initialization task lowers its priority (via a call to
3[7DVN6HW3ULR ) to the value 0,135,2 (i.e. a low priority value). In addition to the new
priority, 3[7DVN6HW3ULR also needs the tasks Id (i.e. the task whose priority is to be
changed). The example illustrates how this Id can be obtained from the service
3[*HW,G.
&RPPXQLFDWLRQWKURXJK0HVVDJHV
6XPPDU\
In using the function 3[0VJ5HTXHVW PVJ VL]H PF RSRRO, the application requests
the message PVJ with a data area of VL]H bytes in size. The memory requested for the
data area is taken from the memory class PF, and the memory used for the message
object originates from the object pool RSRRO. The function 3[0VJ*HW'DWD PVJ
provides the address of the data area associated with the message PVJ thus telling
the calling task where to write its data. The function 3[0VJ6HQG PVJ PE[ sends
the message PVJ to the mailbox PE[
A task waits at the mailbox PE[ with the function 3[0VJ5HFHLYH PVJ PE[. As soon
as a message arrives, the function returns with the message PVJ 3[0VJ*HW'DWD
allows the task to access and evaluate the messages contents. The task can then
release the message using the 3[0VJ5HOHDVHPVJ service. This returns the memory
used by the message to the appropriate memory class, as well as returning the
messages message object to the object pool from which it originated (i.e. from the call
to 3[0VJ5HTXHVW). As mentioned above, the message can be given new data and
reused.
The process of message exchange is similar to writing letters: one buys an envelope
(request a message object) and paper (requesting memory for data). The letter is given
(PxMsgSend) to the post office (PXROS), which delivers the letter to a mailbox (a tasks
mailbox). Having waited for it to arrive, the user removes the letter from the mailbox
(PxMsgReceive) and reads it. The envelope and paper are then either recycled
(PxMsgRelease) or re-used for a new letter. Fortunately, PXROS uses erasable ink on
its paper! :^)
With this comparison in mind, certain application errors can be avoided: after the letter
has been sent, it is no longer available. If letters are repeatedly produced and not
recycled, resources become scarce. Also, keep in mind that PXROS messages are
always sent to a mailbox and not directly to a task.
*HQHUDWLQJ0HVVDJHV
In addition to the standard service, PxMsgRequest, there are two other variants
available:
When the object pool is empty, 3[0VJ5HTXHVWB1R:DLW does not wait for an object to
become available. It immediately returns with the error indication
3;(55B2%-B122%-. 3[0VJ5HTXHVWB(Y:DLW , on the other hand, either waits until
an object becomes available in the object pool RSRRO, or until one of the predefined
events in HYHQWV is signalled to a task. If no message object was made available, the
value of
0VJequals in all variants.
([DPSOH
PxError_t fun()
{
PxMsg_t msg;
PxError_t err;
:ULWLQJDQG(YDOXDWLQJ0HVVDJH'DWD
([DPSOH
typedef struct {
PxUInt_t opcode;
PxUInt_t sender;
....
PxUChar_t *data;
} Request_T;
ReceiveTask(...)
{
PxMsg_t msg;
Request_T *req;
....
/* Get Message; Id in msg */
req = (Request_T *) PxMsgGetData(msg);
switch(req->opcode)
{
case...:
....
}
}
6HQGLQJDQG5HFHLYLQJ0HVVDJHV
The service 3[0VJ6HQG0VJPE[sends the message 0VJ to the mailbox PE[
Messages are stored in a mailbox in the order they arrive. The message that arrived
first is released first. Using 3[0VJ6HQGB3ULR a prioritized message is dealt with first.
3[0VJ6HQG can only return an error code when a PDLOER[ KDQGOHU is installed at the
mailbox. The handler is activated before the message enters the mailbox. The handler
can either reject or accept the message. 3[0VJ6HQG returns the mailbox handlers
error code, thus allowing the caller to recognize why the message was refused (see
chapter 9.3).
PxMsgSend PxMsgReceive
Task
Task
Task
Task
Task
A task withdraws a message from the mailbox PE[ using the function 3[0VJ5HFHLYH
0VJ 0E[ If the mailbox is empty, the task waits. Several tasks can wait at the same
mailbox at the same time. Once a message arrives, it is given to the task that has been
waiting the longest, and the remaining tasks a served on a first-come, first-served
basis.
In addition to the standard service, 3[0VJ5HFHLYH, there are two other variants: (1) If
the mailbox is empty, 3[0VJ5HFHLYHB1R:DLW does not wait for the message to arrive.
The error identifier PXERR_MSG_NOMSG is returned immediately. (2)
3[0VJ5HTXHVWB(Y:DLW waits until either a message is received, or one of the events
is signalled to a task from HYHQWV. In either case,
0VJ has the value of , if no
message was taken from the mailbox.
5HOHDVLQJ0HVVDJHV
When a task has received and processed a message, it can either reuse or release it
with 3[0VJ5HOHDVH PVJ When this service is applied, the occupied resources are
returned to the systems disposal once again.
([DPSOH
SendTask ()
{
PxMsg_t msg;
....
PxMsgRequest (&msg, 100, PXMcSystemdefault,
PXOpoolSystemdefault);
....
PxMsgSend (&msg, mbx);
....
}
3[0VJ5HTXHV 3[0VJ6HQ
Task
Task
3[0VJ5HDOHDV 3[0VJ5HFHLY
When a message is processed, the receiving task often sends a message itself, e.g. to
return requested data. In this case, it would be uneconomical to release the message
with the job request and then create a new message. Instead, the message that is
received should be reused. It is especially conveniant if the space for the requested
data is already provided in the messages data area. After processing, the task need
only enter the requested data in the provided area and return the message to the
original sender.
([DPSOH
typedef struct {
PxUInt_t opcode;
PxUInt_t sender;
PxMbx_t answmbx;
PxUInt_t result;
....
PxUChar_t *data;
} Request_T;
{
PxMsg_t msg;
Request_T *data;
....
....
PxMsgReceive (&msg, mymbx);
data = (Request_T *) PxMsgGetData (msg);
Even if a message must be restructured, it still can be reused. In this case, the data
area must be of sufficient size to accommodate the new data. This can be determined
by with the function 3[*HW%XIIHUVL]HPVJ
8VLQJDQ([LVWLQJ'DWD$UHD
Often the messages program data is "ready to be sent" as the message is requested
with 3[0VJ5HTXHVW. The task cannot simply provide the datas location; it must copy
the data into the messages memory area. Requesting memory and copying the data
increase run time. If the message only receives a data pointer, the process of copying
is avoidable. The two tasks must coordinate the access to the memory area they share.
In this case, requesting messages still requires memory.
To avoid these problems, the application can also create messages with
3[0VJ(QYHORS This service requests a message object and allocates it a predefined
memory area; i.e. QR PHPRU\ LV UHTXHVWHG Using the service 3[$ZDLWV0VJUHO, the
sending task can recognize when a message was released, thus allowing it to reaccess
that data area. When a message is released, PXROS only returns the object to the
object pool and the data area remains unchanged.
3[0VJ(QYHORS 0VJ GDWD VL]H RSRRO )ODJ requests a message object from the
object pool RSRRO The message object is allocated a memory area of VL]H bytes at the
address GDWD, and the message 0VJ is created. Memory is QRW requested, it must
already exist. )ODJ is the address of a variable, which PXROS sets to when a
message is being generated. Once the message is released, Flag is set to . In
addition to the conventional PXROS mechanisms, a service is available that allows a
task to wait for a messages release: 3[$ZDLW0VJUHO IODJ returns as soon as PXROS
sets
)ODJ to (i.e. when the requested message is released). Until then, the task
remains in a ZDLW VWDWH, and other tasks can become active. After a message is
released, the receiver of this message no longer has access to data; otherwise,
inconsistencies might occur. 3[$ZDLW0VJUHO returns, thus indicating that the data
access had been completed.
([DPSOH
typedef struct {
PxUInt_t opcode;
PxUInt_t sender;
PxUInt_t result;
....
PxUChar_t *data;
} Request_T;
Task1Func()
{
PxUChar_t flag;
Request_T req;
PxMsg_t msg;
....
req.opcode = ....
req.sender = myid;
....
PxMsgEnvelop (&msg, (void *) &req, sizeof(Request_T),
PXOpoolSystemdefault, &flag);
PxMsgSend (&msg, mbx);
....
PxAwaitMsgrel (&flag)
if (req->result == OK)
{
....
}
0HVVDJH3RROV
When a message is created, PXROS may have to wait for an object to become
available. Also, using 3[0VJ5HTXHVW to create a message requires memory, which is
not always available. Even when the request can be fulfilled, it may require time to
create the message. In some cases, the delays caused are not acceptable. These
problems can be avoided by creating messages in advance. In this way, if a message
is needed, it is immedialtely accessible (i.e. as long as not all of the messages are
being used). These "ready-made" messages are kept in a so called PHVVDJHSRRO:
can not be distinguished from other messages when taken from a mailbox.
When a message is no longer needed, it is usually released, the object returns to its
object pool, and the memory returns to its memory class. Message that originate from
message pools may not be deleted; they must return to the message pool after being
used. This ensures that the message pool is not emptied after a short time. This
precaution implies that the PXROS application must somehow distinguish between
messages. Within an application, messages can be differentiated as follows:
....
if ( ... ) /* message from message pool */
PxMsgSend (&msg, MsgPool);
else
PxMsgRelease (&msg);
....
This distinction is not really sufficient! For this reason, 3[,QVWDOO5HOPE[ PVJ PE[ is
applied. It defines the mailbox PE[ as the UHOHDVH PDLOER[ responsible for the message
PVJ,. This means that when 3[0VJ5HOHDVH PVJ is called, the message is not
relased; rather, it is sent back to the mailbox PE[. For messages from a message pool,
the pool should always be defined as the release mailbox. Now every message can be
released with 3[0VJ5HOHDVH, while PXROS ensures, when applicable, that the
message can return to the message pool.
If a release mailbox is already defined for a message, 3[,QVWDOO5HO0E[ fails. When the
parameterPE[ has the value the installation of a release mailbox is cancelled.
([DPSOH
PxMbx_t MsgPool;
Task1Func()
{
PxMsg_t msg;
....
PxMbxRequest (&MsgPool, ...);
....
for (i=1; i<=MSG_NO; i++)
{
PxMsgRequest (&msg, MSG_SIZE, ...);
PxMsgInstallRelmbx (msg, MsgPool);
PxMsgRelease (&msg);
/* PxMsgSend (&msg, MsgPool) is also possible */
}
....
}
Task2Func()
{
PxMsg_t msg;
....
....
PxMsgSend (&msg, PxGetMbx(Task3Id));
....
}
{
PxMsg_t msg;
....
PxMsgReceive (&msg, mymbx);
....
PxMsgRelease(&msg);
....
}
([DPSOHV
The source code for the following "data communications" sample programs can be
found in the directory FRPP on the accompanying disk.
H[F
Task1 and Task2 send each other a message that was originally generated by Task1.
Each task increments the value of a counter which is located within the messages data
area. When the counter reaches the value 100 the task that is momentarily in
possession of this message, releases it and subsequently, both tasks go into a state of
waiting.
Typedef struct {
PxMbx_t AnswerMbx;
PxUInt_t Counter;
} Request_T;
PxMsg_t msg;
PxMbx_t mbx;
Request_t *data;
for (;;)
{
(6) PxMsgReceive (&msg, mymbx);
7DVN)XQF
PxMsg_t msg;
PxMbx_t mbx;
Request_T *data;
for (;;)
{
(14) PxMsgReceive (&msg, mymbx);
(15) data = (Request_T *) PxMsgGetData(msg);
(16) if (data->Counter > 100)
{
(17) PxMsgRelease (&msg);
}
GHWDLOHGSURFHVVGHVFULSWLRQ
This contains a data area with the size of the message structure 5HTXHVWB7. The
resources for the messages are received from the system pool and the system memory
class.
GDWD is assigned the address of the messages data area. Now the message can be
provided with its contents:
The counter is initialized and Task1s private mailbox is specified in $QVZHU0E[ This
attribute represents the mailbox that is intended to receive the answer to the message.
sends the message to Task2s private mailbox. Task1 then waits to receive a message
at its private mailbox.
Task2 draws the message previously sent by Task1 from its private mailbox
Then both Task2 and Task1 wait for a message, and remain in this state.
If the counter does not exceed the value 100, Task2 uses PE[ (18) to save the mailbox
(i.e. where the answer is to be received). It specifies its private mailbox as the answer
mailbox (19). Also, the counter is incremented (20) and the message is sent to the
answer mailbox.
Task1 leaves the wait state and evaluates the message that it receives from Task2.
Task1 proceeds in the same way as Task2 did.
H[F
Task1 generates a message with PxMsgEnvelop, sends it to Task2 and waits for its
release through PxAwaitMsgrel. Task2 receives the message, changes the data, and
releases the message. In this way Task1 regains access to the data.
7DVN)XQF
PxMsg_t msg;
PxUInt_t result = 0;
PxUChar_t flag;
PxMbx_t mbx;
7DVN)XQF
PxMsg_t msg;
PxUInt_t *data;
for(;;)
{
(6) PxMsgReceive (&msg, mymbx);
(7) data = (PxUInt_t *) PxMsgGetData(msg);
(8) (*data)++;
(9) PxMsgRelease (&msg);
}
GHWDLOHGSURFHVVGHVFULSWLRQ
Task1 checks if UHVXOW is bigger than 100. UHVXOW was initialized with , thus the task
creates the message.
The variable UHVXOW is this messages data area. PXROS acknowledges the messages
release when it sets IODJ to After sending the message to Task2 (4), Task1 waits for
the message to be released with the call
and has access to the data (7). The data contains the variable UHVXOW for Task1. Task2
increments this variable (8) and releases the message (9).
This enables Task1 to become active again. Once active, Task1 checks the value of
UHVXOW. If it is smaller than 100, Task1 requests another message and sends it to Task2
(4). Task1 then waits for the message to be returned (5). Task2 receives the message
and increments UHVXOW again. If UHVXOW is larger than 100, Task1 sets IODJ to 0 (2). The
following call
H[F
typedef struct {
PxInt_t Opcode;
PxMbx_t AnswMbx;
PxInt_t Result;
} MsgHead_T;
typedef struct {
MsgHead_T Head;
PxUInt_t Data[4];
} MsgType1_T;
typedef struct {
MsgHead_T Head;
PxULong_t Data;
} MsgType2_T;
7DVN)XQF
PxMsg_t msg;
PxMbx_t mbx;
MsgType1_T *data1;
MsgType2_T *data2;
PxInt_t Count = 0;
for (;;)
{
(1) if (Count & 1)
{
(2) PxMsgRequest ( &msg, sizeof(MsgType1_T),
PXMcSystemdefault,
PXOpoolSystemdefault);
(3) data1=(MsgType1_T *) PxMsgGetData (msg);
(4) data1->Head.Opcode = 1;
(5) data1->Head.AnswerMbx = mymbx;
(6) data1->Data[0] = 0;
(7) data1->Data[3] = 1;
}
7DVN)XQF
PxMsg_t msg;
MsgHead_T *head;
MsgType1_T *data1;
MsgType2_T *data2;
PxInt_t result;
for (;;)
{
(17) PxMsgReceive (&msg, mymbx);
(18) head = (MsgHead_T *) PxMsgGetData (msg);
GHWDLOHGSURFHVVGHVFULSWLRQ
Depending on the value of the counter &RXQW, Task1 generates a message with a data
area of large enough for either 0VJ7\SHB7 or 0VJ7\SHB7
The message head is given an "assignment" code ((4) or (10)), and the tasks private
mailbox is specified as the answer mailbox ((5) or (11)). The program data differs in
structure and content, and therefore must be set for the specific assignment ((6) and
(7) or (12)).
which has to evaluate it. It processes the message based on its message type. In order
to identify the type, only the message head is examined. All messages arriving have an
identically structured message head, and are therefore easily interpreted:
The information in the message head allows the task to identify the message and
process it accordingly:
and can now reevaluate it. Because the task in this example fulfills no specific function,
it releases the message immediately.
The use of identically structured message heads helps distinguish between different
message types. If the message head is kept non-specific (i.e. contains no application-
specific entries), the task can easily be used in a variety of different applications. When
a task is reused in a new application, only the application specific changes need to be
added to the new function.
H[F
This example demonstrates the use of a PHVVDJH SRRO: Task1 sends messages with
data areas of a similar size. It creates a message large enough for all message types,
and puts it in a message pool. When needed, Task1 takes a message from the pool,
writes data to it, and sends it to Task2. Task2 processes the message and releases it.
At this time, the message is returned to the message pool it originated from, and from
which it is again requested by Task1. Normally message pools are filled with several
messages and not only with one; this example was kept deliberately simple to facilltate
understanding of the basic mechanism:
typedef struct {
PxInt_t Opcode;
PxMbx_t AnswMbx;
PxInt_t Result;
} MsgHead_T;
typedef struct {
MsgHead_T Head;
PxUInt_t Data[4];
} MsgType1_T;
typedef struct {
MsgHead_T Head;
PxULong_t Data;
} MsgType2_T;
PxMbx_t MsgPool;
PxMsg_t msg;
PxMbx_t mbx;
MsgType1_T *data1;
MsgType2_T *data2;
PxInt_t Count = 0;
for (;;)
{
(5) PxMsgReceive (&msg, MsgPool);
if (Count & 1)
{
data1=(MsgType1_T *) PxMsgGetData (msg);
data1->Head.Opcode = 1;
data1->Head.AnswerMbx = mymbx;
data1->Data[0] = Count;
}
else
{
data2 = (MsgType2_T *) PxMsgGetData
(msg);
data2->Head.Opcode = 2;
data2->Head.AnswerMbx = mymbx;
data2->Data = ((PxULong_t) Count) << 8;
}
Count++;
(6) PxMsgSend (&msg, mbx);
}
7DVN)XQF
PxMsg_t msg;
MsgHead_T *head;
MsgType1_T *data1;
MsgType2_T *data2;
PxULong_t value;
for (;;)
{
GHWDLOHGSURFHVVGHVFULSWLRQ
To install a message pool, both a mailbox, 0VJ3RRO (see also chapter 9), and a
message must be created:
The call
releases the message generated, which then returns to the message pool. This
concludes the preparations required to use the message pool.
writes to the data area and sends the message to Task2s private mailbox (6).
Afterwards, Task1 tries again to draw a message from the pool (5). Since 0VJ3RRO only
contained one message, it is now empty, thus Task1 has to wait. Consequently, Task2
becomes active and draws the message from its own mailbox.
After processing it, Task2 releases the message, (8) which is then returned to the
message pool. At this point, Task1s request can now be fulfilled. Task1 now sends the
new message to Task2...
(YHQWV
6XPPDU\
The application is free to assign the "meaning" of events. 32 different events can be
signalled to tasks,
numbered from 0 to 31 consecutively. The event with the number L is
assigned the L bit in a 32 bit mask. Thus, the macro
defines the event [ (0 <= x <= 31). Events can be pooled in HYHQW PDVNV. A single
event can be considered an event mask that contains RQO\ RQH event. The 25operator
"_" unites event masks with a "logical or" operation. Similarly, the $1'operator " "
combines event masks with a "logical and" operation.
([DPSOH
This line assigns HYHQWV the event mask formed by the events , , and . With
Here HYHQWV is assigned the events contained in both HY and HY. One can check for
the presence of (9(17 in the event mask HYHQWV as follows:
When 3[$ZDLWV(YHQWV HYHQWV is used, the calling task waits for events from the
event mask HYHQWV. As soon as one of these events is signalled to it, the task becomes
ready again, and 3[$ZDLW(YHQWV returns. The return value contains the events from
HYHQWV, which were signalled to the task. The task then evaluates these events.
A task signals events with the function 3[7DVN6LJQDO(YHQWV. Handlers must use the
special version of this call: 3[7DVN6LJQDO(YHQWVB+QG. Both functions contain
parameters for the event pool and the other the Id of the task they are signalled to.
Some PXROS services can wait simultaneousely for both PXROS objects and/or for
events to be signalled. One should keep in mind that both possibilities can conceivably
occur at the same time!
6LJQDOOLQJ(YHQWV
PxTaskSignalEvents (task, events) signals the events HYHQWV to the task WDVN If WDVN
has been waiting for one of these events, it switches to a ready state and becomes
active, provided any higher priority tasks are not active.
Only tasks can call 3[7DVN6LJQDO(YHQWV. Similarly, handlers must use the special
service 3[7DVN6LJQDO(YHQWVB+QG This function has the same parameters as the task
service, but has been specially optimized for use on handler level.
:DLWLQJIRU(YHQWV
For a task, events are QRW considered as KDYLQJ RFFXUUHG, as long as they have not
been signalled to the task. Using the call PxAwaitEvents (events) a task waits for
events from the event pool. The function returns as soon as DW OHDVW RQH of these
events is signalled to the task, or DW OHDVW RQH of these events is about to occur at the
time of the call. The task does not wait until DOO events from events have been signalled.
$UULYLQJ(YHQWV
Events: 1, 5, 9
Events: 0, 1, 3, 5, 9
Events: 3, 5
The return value of 3[$ZDLW(YHQWV holds the events signalled to the task contained in
the mask HYHQWV. These are removed from the list of events in the event mask that a
task was waiting for. Afterwards, these are seen as not having occurred. When the
return value is examined, one should remember that several events may have been
registered; therefore, one should check for the occurrence of any possible events.
Evaluating these events is explained in the application examples.
3[$ZDLW(YHQWV never returns a . This would mean that the function returned although
no event was signalled to the task. 3[$ZDLW(YHQW waits until at least one of the events
in HYHQWVhas been signalled.
([DPSOH
When using 3[$ZDLW(YHQWV, the developer should keep in mind that at least one of
the events from HYHQWV must be signalled to the task during the run of the program;
otherwise, the task is in a dead end (i.e. it will not become active again). This is
especially important when calling 3[$ZDLW(YHQWV
In addition to those services which wait for both events and PXROS objects,
3[$ZDLW(YHQWV is usually used to wait for events.
5HVHWWLQJ(YHQWV
Like 3[$ZDLW(YHQWV, 3[5HVHW(YHQWV HYHQWV cancels events from the event mask.
In contrast however, 3[5HVHW(YHQWV does not wait for one of the events from HYHQWV to
arrive. In other words, this function does not change the tasks state; rather, it returns
immediately. The return value contains the mask of events from HYHQWV that were
actually present at the time of the function call. Furthermore, the return value of
3[5HVHW(YHQWV can be . One must keep in mind that an event can conceivably be
signalled directly after the function returns. This means that the event is queued once
again, even though it was previously deleted with 3[5HVHW(YHQWV.
2WKHU)XQFWLRQV
3DUDOOHO:DLWLQJ
Several PXROS services wait simultaneously for an object to become available, and for
specific events to be signalled (e.g. 3[0VJ5HFHLYHB(Y:DLW). These services are
recognized by the extension B(Y:DLW. They either return as soon as the expected
object is available, or once one of the events from the event mask has been signalled.
These services are typically applied for placing a time limit on how long the task waits
for an object to become available. To do this, a WLPHRXW is started, which signals an
event to the task after a certain time has passed. After starting the timeout, the task
waits for either the requested object, or for the event to arrive. Once the set time limit
has expired, if the expected object has not become available, the task stops waiting.
Other events can also be used to interrupt a waiting task (i.e. not only timeouts). When
this type of service returns because it received the requested object, the return value is
; otherwise, the signalled events are contained in the return value.
,PSRUWDQW Keep in mind that both possibilities can occur simultaneously! For example,
if a message arrives after the task has called 3[0VJ5HFHLYHB(Y:DLW, the task is in a
ready state; however, if it is blocked by a higher priority task until after the timeout has
expired, the return value will not be 0 even though the message arrived.
([DPSOH
TIMEOUT_START (EVENT(1));
$ERUWLQJ)XQFWLRQVZLWK(YHQWV
With the service 3[([SHFW$ERUW, PXROS application can call any function, such that it
will be aborted when specific events occur. This mechanism is used when e.g. a task
activity must be aborted by an "emergency off switch". In this example, the interrupt
handler that reacts to the off switch signals an abort signal to the relevant task, thereby
aborting it immediately.
([DPSOHV
The source code for the following "events" examples can be found in the directory
HYHQWV on the floppy disk.
H[F
Task1 and Task2 wait for different events. When these events arrive and are
evaluated, the receiving task signals its own events to the other task.
7DVN)XQF
for (;;)
{
(1) ev = PxAwaitEvents (EV_1 | EV_2);
(2) if (ev & EV_1)
{
(3) PxTaskSignalEvents (Task2Id, EV_1);
}
(4) if (ev & EV_2)
{
(5) PxTaskSignalEvents (Task2Id, EV_2);
}
}
7DVN)XQF
for (;;)
{
(7) ev = PxAwaitEvents (EV_1 | EV_3);
GHWDLOHGSURFHVVGHVFULSWLRQ
for either EV_1 RU EV_2 to be signalled. At this time, no events have been signalled,
thus Task2 becomes active and sends EV_1 DQG EV_3 to Task1, using
One of these events, EV_1, is contained in Task1s event mask. For this reason, Task1
becomes ready and interrupts Task2. 3[$ZDLWV(YHQWVs return value contains the
events in event mask that were actually signalled to the task. In this case, only EV_1
was sent. This event is UHVHW (i.e. EV_1 is again considered not to have occurred).
EV_3 is still present.
Since Task1 waited for both EV_1 or EV_2 and 3[$ZDLW(YHQWV returned with only RQH
of the signalled events, the return value can only contain RQH or ERWK of the events. To
find out which, the task must evaluate the result as follows:
The first test (2) is positive, therefore Task1 sends EV_1 to Task2:
This event is now waiting at Task2. The second test (4) failed, therefore the conditional
action of the LI statement is ignored. Now Task1 waits again
for EV_1 and EV_2. EV_3, which Task2 signalled, is still present, but is not contained
in the call parameter and is therefore ignored.
and waits for one of the events EV_1 or EV_3. At this time, EV_1 is has arrived and
EV_3 has not. 3[$ZDLW(YHQWV returns with EV_1, and EV_1 is reset in the event
mask.
As the return value is evaluated, the first test (8) fails, while the second test (10) is
successful. As specified in this second conditional statement, Task2 sends EV_1 and
EV_3 to Task1 with
The program continues in this manner, repeating the step described above.
H[F
This example shows the case where an event is signalled to a task again before the
task was able to evaluate it.
7DVN)XQF
for (;;)
{
(1) ev = PxAwaitEvents (EV_1 | EV_2);
7DVN)XQF
for (;;)
{
(6) PxTaskSignalEvents (Task1Id, EV_1 | EV_2);
(7) ev = PxAwaitEvents (EV_3);
(8) ev = PxResetEvents (EV_1 | EV_2 | EV_3);
}
GHWDLOHGSURFHVVGHVFULSWLRQ
for EV_1 or EV_2 to be signalled. At this moment, no events have been signalled to
Task1. Task2 becomes active and sends EV_1 and EV_2 to Task1.
Task1 again becomes active, EV_1 and EV_2 are reset, and 3[$ZDLW(YHQWV returns.
The return value is evaluated using the conditional statements
HYhas the value EV_1 | EV_2. Both conditionals test positive, therefore, Task1 signals
EV_1, EV_2 and EV_3 to Task2:
In this case, EV_3 is signalled WZLFH. These events are present at Task2. Having
signalled these events to Task2, Task1 again waits
Task2 becomes active and continues from where it was interrupted. It calls
and waits for EV_3. Because Task1 already signalled these events, EV_1, EV_2 and
EV_3 are already present. 3[$ZDLW(YHQWV returns immediately. Since Task2 only
waited for EV_3, the return value HY can only contain EV_3. EV_3 is reset in Task2.
The call
indicates which of the three events EV_1, EV_2 or EV_3 is still queued at Task2. The
return value is EV_1 | EV_2. Because it was reset, EV_3 is QRW included in the return
value even though it was signalled WZLFH and "picked up" only RQFH.
This example shows that a task must process signalled events in a timly manner if it is
to react to HYHU\ signal. If an event is signalled again before it is processed by a task,
the task can not determine whether the event was already signalled.
0HPRU\0DQDJHPHQW
6XPPDU\
When 3[0F7DNH%ON PF EON VL]H is called, PXROS takes a memory block of the
size VL]H byte from the memory class PF and makes it available to the application. EON
contains the memory blocks starting address. After being used, the memory block is
returnedto the memory class PFwith the call 3[0F5HWXUQ%ONPFEON
0HPRU\5HTXHVWV
Using 3[0F7DNH%ON, a PXROS task can dynamically request memory from the
memory class PF. If it contains a block of sufficient size, PXROS delivers the memory
areas starting address; otherwise the function reports an error through the return value
PXERR_MC_NOMEM. When memory is no longer required, it can be returned with a
call to 3[0F5HWXUQ%ON. The parameter PF used in both PXROS services indicates the
memory class from which memory is taken, or to which it is returned. The memory
classes used to return a memory block PXVW be the same as that used for requesting
the memory block.
%ON is the address of a data pointer, where PXROS enters the address of the memory
block provided by 3[0F7DNH%ON If there is not enough memory available, %ON is
When memory is released, %ON must contain the address given by 3[0F7DNH%ON. It is
not possible to only partially release a requested block. PXROS sets the pointer to
when a block is released.
The size of the memory area is only needed when a request is made. VL]H contains the
size of the desired memory in %\WH. Certain size restrictions may apply to the requested
memory block.
([DPSOH
fun()
{
PxUChar_t *buffer;
PxError_t err;
....
err = PxMcTakeBlk (PXMcSystemdefault,(PxAligned_t**)
&buffer,100);
if (err != PXERR_NOERROR)
{
....
}
....
PxMcReturnBlk (PXMcSystemdefault, (PxAligned_t **)
&buffer);
....
}
0HPRU\&ODVVHV
&UHDWLQJ0HPRU\&ODVVHV
A new memory class is generated with the service 3[0F5HTXHVW: PXROS takes a
memory class object from the object pool RSRRO and enters its Id in
0F. When RSRRO is
empty, the task waits until an object becomes available.
HighTec EDV-Systeme GmbH 60 20. Mai 1996
PXROS V4 Users Guide Version 1.0
PFW\SH defines the type of the new memory class: i.e. either YDULDEOH or IL[HG block
memory classes. The different memory class types are described in detail in the
sections 7.3.2 and 7.3.3 respectively.
For fixed block memory classes, VL]H indicates the size of the memory blocks in %\WH .
For memory classes with a variable block size, VL]H is basically ignored.
Once generated, the new memory class is not automatically assigned memory. This
must be allocated to the memory class with the appropriate PXROS service.
In addition to the standard 3[0F5HTXHVW, two other services are available for
requesting a memory class: (1) 3[0F5HTXHVWB1R:DLW does not wait if the object pool
is empty; rather it returns immediately with the message PXERR_OBJ_NOOBJ. (2)
3[0F5HTXHVWB(Y:DLW waits until either an object is available in RSRRO, or one of the
events specified in HYHQWV has been signalled to the task. In both services,
0F has the
value if no object has been made available.
Memory classes are released with the call 3[0F5HOHDVH. Once released, memory
classes return to the object pools they were taken from and
0F is set to .
3[0F5HOHDVH fails if the memory class is not empty. In other words, all memory
assigned to the memory class must be taken from the memory class before calling
3[0F5HOHDVH .
0HPRU\&ODVVHVZLWKD9DULDEOH%ORFN6L]H
Variable sized memory classes incur higher request and release run time than fixed
size memory classes. This is due to the time required to search for blocks sufficient to
fulfill a memory request, and the time needed to connect consecutive memory blocks.
They also do not allow one to estimate the processing time; however, variable sized
memory classes provide more flexibility than their fixed size counterparts.
If memory is requested from a variable size memory class for both long and short term
requirements, one runs a risk of memory fragmentation. This occurs when the entire
free memory is split up into many smaller blocks that cannot be connected together.
Under certain circumstances, memory requests can not be "honored", even though the
entire free memory is sufficient (i.e. there are no single blocks of sufficient size
available). For this reason, memory requested for different lengths of time should be
fulfilled by different memory classes.
To generate variable sized memory classes, 3[0F5HTXHVWs parameter PFW\SH is
assigned the value 3;0F9DUVL]HG. There are also special types of variable size
memory classes. The Users Guide does not deal with these as they are only used in
special applications. These types do use 3[0F5HTXHVWs parameterVL]H.
0HPRU\&ODVVHVZLWKD)L[HG%ORFN6L]H
$OORFDWLQJDQG5HOHDVLQJ0HPRU\
When a memory class is generated, it is not immediately assigned its memory. This is
done with a specific PXROS service: 3[0F,QVHUW%ON inserts a memory block into a
memory class. At this time, the memory block may not be allocated to another memory
class; however, it is likely that the block has either not been in a memory class before,
or that it previously belonged to a different memory class. PF is the Id of the memory
class into which the memory block will be inserted. %ON contains the memory blocks
starting address and VL]H its size in byte.
([DPSOH
return PXERR_NOERROR;
}
When memory is removed with the call 3[0F7DNH%ON, the block always contains the
required administrative information for returning the block with the call 3[0F5HWXUQ%ON.
This becomes useless if a block is removed from the memory for any length of time,
e.g. if it is assigned to a different memory class. In this case, it is advisable to remove
the block with 3[0F5HPRYH%ON
The 3[0F5HPRYH%ON parameters PF (the memory class) and %ON (the pointer)
correspond in meaning to their 3[0F7DNH%ON counterparts; however, the two services
differ in the size of the memory blocks they use. Specifically, 3[0F5HPRYH%ON does
not have to request memory of a FHUWDLQ size; rather, RSWVL]H describes the desired size
of the memory block. PLQVL]H and PD[VL]H indicate the minimum and maximum values
within which the memory blocks size must lie. A value can be indicated by VL]HIDFWRU.
The size of the assigned block must be divisible by this value. This is important when,
e.g. memory for a fixed size memory class must be provided. If possible, PXROS takes
a block that is sufficient for the requirements from the memory class PF, and registers
its size in
6L]H
Memory blocks that are removed from a memory class with 3[0F5HPRYH%ON cannot
be returned with the call 3[0F5HWXUQ%ON; instead, they are assigned to a memory
class with 3[0F,QVHUW%ON.
8VHRI'LIIHUHQW0HPRU\&ODVVHVLQWKH6\VWHP
Essentially, there are two reasons to use several memory classes: security and run
time. If single parts of the application only use memory from specific memory classes,
problems that are caused by a lack of memory are limited locally. This means critical
components continue to run, even if there is no memory available for other functions.
Simple systems generally only use the system memory class.
Memory requests from fixed size memory classes can be processed much faster than
requests from variable size memory classes. If similar memory block sizes are
frequently needed, it is advisable to generate a fixed block memory class to service the
requests quickly.
7LSVIRU'HYHORSHUV
Requesting and releasing memory from variable size memory classes is time-
consuming. If small memory blocks are only used for a short time, HighTec
recommends defining corresponding local variables. Requesting large memory areas
via local variables could increase the respective tasks stack requirements
disproportionately.
([DPSOHV
The source code to the following memory administration examples can be found on the
accompanying disk in the directory PHP.
H[F
Task1 requests memory from the system memory class and then releases. The size of
the requested block is increased until the request can no longer be fulfilled. The size is
then set back to the starting value.
7DVN)XQF
PxError_t err;
PxAligned_t *buffer;
PxUInt_t i = 100;
for (;;)
{
(1) err = PxMcTakeBlk (PXMcSystemdefault,&buffer,i);
(2) if (err == PXERR_NOERROR)
{
(3) PxMcReturnBlk (PXMcSystemdefault,
&buffer);
(4) i += 100;
}
else
(5) i = 100;
}
GHWDLOHGSURFHVVGHVFULSWLRQ
The size of the memory block is contained in the variable L and amounts to %\WHV
when the first call is placed. The starting address of the memory block should be
entered into EXIIHU. The return value, HUU, indicates whether the request was successful
or not. If the memory was allocated, HUU has the value PXERR_NOERROR,
After the call, buffer is 0. L is raised by 100 (4) and memory is again requested, only this
time a bigger block (1) is requested. If the memory request cannot be fulfilled, L is
initialized again (5) and the requests starts over.
H[F
Task1 removes a memory block of 2000 bytes from the system memory class. If this
request is successful, a new memory class is generated with a fixed block size of 1000
bytes. The requested memory is placed in this memory class. Then a 500 byte block
from the new memory class is requested and released.
7DVN)XQF
PxMc_t mc;
PxError_t err;
PxAligned_t *adr;
PxSize_t size;
for (;;)
{
(6) err = PxMcTakeBlk (mc, &adr, 500);
if (err == PXERR_NOERROR)
{
(7) PxMcReturnBlk (mc, &adr);
}
}
GHWDLOHGSURFHVVGHVFULSWLRQ
Task1 removes 2000 bytes from the system memory class (1) and, if successful, uses
to generate the memory class PF with a fixed block size of 1000 bytes.
The new memory class, PF, is assigned 1000 bytes (1) of memory. This block begins
at the address DGU DGUis then set to the address directly after these 1000 bytes:
and the remaining 1000 bytes are assigned to the memory class.
The blocks are inserted individually since a block is only tested for sufficient size. It is
not split up, even if it is big enough for several blocks. With
a 500 byte block is requested from the new memory class. The requested blocks size
is VPDOOHU than the memory class fixed block size. The request can be fulfilled. In
contrast, a request of bytes could not be fulfilled, even though the memory class
still has this amount of memory available (2000 bytes is PRUH than the memory class
block size). Finally, the memory is then released (7).
3;5267LPH
6XPPDU\
PXROS has a system clock for time-based routines. This clock is incremented by the
applications periodic call to 3[7LFN'HILQHB+QG. The time span between two calls is
referred to as 3;526WLFN PXROS services specify time with the tick unit.
Time-based jobs usually signal the expiration of a predefined time span to a task. For
this reason, the application is provided with specific services:
3[7R,QLW WR WLFNV HYHQWV initializes a timeout structure at the address WR. After WLFNV
PXROS ticks, the events in the event mask HYHQWV are signalled to the calling task. The
timeout is started with the call 3[7R6WDUW WR and can be stopped with 3[7R6WRS WR.
When events are signalled SHULRGLFDOO\, similar services can be used: 3[3H,QLW
3[3H6WDUW and 3[3H6WRS
Sometimes these services are not sufficient to perform specific jobs. PXROS also
provides a so-called GHOD\ MRE to activate (after a given time span) predefined functions
on the handler level. A GHOD\ REMHFW is required for the definition of a delay job. The
application requests a delay object with the call 3['HOD\5HTXHVW. 3['HOD\6FKHG
GHOD\ WLFNV KDQGOHU DUJ gives the delay object, GHOD\, the assignment to call the
function KDQGOHU with the argument DUJ after WLFNV PXROS ticks. If the job is not
executed on the task level, but on handler level, the service 3['HOD\6FKHGB+QG is
used. This handler specific service has an identical list of parameters.
3;5267LPH%DVH
Normally, the systems time base is made available by a hardware timer that generates
an interrupt after the desired time frame expires. 3[7LFN'HILQHB+QG is called in the
ensuing interrupt handler, and the timer is started once again. Any other periodic
interrupt source could be utilized as an alternative to a timer. Assigning interrupt
routines to an interrupt source is explained in chapter 11. The current state of the
PXROS clock can be "read" with 3[7LFN*HW&RXQW. This service can be used to e.g.
take time measurements within the system.
6WDQGDUG6HUYLFHV
7LPHRXWV
With these functions, the end of a time span is signalled to a task. A timeout structure
of the type 3[7RB7 is required. This structure can either be global, requested
dynamically, or located on the tasks stack.
3[7R,QLW initializes the structure such that the events of the event mask HYHQWV are
signalled to the calling task after WLFNV PXROS ticks. This call does not start the timeout
immediately; rather, it provides and initializes internal resources required.
3[7R&OHDU FOHDUV the timeout. In other words, the timeout is stopped (if active) and the
internal resources, requested by 3[7R,QLW are released. After 3[7R&OHDU has been
called, the application must reinitialize the cleared timeout structure with 3[7R,QLW
before again using the structure with 3[7R6WDUW, 3[7R6WRS, or 3[7R&KDQJH.
([DPSOH
TaskFunc()
{
PxTo_T to;
....
PxToInit (&to, 100, EV_TIMEOUT);
....
PxToStart (&to);
....
PxAwaitEvents (EV_TIMEOUT);
PxToClear(&to);
....
}
3HULRGLF(YHQWV
These functions periodically signal events to a task. The services are related to the
3[7R services described above. 3[3H services require a structure of the type
stack.
3[3H,QLW initializes the structure so that the events in the event PDVN HYHQWV can be
signalled to the calling task after WLFNV PXROS ticks. The periodic event is started with
3[3H6WDUW and stopped with 3[3H6WRS . 3[3H&KDQJH changes the WLFNV and HYHQWV
values, after which the signalling of events must be reinitialized with 3[3H6WDUW.
3[3H&OHDU interrupts any active periodic events and releases the internal resources
requested with 3[3H,QLW. After 3[3H&OHDU has been called, the application must
reinitialize the cleared periodic event with PxPeInit before again using the structure with
3[3H6WDUW , 3[3H6WRS or 3[3H&KDQJH .
([DPSOH
TaskFunc()
{
PxPe_T pe;
....
PxPeInit (&pe, 100, EV_PE);
....
....
PxPeStart (&pe);
....
for (;;)
{
PxAwaitEvents (EV_PE);
....
}
}
'HOD\-REV
The application can give PXROS a GHOD\ MRE. This activates and executes the indicated
function on the handler level after a given time span expires.
'HOD\-RE5HVRXUFHV
3['HOD\5HTXHVW does not immediately assign a job to the requested delay object. This
is accomplished in an individual step (see section 8.4.2).
A delay object is released with 3['HOD\5HOHDVH and returns to the object pool it was
taken from.
'HOD\ is thereby set to . If the delay job given 'HOD\ was not executed, it
is deleted.
([DPSOH
TaskFunc()
{
PxDelay_t delay;
....
/* request */
PxDelayRequest (&delay, PXOpoolSystemdefault);
/* use */
.....
/* release */
PxDelayRelease (&delay);
....
}
6WDUWLQJD'HOD\-RE
With 3['HOD\6FKHG, the delay object, GHOD\, is given an assignment and allocated to
PXROS. After WLFNV PXROS ticks have expired, PXROS activates the function KDQGOHU
with the argument DUJ. If KDQGOHU requires several arguments, these can be entered in
an individual structure. This structures address is given inDGU
3['HOD\6FKHG can only be called by tasks. Handlers must use the handler specific
service 3['HOD\6FKHGB+QG, which uses an identical parameter list.
([DPSOH
typedef struct {
....
....
} ArgStruct_T;
/* request */
PxDelayRequest (&delay, PXOpoolSystemdefault);
/* use */
str ... =
str ... =
tr ... =
PxDelaySched (delay, 100, handler, (PxArg_t) &str);
/* release */
PxDelayRelease (&delay);
....
}
As soon as KDQGOHU is activated, no job is associated with the relevant delay object. If a
function is to be called SHULRGLFDOO\, 3['HOD\6FKHGB+QG must be repeatedly replace
the job associated with the calling function. To do so, it must "know" the the relevant
delay objects Id, thus the Id must be provided globally or via the argument.
([DPSOH
typedef struct {
PxDelay_t delay;
....
} ArgStruct_T;
TaskFunc()
{
PxDelay_t delay;
ArgStruct_T str;
....
/* request */
PxDelayRequest (&delay, PXOpoolSystemdefault);
str.delay = delay;
str.... =
str.... =
/* start delay job */
PxDelaySched (delay, 100, handler, (PxArg_t) &str);
....
}
&DQFHOOLQJD'HOD\-RE
By calling 3['HOD\6FKHG with the value for WLFNV, a delay job associated with the
specified delay object can be cancelled In this situation, the arguments KDQGOHU and
DUJare of no consequence. If the job has already been executed, the call has no effect.
If 3['HOD\6FKHG is called for a delay object with WLFNV not equal to , the old job will be
cancelled and the new job is installed. It is therefore not necessary to cancel the old job
explicitely before using 3['HOD\6FKHG in this way. If the old job is to be kept, a second
delay object must be requested and the new job linked to it.
([DPSOH
TaskFunc()
{
PxDelay_t delay;
....
/* request */
PxDelayRequest (&delay, PXOpoolSystemdefault);
/* release */
PxDelayRelease (&delay);
....
}
([DPSOHV
The source code for the delay job examples can be found in the directory GHOD\ on the
accompanying disk.
All examples use signals and wait for events, the use of which is described in detail in
chapter 6. This requires knowledge about how events are signalled and received, as
well as the effect this has on the scheduling of tasks.
H[F
Task1 generates a delay job that activates 'HOD\)XQF after 100 ticks. This function
signals EV_DELAY to Task2. Task2 then becomes active and signals EV_SIG to
Task1, which restarts the delay job.
'HOD\)XQF
7DVN)XQF
PxDelay_t delay;
(2) PxDelayRequest (&delay, PXOpoolSystemdefault);
7DVN)XQF
for (;;)
{
(5) PxAwaitEvents (EV_DELAY);
(6) PxTaskSignalEvents (Task1Id, EV_SIG);
}
GHWDLOHGSURFHVVGHVFULSWLRQ
With
Task1 requests the delay object GHOD\ from the system pool. The call
gives GHOD\ the following delay job: after 100 PXROS ticks, the delay function
'HOD\)XQF is called with the argument 7DVN,G
Now both tasks are in a state of ZDLWLQJ After the lapse of 100 PXROS ticks, PXROS
activates 'HOD\)XQF. With
EV_DELAY is sent to Task2, the Id of which is given to the function as argument. Upon
receiving this signal, Task2 no longer waits. Using
Task2 sends EV_SIG to Task1. Its wait is ended and it restarts the delay job.
H[F
Both tasks start an individual delay job that in both cases calls 'HOD\)XQF after a
certain time. Both tasks wait for an event to be signalled. 'HOD\)XQF signals an event to
a task and restarts itself. The delay objects event, task and Id take the function from a
parameter structure, the address of which is given as argument.
typdef struct {
PxDelay_t delay;
PxTask_t task;
PxEvents_t events;
PxTicks_t ticks;
} ArgStr_T;
'HOD\)XQF
7DVN)XQF
PxDelay_t delay;
(4) PxDelayRequest (&delay, PXOpoolSystemdefault);
for (;;)
{
(10) PxAwaitEvents (EV_DEL1);
}
GHWDLOHG3URFHVVGHVFULSWLRQ
Task1 and Task2 have almost identical code. For this reason, only Task1s code is
described here.
Afterwards, some values are assigned to a parameter structure ((5) - (8)). These
include the Id of a delay object, the Id of a task, a value for PXROS ticks, and an event
mask. The task gives PXROS the delay job:
After a given period of time, PXROS calls 'HOD\)XQF gives the address of the
parameter structure as argument. With
the event is signalled to the task and the delay job is restarted:
If, at this time, the delay jobs of both tasks are waiting, these are executed
successively. They do not interrupt each other.
H[F
This example demonstrates how a delay job is stopped and its delay object is released.
Task1 initializes a delay job and waits for the signals EV_DELAY and EV_INTR. If
EV_DELAY is signalled, the task restarts the job. Using EV_INTR, the delay job is
stopped and the object released.
'HOD\)XQF
7DVN)XQF
Pxdelay_t delay;
PxEvents_t ev;
(2) PxDelayRequest (&delay, PXOpoolTaskdefault);
(3) PxDelaySched (delay, 1000, DelayFunc,
(PxArg_t) EV_DELAY);
7DVN)XQF
GHWDLOHGSURFHVVGHVFULSWLRQ
The task then waits for the signals EV_DELAY and EV_INTR.
While Task1 is waiting, the lower priority Task2 becomes active and signals EV_INTR
to Task1.
Once Task1 is reactivated, it evaluates the events it received: if the delay job has
already been executed, then EV_DELAY was sent and Task1 restarts the job (7);
however, this case is not important at the moment. The requirement
is fulfilled by the event signalled by Task2. The task stops the delay job by calling:
WLFNVis assigned the value The other two parameters for this function are irrelevant
and thus assigned as well. The delay object, GHOD\, is now released:
Since the release of the delay object automatically stops a job in process (see section
8.4.1), the explicit interruption (9) is in this case superfluous. The task now waits for the
events EV_DELAY and EV_INTR, which never arrive.
H[F
This example demonstrates how a timeout is aborted, and how resources are released
when using 3[7R services. Task1 initializes a timeout. Once the timeout expires,
EV_DELAY is signalled. The task then waits for the events EV_INTR and EV_DELAY.
If EV_DELAY is signalled, the task restarts the timeout. If EV_INTR is signalled, the
timeout is cleared.
7DVN)XQF
PxTo_T to;
PxEvents_t ev;
7DVN)XQF
GHWDLOHGSURFHVVGHVFULSWLRQ
Task1 has a timeout structure, WR, on its stack. Using 3[7R,QLW, Task1 initializes it to
wait 100 PXROS ticks and then signal EV_DELAY to the task.
and waits for EV_DELAY and EV_INTR (4). With Task1 in a wait state, Task2 becomes
active and sends Task1 the signal EV_INTR
Task2 remains in endless loop for the rest of the program. Task1 now evaluates the
events signalled: if the timeout has already expired, EV_DELAY was signalled and
Task1 restarts the timeout (6). This is currently not the case. The requirement
This stops the timeout. Subsequently the task awaits the events EV_DELAY and
EV_INTR, which can no longer be signalled.
H[F
An event is periodically signalled to Task1. Every time the event is signalled, Task1
increments a counter. After 10 times, the periodic event is cleared.
7DVN)XQF
PxPe_T pe;
PxInt_t count;
Task1 has a structure, SH, on its stack. Using PxPeInit, Task1 initializes it such that the
task is signalled EV_PE after 100 ticks.
and the counter is initialized at 0 (3). Task1 awaits the signal EV_PE
and increments the counter as soon as it receives the signal for the event (5). After 10
times, the structure for the periodic event is cleaed:
Afterwards, Task1 remains in PxAwaitEvents (EV_PE) for eternity (or at least until you
stop the program :^).
0DLOER[HV
6XPPDU\
&UHDWLQJ0DLOER[HV
When a task is created, its SULYDWH PDLOER[ is created simultaneously. This private
mailbox is where the task normally awaits messages.
Usually the private mailboxes are sufficient for an application intertask communcation.
Sometimes however, it is useful to create additional mailboxes to e.g. be used as
message pools to store messages that were generated in advance (see chapter 5.7).
This saves time since requesting a message from a mailbox is a lot quicker than to
creating a new message each time one is needed. Message pools can also be quite
useful for implementing semaphores.
A mailbox is created with the call 3[0E[5HTXHVW: PXROS takes a mailbox object from
the object pool RSRRO and enters its Id in
0E[. If RSRRO is empty, the task waits until an
object becomes available.
If the mailbox is no longer needed, it can be released by with the call 3[0E[5HOHDVH.
When released, the object used returns to the object pool from which it was taken. As a
result,
0E[ is set to The service 3[0E[5HOHDVH fails if there are still messages in
the mailbox, or if tasks are waiting for messages at the specified mailbox. A tasks
private mailbox can not be released.
0DLOER[+DQGOHUV
Mailbox
Handler
Using the service 3[0E[,QVWDOO+QG, the routine KQG is installed at the mailbox PE[ as
a PDLOER[ KDQGOHU. KQG can be activated by PXROS whenever a message is sent to
PE[. The mailbox handler need not be activated with the arrival of HYHU\ message;
instead, specific messages can be chosen. The choice is not based on the messages
FRQWHQW; rather, it is based on the given priority. The message type is defined by the
parameter PVJVSHF. The parameter can receive one of the following values:
These messages are sent with the service 3[0VJ6HQG. If PVJVSHF has this
HighTec EDV-Systeme GmbH 84 20. Mai 1996
PXROS V4 Users Guide Version 1.0
If a mailbox handler is installed at the specified mailbox, the call fails. A mailbox
handler can be removed by calling 3[0E[,QVWDOO+QG and specifing the parameter KQG
to be .
Further processing of the message is determined by the mailbox handlers return value
as follows:
If KQG returns the value other than , PXROS assumes that the handler has
refused to accept the message. In this case, the message is QRW passed on
to the mailbox, and the 3[0VJ6HQG call fails. The return value of KQG is
taken on by 3[0VJ6HQG.
If KQGreturns the value and the message is set to , PXROS assumes that
KQG has processed the message and either released it or sent it on its way.
In this case, the message does QRW reach the mailbox.
If KQG returns the value 0 and has QRW set the message to , the message
reaches the mailbox.
The standard version of PXROS does not provide a service to send and release
messages on the handler level. An installed mailbox handler can only read and
evaluate messages. The use of mailbox handlers enables tasks to wait at GLIIHUHQW
mailboxes simultaneousely: a mailbox handler is installed at every mailbox the task
wishes to monitor. Once a message arrives, the mailbox handler signals an event to the
task. This mechanism can also be used for flow control. In this case, the mailbox
handler registers any messages that arrive.
,PSRUWDQW a mailbox handler must be defined such that all parameters within the
routine are transfered over the stack. Register can not be allocated for this purpose.
([DPSOHV
The source code for the following examples can be found in the directory PE[ on the
accompanying disk.
H[F
This example demonstrates how a mailbox handler enables a task to wait for
messages at several mailboxes simutaneously: Task1 creates a mailbox, PE[ with a
mailbox handler that signals an event whenever a message arrives. The task waits at
its private mailbox for messages and, simultaneously, for the mailbox handlers events.
Task2 sends a message, alternating between PE[ and Task1s private mailbox. If the
message arrives in PE[, Task1 stops waiting and takes the message from PE[.
typedef struct {
PxMbx_t Mbx;
} Request_T;
0E[+QG
7DVN)XQF
for (;;)
{
(5) ev = PxMsgReceive_EvWait (&msg, mymbx, EV_MBX1);
(6) if (msg)
{
req = (Request_T *) PxMsgGetData(msg);
(7) req->Mbx = mbx;
PxMsgSend(&msg, Task2Mbx);
}
(8) if (ev & EV_MBX1)
{
(9) PxMsgReceive (&msg, mbx);
req = (Request_T *) PxMsgGetData(msg);
(10) req->Mbx = mymbx;
(11) PxMsgSend(&msg, Task2Mbx);
}
}
for (;;)
{
(12) PxMsgReceive (&msg, mymbx);
req = (Request_T *) PxMsgGetData(msg);
(13) PxMsgSend (&msg, req->Mbx);
}
GHWDLOHGSURFHVVGHVFULSWLRQ
Task1 creates the mailbox PE[ (1), and installs the funtion 0E[+QG as the mailbox
handler for the new mailbox.
The function 0E[+QG is called with the argument (9B0%; for every message that is
sent to PE[.
Task1 then creates a message (3). The messages data area notes the mailbox to
which the message is to be sent back to. Task1 specifies its private mailbox as the
receiving mailbox, and sends the message to Task2 (4). Task1 then waits at its private
mailbox for either a message or the event (9B0%; (5).
Task2 accepts Task1s message from its private mailbox (12) and sends it to the
mailbox specified in the messages data area, in this case Task1s private mailbox (13).
The mailbox handler signals the event EV_MBX1 to Task1, which was specified during
its installation (2). The mailbox handler now returns Afterwards, PXROS places the
message into the mailbox PE[. Task1 is activated by the signalled event and takes the
message from PE[:
Once again, Task1 specifies its private mailbox in the messages data area, and the
message is sent to Task2. This process is continuously repeated. If a task is to wait at
a third or fourth mailbox, the mailbox handler 0E[+QG would be installed with a
different event for each case. This enables the calling task to directly identify the
mailbox that contains the new message.
2EMHFWVDQG2EMHFW3RROV
6XPPDU\
The object type dictate which PXROS services are available for the various objects. For
example, a service for a PDLOER[ REMHFW cannot be used on a GHOD\ REMHFW. Some
services are provided for all objects, regardless of their object type, such as those that
request or release objects. Services dealing with individual PXROS objects are
described in the corresponding chapters.
New object pools can be created to distribute objects at any time while the program is
running. There are two types of object pools: YLUWXDO and UHDO object pools. While UHDO
object pools actually distribute objects, YLUWXDO object pools merely serve to limit access
to objects. The reason for, and the use of these differences is dealt with in section 10.4.
The system pool is generally sufficient for use with simple applications.
*HQHUDWLQJ2EMHFW3RROV
3[2SRRO5HTXHVW creates an object pool. Section 10.4 describes how additional object
pools can be useful. With the call 3[2SRRO5HTXHVW, PXROS takes an object from the
object pool SRRO, and converts it into an object pool, the Id of which is written in
2SRRO
If SRROis empty, then the task waits until an object becomes available.
FDSDFLW\ specifies how many objects the object pool should contain. These objects are
taken from the source pool VUF. W\SH defines whether a UHDOor YLUWXDO pool is created. To
create a UHDO object pool, W\SH receives the value 3;2SRRO5HDO, while to create a
YLUWXDO pool, W\SH is given the value 3;2SRRO9LUWXDO . Essentially, the difference lies in
the immediacy with which the object is extracted from a source pool. For a real object
pool, an object is extracted immediately from VUF. In contrast, an object is only taken
from a virtual pool when required. These differences are dealt with in detail in sections
10.2.1. and 10.2.2.
task is signalled one of the events in the event mask HYHQWV. In both services,
2SRRO
has a value of if no object pool was made available.
3[2SRRO5HOHDVH releases an object pool and returns the underlying object to the
object pool from which it came. The objects contained within the released object pool
are also returned to their source pool. If however, objects from the object pool are still
being used, the object pool cannot be released; otherwise, the object pool into which
they must return, would no longer exist! Also, if tasks are waiting for objects at the
object pool to be released, a call to 3;2SRRO5HOHDVH is unsuccessful.
9LUWXDO2EMHFW3RROV
A virtual object pool serves to limit the use of objects in certain modules, without
actually allocating objects specifically to those modules. In this way, available objects
are not used up in one area alone. For example, if a task requests an object from the
object pool 3RRO, and 3RRO is empty, the request would not be "granted". If however,
3RRO is a virtual object pool with a small capacity, other tasks can make requests on the
source pool and (assuming the source pool is not empty as well) still receive the
objects theve requested.
5HDO2EMHFW3RROV
*HQHUDWLQJ$GGLWLRQDO2EMHFWV
When PXROS is initialized, a number of objects are generated. These are kept in the
system object pool. New objects can be inserted with the call 3[2SRRO,QVHUW1HZ2EM.
Free memory is then converted into additional objects.
%ON must indicate a free area
with the size of
VL]H bytes. This service changes memory into an unspecified object
and places it in the object pool RSRRO. This object pool PXVW be a UHDO object pool (see
section 10.2.2). Also,
VL]H must be large enough to hold an object whose size that can
be determined with 3[*HW2EMVL]H. The size of an object is dependent on both the
processor used, and on the maximum length of the object name.
If the service is successful, is returned,
%ON is increased by the size of one object,
and
VL]H is reduced accordingly. If unsuccessful, an error code is returned and both
parameters remain unchanged.
Normally, all objects that are likely to be needed are generated during the initialization
of PXROS. 3[2SRRO,QVHUW1HZ2EM is used during the initialization of PXROS e.g. if
there is not enough memory in the system memory class available for all requested
objects. This service might also during run time if additional memory (e.g memory card)
becomes available which is also to be used for objects.
8VLQJ'LIIHUHQW2EMHFW3RROVLQWKH6\VWHP
The use of several different real object pools serves essentially to protect critical
system functions. By dividing different parts of the system into cells, problems caused
by resource difficiency can be contained within certain parts of the application. Other
areas are then left unaffected. To avoid delays in receiving objects (waiting for
availability), resources for critical jobs should be taken from the system pool or from a
special real object pool.
Virtual object pools can also help protect critical functions from resource deficiency. For
example, a task must wait for an object because a virtual pool is empty but the source
is not. In this case, only object requests that can accept such delays should be sent to
such a pool. In most simple systems, only the system pool is normally used.
2WKHU6HUYLFHV
3[2SRRO*HW&XUUHQW&DSDFLW\ shows how many objects are resident in the object pool
RSRRO . 3[2SRRO*HW7\SH reports whether RSRRO is virtual or real.
Like tasks, objects can have names. These names serve to make identification easier
while debugging the application. These names can not be used to identify objects
within the application itself. The maximum length of the name is fixed during the
initialization of PXROS. The sizes of objects increase accordingly.
3[2EM6HW1DPH assigns the object REM the name QDPH. This name is saved within the
fixed length specified during initialization. In other words, QDPH is truncated if it is too
long. The name is not saved with a terminating zero if it exceeds the maximum length.
PXROS gives the system memory class and the system pool their names.
3[2EM*HW1DPH copies the name of a given object into the buffer EXIIHU. The size of
the buffer is reported in EXIVL]H If the name is longer then only EXIVL]H symbols are
copied.
([DPSOHV
The source code for the following examples can be found in the directory RSRRO, on the
accompanying disk.
H[F
7DVN first creates a real object pool. This serves as the source pool for a virtual object
pool that is generated by one of its objects. Delay objects are then requested from the
virtual object pool. The last request fails because the virtual object pool is empty, even
though the source pool itself is not empty.
for (;;)
{
(3) err = PxDelayRequest_NoWait (&Obj1, VirtPool);
(4) err = PxDelayRequest_NoWait (&Obj2, VirtPool);
(5) err = PxDelayRequest_NoWait (&Obj3, VirtPool);
(6) PxDelayRelease (&Obj1);
(7) PxDelayRelease (&Obj2);
}
GHWDLOHGSURFHVVGHVFULSWLRQ
5HDO3RRO contains 5 objects taken from the system pool. After creating the object pool,
the system pool contains IHZHUREMHFWV (i.e. five objects + one object pool). 9LUW3RRO, a
new virtual object pool containing two objects, is then requested from 5HDO3RRO.
5HDO3RRO now contains 4 objects (only 1 object taken for the object pool). In the
endless loop that follows, a delay object is requested three times from 9LUW3RRO ((3), (4)
and (5)). The first two requests are successful and the return value is
PXERR_NOERROR. Due to these requests, 5HDO3RROs capacity has dropped to two,
and 9LUW3RRO now has 0 objects available. Therefore
returns the error PXERR_OBJ_NOOBJ, and the two other requested delay objects are
released (6) and (7).
H[F
This example attempts to create as many objects as possible from the memory field
PHP, and to place these in an object pool.
PxAligned_t mem[100];
7DVN)XQF
PxAligned_t *adr;
PxOpool_t Pool;
PxSize_t size;
PxError_t err;
PxUInt_t capacity;
GHWDLOHGSURFHVVGHVFULSWLRQ
Using
Afterwards, a loop is used to convert memory into an object, which is then placed in the
object pool 3RRO.
With this function, DGU increases in size by one object, while VL]H is reduced by the size
of one object. Once the memory has been used up, 3[2SRRO,QVHUW1HZ2EM returns an
error and the loop is terminated (5). Afterwards, the object pools new capacity is finally
determined and saved in FDSDFLW\
,QWHUUXSW,QWHUIDFH
The interrupt interface depends on the hardware used. PXROS provides services for
defining interrupt handlers. These services offer the application an interface
independent of hardware.
When this interrupt interface is used, functions can be chosen and used as interrupt
service routines. With this in mind, when the interrupt occurs, preparations must be
made before the execution of the routine. One must take care not to increase the
interrupt latency time unnecessarily. For example, not every interrupt handler requires a
register bank or a stack. Also, at times it is possible to start an interrupt handler as the
application is created. TrapInstallChandler is not always the optimum method,
especially when high frequency interrupts are used and should only be allowed to run
for a short time period. In such cases, the interrupt interface should be created
statically. This is done by using certain macros as the function is defined.
The modules containing the functions for the trap interface are not distributed in the
PXROS library. These modules are delivered separately (as source code) since it is
usually necessary to modify the trap interface to the target hardware. Specifically, they
must be configured, translated, and linked to the target hardware. Descriptions of these
modules are found in the individual modules, as well as in their header files, which also
contain a description for the static definition of the interrupt routine.
If certain routines are specified as interrupt handlers without using the function
described above (i.e. assembly routines), they must ensure that the function saves the
processor context before using the processor, and restores it when exiting. If function
calls are used, the function must also make sure there is room on the stack.
(UURU+DQGOLQJ
6XPPDU\
PXROS provides two different error handling services. Errors are seperated into two
classes, and PXROS handles each class differently:
5XQWLPH HUURUV are one type of error common to many PXROS applications. A lack of
resources is an example a runtime error. This is usually noted in the services return
value.
The second of errors, DSSOLFDWLRQ HUURUV, can generally be traced to the improper use of
the services. For example, attempting to use a service with the wrong object type will
cause an application error. These errors can be caught through the additional tests
performed in the PXROS debug library. PXROS does not warn of these errors with a
return value; instead, PXROS calls 3[0HVVDJH. This service activates an error
function that reacts in accordance with the severity of the error.
3[0HVVDJH)XQ'HIDXOW is the standard PXROS error function; however, PXROS
5XQWLPH(UURUV
Run time errors occur during normal usage. Most runtime problems are related to
resource requests, and are reported in the calling services return value. Ignoring a
reported error can lead to even more severe problems. For example: if a request for an
object fails and is not noticed, an illegal object Id may be sent to a PXROS service.
In addition to reporting an error in the return value, PXROS saves the last error that
occurred in each task. 3[*HW(UURU shows the calling tasks last saved error. The
application is allowed to change the saved error value. Once an error is removed,
PXERROR_NOERROR is usually written to this value to avoid confusion from reports
of an old error. The call 3[6HW(UURUHUU sets the error value to HUU
All errors of this type are registered by both the PXROS production library and the
debug library. This allows the application to react dynamically to runtime errors.
$SSOLFDWLRQ(UURUV
Application errors occur when services are used incorrectly. These errors are only
detected by additional tests performed in the PXROS debug library. For example, the
debug library notices when a tasks stack overflows, or e.g. if an object Id of the wrong
type is passed to a service.
These errors are sometimes the result of unnoticed or ignored run time errors. If, for
example a message request is unsuccesful, the variable for the message Id is If a
service with this Id is called, this causes an application error because the Id does not
represent a message.
When such an error occurs, PXROS calls 3[0HVVDJH FODVV HUU . This service
reports the error with the systems error message function. The error message function
is sent the type of error in FODVV, and the error code HUU. It can also receive additional,
user-specified parameters. FODVV is assigned one of the values: 3;:DUQLQJ, 3;(UURU or
3;)DWDO.
DOZD\V LJQRUHV HUURUV RI WKH FODVV 3;:DUQLQJ 3;(UURU FODVV HUURUV DUH LJQRUHG ZKHQ
IRXQG LQ WKH SURGXFWLRQ OLEUDU\ KRZHYHU LQ WKH GHEXJ OLEUDU\ WKLV FODVV RI HUURU FDXVHV
DFDOOWR3[3DQLF
By calling 3[&WUO, the application can define a customized error message function. The
first parameter PXVW have the value 3;&WUO6HW0HVVDJH)XQ . The application can also
activate this function by calling 3[0HVVDJH.
([DPSOH
The source code for this example can be found in the directory HUURU on the
accompanying disk.
H[F
0\(UURU0HVVDJH)XQF3[0HVVDJH&ODVVFODVV3[(UURUBWHUU
if (class == PXWarning)
(1) warning++;
else
if (class == PXError)
(2) error++;
else
(3) PxPanic ();
7DVN)XQF
for (;;);
GHWDLOHGSURFHVVGHVFULSWLRQ
7DVN defines the custom error message function: 0\(UURU0HVVDJH)XQF. This counts
all warnings and errors ((1) and (2)), and stops the system with a call to 3[3DQLF (3)
whenever a fatal error occurs. The message function is activated by calling:
This contains a warning and the error code -1. Afterwards, the application requests a
new memory class PF (6). The error variable is not assigned the requests return value;
rather, it is given the last error saved for the task:
The new memory class is not allocated any memory. The application attempts to create
the following message:
(8) PxMsgRequest(&msg,100,mc,PXOpoolSystemdefault);
This call fails, and again the error is assigned the last error reported by 3[*HW(UURU (9).
The task ignores the error and
tries to send a message; however, since no message could be created (8), PVJ is an
illegal message Id. PXROS treats this as fatal application error and activates the error
message function with the error class 3;)DWDO. 0\(UURU0HVVDJH)XQF then stops the
system by calling 3[3DQLF (3).
6FKHGXOLQJ
6XPPDU\
PXROS is a PXOWLWDVNLQJ operating system. In other words, using several tasks allows
PXROS to run several operations simultaneously. These make up the lions share of
the functions implemented with PXROS. In addition to tasks (and PXROS itself),
KDUGZDUH LQWHUUXSW KDQGOHUV allow an application to react to external processor
interrupts. PXROS also provides services for activating the so-called VRIWZDUH LQWHUUXSW
KDQGOHU.
The operating system decides which code is executed. PXROS uses SUHHPSWLYH
SULRULW\EDVHGVFKHGXOLQJ to determine exactly when the various jobs are processed.
+DUGZDUH,QWHUUXSW+DQGOHUV
On some processors, hardware interrupts can also be given priorities relative to one
another. PXROS uses this hierarchy, thus allowing high priority handlers to interrupt
handlers with a lower priority.
PXROS never disables the interrupt system. Also, the operating system does not affect
how the processor handles its interrupts. Basically the processors interrupt latancy is
dependent on how the interrupt handlers are installed (see chapter 11).
6RIWZDUH,QWHUUXSW+DQGOHUV
Basically, software interrupt handlers are either GHOD\ KDQGOHUV (see chapter 8.4) or
PDLOER[ KDQGOHUV. They can interrupt any task, but they may also be interrupted by any
hardware interrupts that occur while they are running. Software interrupt handlers are
not assigned priorities, and therfore do not interrupt one another. When two or more
software interrupt handlers are called simultaneously, they are processed sequentially.
7DVN6FKHGXOLQJ
Tasks are scheduled according to their respective WDVN SULRULWLHV. Each task is given a
priority when it is created. This can be changed dynamically with a special PXROS
service. The tasks priority only controls its scheduling in relation to other tasks. If a
handler is activated, any active task is interrupted immediately.
Zero (0) is the highest possible priority a task can have. The lowest possible task
priority depends on the processor used, as well as the version of PXROS used.
Normally the lowest priority is 15 or 31. PXROS does not schedule a task based on the
absolute value of its priority; rather, scheduling is based on the relative priorities
between tasks.
In addition to its priority, the tasks status plays a role in scheduling. Tasks are
generally considered to be in one of two possible states: ZDLWLQJ or UHDG\. All ready
tasks compete to become active, whereas tasks in the wait state remain dormant until
something occurs to make them active. Tasks in the ready state execute their code in
the order of their respective priorities (i.e. highest to lowest).
Under the following conditions, a task will relinquish processor control to another task:
A task or a handler calls a PXROS service that places a task with a higher
priority into a ready state (i.e. the task was in a wait state) .
Using the relevant PXROS service, the active task sets its own priority lower
than that of another ready task. Alternatively, the active task could set
another ready tasks priority higher than it own.
7DVNVRI(TXDO3ULRULW\
If a number of tasks with equal priorities are ready at the same time, the task that has
been ready for the longest time is activated first. The remaining tasks are processed on
a "first come, first served basis". When a ready tasks priority is dynamically changed,
the task is treated as if it were temporarily in a wait state and then became ready. In
other words, the task does not become activate until all other ready tasks at the new
priority level have been processed (i.e. those that have been waiting longest). Of
course the new priority level can always be interrupted by ready tasks with a higher
priority.
6SHFLDO7\SHV
Processing time plays no role in deciding which task becomes active. In addition to the
tasks priorities, the PXROS-Plus-version allows to schedule tasks with a WLPH VOLFLQJ
process. This process is explained in chapter 19.3.
([DPSOH
All examples in the Users Guide describe which tasks and handlers are active. For this
reason, no example was provided to demonstrate the scheduling mechanism
idividually.
&UHDWLQJ7DVNV
Chapter 3.1 demonstrated how tasks can be created with the function &UHDWH6WGWDVN.
This function offers applications a comfortable interface for creating tasks. When tasks
are created with this service, some parameters are set to default values, which is not
always acceptable. This chapter explains the actual process of creating a task creation.
Task-Create
Tasks are created with the service 3[7DVN&UHDWH. The parameter WV contains the
address of a structure of the type 3[7DVN6SHFB7. This structure is used to configure
the new task. The remainder of this chapter describes the individual attributes of this
configuration structure. It also explains how to chose suitable values for the various
attributes.
typdef struct
{
PxUChar_t *ts_name;
void (*ts_fun) (PxTask_t, PxMbx_t, PxEvents_t);
PxMc_t ts_mc;
PxOpool_t ts_opool;
PxStackSpec_T ts_taskstack;
PxSize_t ts_tblimit;
PxUChar_t ts_prio;
PxEvents_t ts_actevents;
PxTicks_t ts_timeslices;
PxAbortFrame_t ts_abortstack;
PxSize_t ts_abortstacksize;
PxTaskSchedExt_t ts_sched_extension;
PxArg_t ts_sched_initarg;
PxArg_t ts_privileges;
PxUInt_t ts_int_dummies[ ];
PxTaskContext_T *ts_context;
PxDataAddr_t *ts_addr_dummies[ ];
} PxTaskSpec_T, *PxTaskSpec_t;
If 3[7DVN&UHDWH is successful,
7DVN,G contains the new tasks task Id. If the service
fails,
7DVN,G is set to 0, and the return value provides information as to why the task
was not created.
WVBQDPH
WVBQDPH is the name given to the task. It is used to help debug the application and can
WVBIXQ
The function, WVBIXQ, contains the new tasks code. This does have certain restrictions,
e.g. the function must have a defined prototype. Details are given in chapter 3.2.
WVBPF
When memory is requested for any purpose, one must always specify the memory
class from which the memory is taken. Selecting the memory class often depends on
how important the request is within the application as a whole. If an application
provides several different memory classes, important requests should be directed to
their own exclusive memory class, or to the system memory class. This increases the
probability that the memory pool will have enough memory to satisfy the request.
Requests that are not as important tend to be directed to a memory class that is
provided for general use. At times, this may be unable to meet all requests.
HighTec recommends that tasks direct their normal memory requirements to this task
default by specifying 3;0F7DVNGHIDXOW. If the task changes its meaning, the memory
class need only be adjusted when it is created. Regardless of the tasks importance,
only truly important requests should specify the memory class (or the Id of a special
memory class) directly.
WVBRSRRO
The application must always specify the object pool from which a requested object
should be taken. This often depends on the importance of the request within the
application as a whole. If a number of object pools are available, important requests are
usually directed to a real object pool set up specifically for such requests, or to the
system pool. This increases the probability that an object will be provided in a timely
manner. Less important requests are usually directed to virtual object pools that are
provided for general use.
For the most part, the importance of an object request is related to the importance of
the requesting task. To make this work, a task is allocated a GHIDXOW REMHFW SRRO that
correspond to its importance. This object pool is set in the attribute WVBRSRRO when the
task is created. The task default can either be the system pool or an object pool
generated at run time.
HighTec recommends that all tasks direct their object requests to this default pool by
specifying 3;2SRRO7DVNGHIDXOW. If the meaning of a task changes, its object pool need
only be changed at the time of the tasks creation. Regardless of the tasks importance,
only truly important requests should take objects from the system pool or a specific real
object pool.
means that the calling tasks object pool is inherited by the request. The advantages of
using different object pools is described in chapter 10.1.
WVBWDVNVWDFN
Every task has its own stack, the configuration of which is defined by the structure
3[6WDFN6SHFB7 :
typedef struct
{
PxStackSpecType_t stk_type;
PxSize_t stk_size;
void *stk_src;
} PxStackSpec_T, *PxStackSpec_t;
There are two methods with which a task can be assigned a stack. While the task is
being created, memory is automatically requested for the stack. Alternatively, a task
may be given its task stack explicitely (i.e. an available memory area). These options
are explained in the following paragraphs. The init tasks stack is an exception. This is
explained in section 14.16.
$XWRPDWLF6WDFN5HTXHVW
This is the normal way to give a stack to the task. The stacks structure is set as
follows: VWNBW\SH receives the value 3;6WDFN$OORF. The stack size is given as the
number of LQWHJHUV in the parameter VWNBVL]H. VWNBVUF specifies the memory class that
allots memory to the stack.
The task creation function, &UHDWH6WGWDVN (chapter 3.1), creates the stack in this way,
using memory from the system memory class.
([SOLFLW6WDFN$OORFDWLRQ
If a free area of memory is specified for stack, the structures attributes should be set
as follows: VWNBVL]H contains the size of the available memory (this is the amount of
LQWHJHUV). VWNBVUF is given either the start or end address of the memory area. If the
start address is given, then VWNBW\SH must have the value 3;6WDFN*URZ. Conversely, if
the end address is given, VWNBW\SH must be given the value 3;6WDFN)DOO.
PXROS checks for stack overflow regardless of how the stack was created. For
backwards compatibility with earlier PXROS versions, one can forgo these tests if the
memory for the stack is already available. To do this, the stack should be configured as
follows:
begin, i.e. the memory areas lowest address for growing tasks, or the memory areas
highest address for falling stacks. Whichever the case, the prossesors alignment
should be taken into account.
The option to not check the stack should only be used in exceptional circumstances.
&KRRVLQJD6WDFN6L]H
Determining the stack size dependends on the tasks code: e.g. every function within a
nested call increases the demands on the tasks stack. In this scenario, not only the
functions prologue, but all local variables and (in some cases) parameters are placed
on the stack. This can make it quite difficult to estimate the stacks needs when starting
a new application.
If the chosen stack is too small, difficult to locate run time errors may occur as unknown
memory areas are written to. Although PXROS debug library tests every call to PXROS
services for stack overflow, it cannot guarantee every such instance will be registered.
HighTec recommends generosity when choosing the stacks size (assuming there is
enough memory available to the system). At the end of the development phase, the
system can always be optimized. With the realtime monitor, PXmon, a tasks maximum
requirements can be determined, and the stack size can be adjusted accordingly.
WVBWEOLPLW
WVBWEOLPLWspecifies the maximum amount of memory that a task can use for messages.
This can be seen as a sort of memory account that a task uses to control its use of
memory. When 3[0VJ5HTXHVW (see chapter 5.2) is called to request a message, the
size of the messages data area is subtracted from the tasks memory account. When
the message is released, this amount is deposited back in the account.
This limit cannot be turned off. If WVBWEOLPLW is 0, the task cannot request a message with
PxMsgRequest. If WVBWEOLPLW is -1 (= 0xfff..), the limit would have practically no influence,
because this is a relatively high value.
The memory limit helps ensure that a task does not use up all available memory for
messages. This can happen if messages are repeatedly sent and received, but are not
in turn released by the receiver. This can occur e.g. at the beginning of the
development phase when the application still contains errors. Applications can also be
protected from "memory gluttons" by using multiple memory classes (see chapter 7.4).
Excessive memory use can be easily located with the help of the realtime monitor
PXmon.
The task creation function, &UHDWH6WGWDVN (chapter 3.1), sets WVBWEOLPLW to -1.
WVBSULR
WVBSULR defines the tasks priority. The highest possible priority is always , and the
lowest depends on the processor and the PXROS variant used. On most processors,
this value is usually or . PXROS only uses relative values of the task priorities to
schedule tasks; their absolute values are not really important. No firm rules apply to
assigning task priorities, although the following guidelines should help: Tasks with a
small buffer, time critical tasks, tasks close to the hardware, and tasks that service
other tasks generally receive a high priority. Tasks that perform duties unrelated to the
hardware usually receive lower priorities. These include data evaluation tasks, tasks
that run displays and ROM checks.
WVBDFWHYHQWV
Normally a task starts UHDG\ to execute its code. Once a task is created, it can be given
an activating event, which causes it to ZDLW until the activating event is signalled.
WVBDFWHYHQWV holds the tasks activating events mask.
The task creation function, &UHDWH6WGWDVN (chapter 3.1) sets WVBDFWHYHQWV to 0. This
means that the task is ready immediately after creation.
WVBWLPHVOLFHV
PXROS normally allocates control over the processor based on a tasks priority and
status. Some versions of PXROS provide timeslicing as an additional scheduling
mechanism. It is described in chapter 19.3. WVBWLPHVOLFHV sets the numer of 3;526
WLFNV that make up a time slice. If WVBWLPHVOLFH is , the default is applied to the task, i.e
WVBDERUWVWDFNWVBDERUWVWDFNVL]H
These two attributes are only needed if the task uses the abort mechanism (see
3[([SHFW$ERUW as described in chapter 17). If this service is not used, WVBDERUWVWDFN
and WVBDERUWVWDFNVL]H can be set to 0. Tasks created with &UHDWH6WGWDVN can not use
the the abort mechanism since the standard task creation function sets both values to
0.
The abort stack must be provided when a task is created. WVBDERUWVWDFNVL]H sets the
size of the abort stack and contains the number of abort frames available on the abort
stack. The maximum number of nested calls to 3[([SHFW$ERUW is equal to the number
of abort frames.
The abort stack "falls" and is decremented before a value is saved on the stack.
WVBDERUWVWDFN holds the first address after the provided memory area. The processor
([DPSOH
fun1()
{
...
PxExpectAbort (EV_ABORT2, fun2);
...
}
fun2()
{
/* no PxExpectAbort */
}
TaskFunc()
{
...
PxExpectabort (EV_ABORT1, fun1);
...
}
main()
{
PxTaskSpec_T ts;
PxUChar_t *adr;
PxSize_t size;
....
/* Task initialization */
...
size = 2*PxGetAbortFrameSize();
PxMcTakeBlk(PXMcSystemdefault, (PxAligned_t **) &adr,
size);
ts.ts_abortstacksize = 2;
ts.ts_abortstack = (PxAbortFrame_t) &adr[size];
...
}
The task 7DVN)XQF contains two nested calls to 3[([SHFW$ERUW. This means two abort
frames are required, thus WVBDERUWVWDFNVL]H must have a minimum value of 2. The abort
stack is requested from the system memory class dynamically, thus
size = 2*PxGetAbortFrameSize()
bytes are required, beginning at the address DGU. The first address after the memory
area is DGU>VL]H@. Therefore, WVBDERUWVWDFN must be set to DGU>VL]H@.
WVBVFKHGBH[WHQVLRQWVBVFKHGBLQLWDUJ
WVBSULYLOHJHV
WVBLQWBGXPPLHV
These attributes are reserved for future extensions and should be set to .
WVBFRQWH[W
This attribute is extremely processor dependent and is described in detail in chapter 18.
WVBDGGUBGXPPLHV
These attributes are reserved for future extensions and should be set to .
)HDWXUHVRIWKH,QLWLDOL]DWLRQ7DVN
When setting the attributes of initialization tasks configuration structure, consider the
following features: the attribute WVBIXQ is not interpreted; instead, this function is
assigned the task code from which 3[,QLW is called. WVBPF must specify the system
memory class, and WVBRSRRO must refer to the system pool. WVBDFWHYHQWV has no
meaning for the init task.
The initialization of the task stack is also quite different compared to "normal". The
initialization task uses the programs user stack. The application configures this either
with the linker while the program is generated, or during the startup phase.
If the linker is used to configure the user stack, the following macros (defined in
S[GHIK) are recommended for setting the attribute WVBWDVNVWDFN:
ts_taskstack.stk_type =3;3URF*HW,QLWVWDFN6SHFW\SH
ts_taskstack.stk_size = 3;3URF*HW,QLWVWDFN6L]H
ts_taskstack.stk_src = 3;3URF*HW,QLWVWDFN6WDUW
This setup allows PXROS to uses processor specific information to recognize stack
overflow (if possible). These macros may require the declaration of certain external
variables, which can be accomplished with the macro 3;3URF,PSRUW,QLWVWDFN (also
defined in S[GHIK).
If the user stack is configured by an application specific startup, these entries should be
provided as described for creating "normal" task (see section 14.5.2).
([DPSOH
#include "pxdef.h"
...
PXProcImportInitstack;
...
main()
{
PxInitSpec_T is;
PxTaskSpec_T ts;
([DPSOH
The function %VS,QLW serves as a good example for the information described this
chapter. %VS,QLW is used to initialize PXROS, and it creates the tasks used in all of the
example programs contained in the Users Guide.
3;526,QLWLDOL]DWLRQ
$6WDQGDUG,QLWLDOL]DWLRQ
During initialization, PXROS creates a stock of objects and one task. The memory
required to create these object must be reserved on the target system. The parameter
ILUVWEONB VWDUW specifies the starting address of this memory block, and ILUVWEONBVL]H
indicates its size. During initialization, the V\VWHP PHPRU\ FODVV is generated, and the
allocated memory is assigned to this memory class. At run time, the application can
dynamically use the remaining memory (i.e. that not used to create the task and objects
during initialization) for memory requests, or to create objects and tasks. If PXROS is
given too little memory, resource requests made at run time could fail.
The easiest way to allocate memory is to define a global array of the type 3[$OLJQHGBW.
The size of this array should correspond to the entire amount of memory that PXROS
will manage. ILUVWEONBVWDUW must contain the arrays starting address. This method can
not always be used (e.g. c16x large model); however, one should chose the data type
PxAligned_t, which recognizes potential processor dependent alignments when
memory is requested. At run time, additional physical memory can be added to the
system memory class with 3[0F,QVHUW%ON.
([DPSOH
#define SYSMEMSIZE
(9000 + sizeof (PxAligned) - 1) / sizeof (PxAligned)
/* size in PxAligned units */
PxAligned_t Sysmem[SYSMEMSIZE];
During initialization, a stock of objects is created. REMQR defines the number of objects
that are created and added into the system pool. The memory required to create the
object pool, as well as the objects it contains, is taken from the system memory class.
The amount of objects required is equivalent to the maximum number of objects that
must exist DW WKH VDPH WLPH during the course of the application. This amount is always
selected on extremely application-dependent creiteria. Until more is known, REMQR
should be set generously, provided enough memory is available for the system memory
class. In this way one avoids run time problems caused by insufficient objects. At the
end of the development phase, the object requirements can be monitored at run time
with the realtime monitor PXmon. REMQR can then be optimized using this information.
Two more objects are created during PXROS initialization: the system memory class
and the system pool.
Afterwards, the LQLWLDOL]DWLRQ WDVN is created. Its task code is the program code through
which the PXROS initialization was called. Like every other task, the initialization task is
assigned a specific priority. This is set by in the value SULR.
Every task may receive an individual name. The initialization tasks name is defined in
QDPH. This value is only used to help debug an application, i.e. when using PXmon, it
Once PXROS has been successfully initilized, VWG,QLW returns initialization tasks task Id;
otherwise, it returns a . In addition to initializing PXROS, other important components
are initialized within VWG,QLW, e.g. the system clock is started. This service is not dealt
with in this chapter.
,QLWLDOL]DWLRQ'HWDLOV
PXROS is initialized with the service 3[,QLW. The parameter LV contains the address of a
structure of the type 3[,QLW6SHFB7, with which PXROS is configured. The following
sections describe this structures individual attributes. For example, these sections
explain how to select appropriate values for the various attributes. A standard, project-
specific initialization can be implemented with the function VWG,QLW, and used during the
development of the application. If errors occur, 3[,QLW returns a ; otherwise it returns
the initialization tasks task Id.
typedef struct
{
PxMcType_t is_sysmc_type;
PxSize_t is_sysmc_size;
PxAligned_t *is_sysmc_blk;
PxSize_t is_sysmc_blksize;
PxUInt_t is_obj_number;
PxUInt_t is_obj_namelength;
PxTaskSpec_t is_inittask;
PxInt_t is_monitoring;
PxInt_t is_int_dummies[ ];
PxGlobalSchedExt_T *is_schedext;
PxDataAddr_t *is_addr_dummies[ ];
} PxInitSpec_T, *PxInitSpec_t;
LVBV\VPFBW\SHLVBV\VPFBVL]H
Memory reserved for PXROS on the target system, is allocated to the system memory
class, wich is usually a memory class of YDULDEOH block size. For this reason,
LVBV\VPFBW\SH usually holds the value 3;0F9DUVL]HG, and LVBV\VPFBVL]H is
meaningless. This value is only used in exceptional cases in wich the system memory
class may have different type. These exceptions are not dealt with the Users Guide.
LVBV\VPFBEONLVBV\VPFBEONVL]H
LVBREMBQXPEHULVBREMBQDPHOHQJWK
Objects, like tasks, can receive names. Object names are also only used to help debug
an application, and cannot be used for identification. LVBREMBQDPHOHQJWK specifies the
maximum name length, and the size of each object increases accordingly. For this
reason, only the debug library allows one to name objects. LVBREMBQDPHOHQJWK is
therefore meaningless to the production library.
LVBLQLWWDVN
When PXROS is started, the initialization task is created automatically. Like every other
task, it must be configured. This is done via a structure of type 3[7DVN6SHFB7.
LVBLQLWWDVN holds the address of this structure. This structures attributes, and the
LVBPRQLWRULQJ
LVBPRQLWRULQJ regulates which additional monitoring job PXROS supports. Currently, the
3;0RQLWRU0HPRU\
3;0RQLWRU1HZV7DVNV
This service reports the creation of a task to the debugger. The realtime
monitor, Pxmon-RT require this information for debugging in realtime.
These values can be bitwise ored into LVBPRQLWRULQJ. Not all services are available in
every version of PXROS. Because monitoring is an application specific service, VWG,QLW
sets LVBPRQLWRULQJ to .
LVBLQWBGXPPLHV
These attributes are reserved for future extensions and should be set to .
LVBVFKHGH[W
With every task change, PXROS can execute user-defined functions.These functions
are provided in a structure of the type 3[*OREDO6FKHG([WB7. LVBVFKHGH[W contains the
structures address. This attribute is described in detail in chapter 19.1. Usually this
service is only available in the PXROS debug library. VWG,QLW does not use this attribute.
LVBDGGUBGXPPLHV
These attributes are reserved for future extensions and should be set to .
([DPSOH
The function %VS,QLW serves as a good example for the information described this
chapter. %VS,QLW is used to initialize PXROS, and it creates the tasks used in all of the
example programs contained in the Users Guide.
&RPPRQ7DVN'DWD
With PXROS, an application can store task-specific data and retrieve it globally. The
call 3[6HW$SSLQIR LQIR writes this task-specific data to LQIR. 3[*HW$SSLQIR is used to
read the stored information later.
For example, this feature can be used to provide a task with a special identifier that
must be given when connecting to a server. This identifier can be passed as a
parameter from deeply nested functions. It could also be saved task-globally, thus
giving every service function access to the identifier as needed.
([DPSOHZLWKRXWXVLQJWDVNVSHFLILFGDWD
TaskFun()
{
PxInt_t Id;
....
ServerOpen (&Id, ...);
....
Service1 (Id, ...);
....
Service2 (Id, ...);
....
Service3 (Id, ...);
....
Service4 (Id, ...);
....
}
([DPSOH8VLQJWDVNVSHFLILFGDWD
TaskFun()
{
....
ServerOpen (&Id, ...);
PxSetAppinfo (Id);
....
Service1 (....);
....
Service2 (....);
....
Service3 (....);
....
Service4 (....);
....
}
void Service? ()
{
PxInt_t Id;
Id = PxGetAppinfo();
.....
}
In this way, the identifier remains unnoticed by the service function user. Also, changes
can be introduced at individual points. Changing the data type only effects the datas
actual user functions.
If a number of different modules use task-specific data, access must be controlled such
that data is not overwritten, as well as to ensure that the desired data is accessed. With
this in mind, data should not be stored with 3[6HW$SSLQIR directly; instead, an
extendible data structure should be created, to which the different data from the
individual modules can be written. Chapter 23.1 describes a module which regulates
secure access to services.
([DPSOH
The following source code can be found in the directory DSSLQIR on the accompanying
disk.
([F
Both tasks use a function called IXQF. The task-specific data saved in the two tasks
contains the respective other tasks Id. Each task is signalled an event.
PxArg_t info;
PxTask_t task;
(1) info = PxGetAppinfo ();
(2) task = (PxTask_t) info;
(3) PxTaskSignalEvents (task, EV_1);
7DVN)XQF
7DVN)XQF
GHWDLOOHGSURFHVVGHVFULSWLRQ
With
7DVN saves WDVNs Id in its task-specific data. It then waits for the signal EV_1 (6).
While 7DVN is waiting, 7DVN becomes active and stores WDVNs Id in ist task-specific
data ((8) and (9)). 7DVN calls IXQF (10), where the tasks data is evaluated:
The task whose Id is saved in the task-specific data, is signalled the event EV_1 (3). In
this case, 7DVN becomes active and also calls IXQF (7). After evaluating the task-
specific data, EV_1 is signalled to WDVN (3). 7DVN again waits for EV_1, and 7DVN
continues executing its code where it was interrupted.
7DVN returns immediately from the function IXQF, as the event has already been
signalled. )XQF is then called again (10), and the programm continues in this way ad
infinitum.
$ERUW0HFKDQLVP
6XPPDU\
PXROS has the ability to abort functions when certain user-defined events occur. The
abort mechanism is realized with the service 3[([SHFW$ERUW.
This service is given a number of events to trigger the abort. If one of these events is
signalled to the calling task, PXROS stops the function call immediately.
3[([SHFW$ERUW returns the events actually that triggered the abort. If the function ends
"naturally", the abort function returns a 0. Only properly configured tasks can use this
function. If resources are requested, the calling task must ensure that they are not lost
when the task is aborted.
8VLQJWKH$ERUW0HFKDQLVP
The function IXQ is called, but is aborted if an event contained in the event mask,
HYHQWV, is signalled to the calling task. 3[([SHFW$ERUW returns the event(s) that
triggered the abort. If IXQ terminates normally, 3[([SHFW$ERUW returns a . IXQ always
loses its pontential return value. When 3[([SHFW$ERUW is called, the function IXQ must
be declared such that its parameters are transferred over the stack (i.e. not over the
register), and they must be specified after the actual function name (e.g. IXQ).
The abort mechanism can be used e.g. when a task activity is to be stopped by an
emergency off switch. In this example, the interrupt handler that reacts to the switch
signals an abort event to the relevant task.
A task must be configured to use the abort mechanism. This task requires an DERUW
VWDFN, the size of which corresponds to the deepest level of nested calls to
3[([SHFW$ERUW (see chapter 14.10).
([DPSOH
InterruptCode()
{
/* Interrupt for emergency-off */
PxTaskSignalEvents_Hnd (TaskId, EV_INTR);
}
TaskCode()
{
PxEvents_t ev;
....
ev = PxExpectabort (EV_INTR, act);
if (ev)
{
/* "act" aborted */
}
else
{
/* "act" run through to end */
}
....
}
The function called by 3[([SHFW$ERUW can call 3[([SHFW$ERUW as well; however, this
deactivates the RXWHU DERUW IUDPH (i.e. the first call to the abort mechanism). The outer
abort frame must be reactivated manually after returning from the iQQHU DERUW IUDPH
(see sections 17.3 and 17.4).
$FWLYDWLRQDQG'HDFWLYDWLRQRIWKH$ERUW0HFKDQLVP
A task can activate or deactivate the abort mechansim by changing its PRGH with the
appropriate services. The task mode is of type 3[7PRGHBW. This data type contains a
bit mask that specifies which of the following PXROS mechanisms are temporarily
GHDFWLYDWHG:
Aborts
Remote Procedures
Remote Handler
Timeslicing
The task mode is set by bitwise oring of the desired, corresponding values:
PXTmodeDisableAborts
PXTmodeDisableRemprocs
PXTmodeDisableRemhnds
PXTmodeDisableTimeslicings
([DPSOH
void fun()
{
PxTmode_t mode;
....
/* determine task mode and deactivate the abort
mechanism */
mode = PxSetModebits (PXTmodeDisableAborts);
/* protected run before abort */
....
,PSOLFLWGHDFWLYDWLRQZLWK3;5266HUYLFHV
Certain PXROS services can remove events from a tasks event mask. These includes
the services, 3[$ZDLW(YHQWV, 3[B(Y:DLW services, and 3[([SHFW$ERUW itself.
These services automatically deactivate the abort mechanism, but they do not
reactivate it.
([DPSOH
fun1()
{
....
ev = PxExpectAbort (EV_INTR1, fun2);
....
}
void fun2()
{
....
ev = PxExpectabort (EV_INTR2, fun3);
....
}
In this example, IXQ can only be aborted by the signal EV_INTR2 (i.e. EV_INTR1 does
not abort IXQ). If IXQ ends normally, IXQ will not be aborted by the signal EV_INTR1,
because the call to 3[([SHFW$ERUW (in fun2) deactivates the abort mechanism.
Remember, when using these services, the abort mechanism must be reactivated
manually after the function terminates.
([DPSOH
fun1()
{
....
ev = PxExpectAbort (EV_INTR1, fun2);
....
}
void fun2()
{
....
ev = PxExpectabort (EV_INTR2, fun3);
PxClearModebits (PXTmodeDisableAborts);
....
}
Now the abort mechanism is reactivated after IXQ is terminated (i.e. either naturally or
via an abort); however, EV_INTR1 does not cause an abort as long as IXQ is running.
Normally, the abort mechanism should remain effective, regardless of the level of
execution. This is achieved with services that deactivate the abort mechanism, but still
react to possible abort events. If an abort event is signalled to the task, the task can
trigger the abort mechanism by reactivating it, and resignalling the received event to
itself.
([DPSOH
fun1()
{
....
ev = PxExpectAbort (EV_INTR1, fun2);
....
}
void fun2()
{
PxEvents_t ev, abort_ev;
PxTmode_t mode;
....
....
mode = PxSetModebits (PXTmodeDisableAborts);
if ((mode & PXTmodeDisableAborts) == 0)
abort_ev = PxGetAbortingEvents();
else
abort_ev = 0;
....
}
3[*HW$ERUWLQJ(YHQWV returns the events that aborted the current activity, provided the
3URWHFWLQJUHVRXUFHV
When using the abort mechanism, remember that resource requests require special
protection. For example, if memory is requested for a function that uses
3[([SHFW$ERUW, memory can be lost if the function is aborted.
([DPSOH
....
alloc (&mem);
....
....
free (&mem);
....
}
TaskCode()
{
....
ev = PxExpectabort (EV_INTR, act);
....
}
If the task is aborted (as specified in DFW) between the calls to ALLOC and FREE, the
memory is lost. In this case, the memory is accessed via the local variable PHP, which
is no longer available after the abort.
To prevent the loss of resources when using 3[([SHFW$ERUW, the abort mechanism
can be turned off between the request for resources and their release (see section
17.3). A second method of dealing with this problem by referencing the resources
outside of the abort frame.
In the previous example, the requested memory was lost because the reference to the
memory was no longer available outside of the function. The reference was saved in a
local function variable. This problem is avoided by saving the reference in a transfer
parameter.
([DPSOH
Before the call, PHP is set to 0 and sent as a parameter to DFW. Once released, PHP
receives the value 0 again. If DFW is aborted, the memory can still be accessed and
released from the function IXQF via the parameter PHP. The PXROS services for
requesting and releasing memory are protected against the abort mechanism, so an
abort occurring while such a service is active will not cause problems.
This method has the disadvantage that all resource requests in 3[([SHFW$ERUW must
be known in advance. This can be problematic when using and implementing standard
modules or library functions. For this reason, such functions usually protect their
resource usage against the abort mechanism by periodically deactivating it (see section
17.3); otherwise the functions are not used in 3[([SHFW$ERUW.
The most flexible means to deal with this potential problem is to have the called
function automatically recognize what sort of cleanup work is necessary after the abort
mechanism is used. Chapter 23.3 describes a module that supports this service.
([DPSOH
The source code for the following example can be found on the accompanying disk in
the directory DERUW.
([F
aborted.
7DVN)XQF
for (;;)
{
(2) PxToStart (&to);
(3) ev = PxExpectAbort (EV_INTR, CountFunc, &count)
(4) if (ev)
{
(5) start += 100;
}
else
{
(6) start = 0;
}
(7) count = start;
}
GHWDLOOHGSURFHVVGHFULSWLRQ
Task1 starts a timeout set for 10 PXROS ticks ((1) and (2)). Afterwards,
&RXQW)XQF is called in 3[([SHFW$ERUW. The call includes the address of the variable
FRXQW as ist parameter. The function is aborted when the timeout signals EV_INTR to
Task1. If this is the case, the return value HY will not equal 0 (4) and VWDUW is larger;
otherwise, VWDUW is reinitialized with 0 (6).
FRXQW is set to the value of VWDUW (7), and the process begins again. &RXQW)XQF is not
aborted by the timeout, if VWDUW is so large, that FRXQW in &RXQW)XQF is incremented to
20000 before the timeout expires.
3URFHVVRU'HSHQGHQW6HUYLFHV
PXROS provides the application with a common interface underneath which processor
dependent differences are hidden. This includes the interrupt interface. There are even
services available for specific processors. Except for the interrupt interface, the
services described in the following pages are required only rarely in a PXROS
application.
3;526IRU6LHPHQV&[3URFHVVRUV
,QWHUUXSW,QWHUIDFH
The module for the interrupt interface are distributed in source from along with PXROS.
Using special compiler options, the interrupt interface can be adapted to the best use of
the target hardware.
'HILQLJ+DQGOHUV'\QDPLFDOO\
Calling 7UDS,QVWDOO&KDQGOHU (at run Time) installs an interrupt handler for the hardware
interrupt specified. This allows one to install arbitrary functions that react to certain
interrupts as they occur; however, certain preparations are usually necessary to use
interrupt handlers. These preparations can potentially increase the interrupt latency
time.
Before an interrupt handler is installed, the interrupt vector table must be initialized. If
the vector table is located in RAM, it can usually be initialized with the function 7UDS,QLW.
For all other interrupts for which a handler is dynamically defined, the call to
7UDS'LVSDWFK should be used.
'HILQLQJ+DQGOHUV6WDWLFDOO\
Usually the handler is defined before the programm is created, and it stays in place for
the duration of the application. With the appropriate macros, a handler can be installed
statically in the source code when the function is declared. The declaration macros are
described in the header S[VWUDSK. The interrupt latency time is noticeably less than
with a static definition. During run time, the application must call 3[6WUDS,QLW before the
first interrupt takes place. This function is only available in the GNU C16x C/C++
compiler version 3.1 and beyond.
7UDS9HFWRU7DEOHLQ(3520
The C16x-processors trap vector table is located in the 512 bytes beyond the address
0. If there is no RAM there, the vector table can not be dynamically changed. Under
these circumstances, the vector table must be completely configured while the
programm is created. In some applications (e.g. Pxmon), the trap vector table must be
modifiable during run time.
In such cases, a copy of the table can be maintained in RAM. Jumps are entered in the
corresponding points of the "RAM Vectab" as with the trap table. The service functions
must be modified such that they operate on the "RAM Vectab" instead of the trap
modules. When the modules are translated, the macro 75$39HFWDE is set to the
starting address of the RAM vector table. The compiler is then called as follows:
The starting address of the RAM Vectab is indicated above as ;;;;. If 7UDS9HFWDE is
set to -1, no vector table exists in the RAM. If 75$39HFWDE is not defined, the vector
table is located at the address 0.
A firmware monitor used for debugging must be generated to operate on the RAM
Vectab, as it must modify the table during run time.
7DVN&RQWH[W
The WDVN FRQWH[W for C16x Processors is used in PXROS versions that support mixed
memory models. The task context is meaningless in other versions, and all structures
or functions pertaining to it are empty.
typedef struct {
PxInt_t c166_dpp0;
PxInt_t c166_dpp1;
PxInt_t c166_dpp2;
} PxTaskContext_T, *PxTaskContext_t;
In this way, the relevant processor registers for each task can be saved independent of
all other tasks or initializations.
Using the function 3[7DVN,QVWDOO&RQWH[W ,
FRQWH[W is defined as the new task context.
3[*HW7DVN&RQWH[W copies the calling tasks context into the address specified in
FRQWH[W .
At the beginning of an application, a newly created task always receives the task
context indicated in the structure PxTaskSpec_T; specifically, that described in
WVBFRQWH[W. If the value is , the task context is inherited from the creating task.
3;526IRU,QWHO[3URFHVVRUV
,QWHUUXSW,QWHUIDFH
7DVN&RQWH[W
typedef struct {
unsigned long t_esp1;
unsigned long t_ss1;
unsigned long t_esp2;
unsigned long t_ss2;
unsigned long t_cr3;
unsigned long t_ldt;
char Bitmap [ (MAXTSSIOADDR+1) /NBPB ] ;
} PxTaskContext_T, *PxTaskContext_t;
In this way, the relevant processor registers for each task can be saved independent of
all other tasks or initializations.
With 3[7DVN,QVWDOO&RQWH[W,
FRQWH[W is defined as the new task context. If one of the
attributes (except %LWPDS) is set to [IIIIIIII in *context, the corresponding value in the
task context is not changed. 3[*HW7DVN&RQWH[W copies the calling tasks context into
the address specified in FRQWH[W. The values of 0$;766,2$''5 and 1%3% are
defined in pxdef.h.
At the beginning of an application, a newly created tasks always receive the task
context indicated in the structure PxTaskSpec_t; Specifically, that described in
WVBFRQWH[W. If the value is , the task context is inherited from the creating task.
6HUYLFHVRIWKH3;5263OXV9HUVLRQ
Some PXROS services are only available in the PXROS-Plus version. These services
are not included in the standard distribution since they often either increase run time or
memory requirements. They are rarely needed, but some can be quite useful at times.
This chapter touches on such services. For more information, please contact HighTec.
6FKHGXOLQJ([WHQVLRQV
During a task change, PXROS can execute certain user-defined functions. This service
is usually available in the debug library of the standard PXROS distribution. The
PXROS-Plus version also allows to assign tasks specific scheduling extensions; in
other words, PXROS executes specific, user-defined functions whenever a task is
activated or deactivated.
Scheduling extensions greatly increase the time required for each scheduling function.
Furthermore, more space is required for the task control structure. The task control
block of every task is enlarged whenever a scheduling extension is used. This is done
to create space to save data for future processing.
typedef enum {
PXSchedExtForeignHnd_Bgn,
PXSchedExtForeignHnd_End,
PXSchedExtOwnHnd_Bgn,
PXSchedExtOwnHnd_End,
PXSchedExtSched,
PXSchedExtRemproc_Bgn,
PXSchedExtRemproc_End,
PXSchedExt_LastCode
} PxSchedExtCause_t;
With a variable of type 3[6FKHG([W&DXVHBW, PXROS reports what triggered the tasks
activation or deactivation. Possible triggers include: task changes (3;6FKHG([W6FKHG),
a software interrupt handler that was installed by a task (3;6FKHG([W2ZQ+QGB%JQ or
-B(QG) begins or end, the starting or ending of a software interrupt handler that was
installed by a different task (3;6FKHG([W)RUHLJQ+QGB%JQ or -B(QG) and the starting or
ending of a remote procedure ( 3;6FKHG([W5HPSURFB%JQ or B(QG).
*OREDO6FKHGXOLQJ([WHQVLRQV
Global scheduling extension can produce scheduling statistics, which can be evaluated
with PXmon. This can provide far-reaching information about the systems behaviour.
This extension uses a data structure to record when a task is activated or deactivation,
the tasks run time, and the scheduling took place. Several functions are available for
this extension.
typedef struct {
PxUInt_t gse_size;
void (*gse_init) (void *);
void (*gse_save) (void *, PxSchedExtCause_t);
void (*gse_restore) (void *, PxSchedExtCause_t);
} PxGlobalSchedExt_T, *PxGlobalSchedExt_t;
JVHBVL]H contains the size of the data to be processed. PXROS adds space to every
task control block and sets it to 0. When the task is activated for the first time, its data
is initialized with JVHBLQLW. JVHBUHVWRUH is called when the task is activated and
JVHBVDYHis called when the task is deactivated
These functions must pass their parameters via the stack. They are executed on the
handler level and thus may only use handler services. All functions use the first
parameter to store the starting address of the data area provided in the task control
block. In an additional parameter, both JVHBVDYH and JVHBUHVWRUH receive information
about what triggered the scheduling.
7DVN6FKHGXOLQJ([WHQVLRQV
The task-specific scheduling extension is normally used to multiplex specific data for
several tasks. For example, a normally global variable HUURU, can be multiplexed for
multiple tasks. When a task is activated, it writes a value to HUURU. The task can access
HUURU directly, and HUURUs current value is saved when the task is deactivated. The task-
typedef struct {
PxUnit_t tse_size;
void (*tse_init) (void *, PxArg_t);
void (*tse_save) (void *, PxSchedExtCause_t);
void (*tse_restore) (void *, PxSchedExtCause_t);
} PxTaskSchedExt_T, *PxTaskSchedExt_t;
WVHBVL]H contains the size of the data that is to be processed by the functions. PXROS
adds space to every task control block and sets it to 0. When a task is activated for the
first time, its data is initialized with WVHBLQLW. The initialization value is passed to the
second argument and stored in the structure when the task is created (see chapter
14.11). WVHBVDYH is called, when the task is deactivated, and WVHBUHVWRUH is called when
it is activated.
These functions must pass their parameters via the stack. They are executed on the
handler level and thus may only use handler services. All functions use the first
parameter to store the starting address of the data area provided in the control block. In
an additional parameter, both WVHBVDYH and WVHBUHVWRUH receive information about what
triggered the scheduling.
+DQGOHU6HQG
In the standard version of PXROS, a handler cannot send or release messages. This
service is rarely necessary; however, the services 3[0VJ6HQGB+QG,
3[0VJ6HQGB3ULR+QG and 3[0VJ5HOHDVHB+QG are provided in PXROS-Plus to offer
this feature. The parameters correspond to the equivalent task services (see chapter
5). To enable handlers to release messages, a specific task functions as a PHVVDJH
UHOHDVHVHUYHU. This server is created with the function 3[0VJUHOVUY,QLW .
In this version, handlers can not create messages or wait for them to arrive. Handlers
access messages either through a mailbox handler, or with a global variable serviced
by a task that enters the Id any messages created or received on the handlers behalf.
7LPH6OLFLQJ
PXROS priority based scheduling always gives control of the processor to the ready
task with the highest priority. This task cannot be interrupted by a task at the same
priority level. It stays active until it is either interrupted by a task with higher priority, or
until it enters a wait state.
Every task is allocated a specific time credit in a timeslicing account. The active tasks
time credit is decremented with every PXROS tick. Once these credits are expended,
PXROS activates the next ready task at the same priority level. PXROS then restocks
the first tasks account. If no other tasks are ready, the active continues processing.
The reload value of a tasks time account is set when the task is created. This value
can be called up and changed at run time. 3[*HW7LPHVOLFHV returns the calling tasks
current reload value. 3[6HW7LPHVOLFHV sets the reload value in WLFNV PXROS ticks. If
ticks is 0, the task does not participate in the time slicing process.
8VLQJ3;526ZLWK(3520V
PXROS applications can usually run in EPROMs without restrictions; however, one
should consider potential restriction intoduced by the development environment and the
hardware used. These have little to do with PXROS itself, but are generally related to
the interrupt interface. The remainder of this chapter concerns almost all basic EPROM
applications.
The following sections mention some things to look for when creating an application for
specific target processors and development environments.
6LHPHQV&[)DPLO\ZLWKWKH*18'HYHORSPHQWWRROV
,QWHUUXSW,QWHUIDFH
The interrupt interface is established via the vector table, which is located at address 0.
configuring the vector table depends on whether the related interrupt handler is defined
dynamically, i.e. at run time with 7UDS,QVWDOO&KDQGOHU, or if it is defined statically at the
beginning of an application. In the first case, a jump to the function B7UDS'LVSDWFK
must be entered in the interrupt vector table for each interrupt:
The interrupt hadler can be defined statically (as the function is declared) using the
macros inS[VWUDSK. In this way when the application is compiled, the linker specifies a
direct jump to the interrupt handler in the vector table.
&RPSLOHU2SWLRQV
To create an application that can run on an EPROM, the option PURPDEOHFRGH must
be specified when translating each module. Other options are not required.
The file FUWV, which is distributed with the GNU development tools, contains the code
for the startup phase. It initialize the hardware and perform other jobs, such as setting
the BBS (i.e. Block Storage Section) to 0, or initializing application data. FUWV may
need to be adapted to the specific hardware used.
/LQNHU0DS)LOH
C16x executables consist of data, text and BBS areas. The codes complete WH[W area
must be saved in map file for the EPROM. The GDWD area contains constant data and
must be saved to the same address area. The BBS area contains non-initialized data
and must be saved to an area that also contains RAM. In certain memory models
(specmed, small, compact) the data page pointers must be initialized such that they
cover both the BBS DQG data areas.
3RWHQWLDO3UREOHPV
The application is usually developed on a target system that contains RAM throughout
the address areas used. In testing phase, the application is loaded onto the processor
with a firmware monitor and a debugger. If no bugs are found, then the application
should run on the EPROM. Sometimes bugs appear in the transition, that were not
discovered during the testing phase.
This can often be traced to the startup file FUWV, which may need to be adapted to the
hardware used. Such bugs are not found during the Ram test since the firmware
monitor configurations certain hardware features automatically, and the debugger
automatically sets the applications RAM area (BBS) to 0.
For example, the monitor may activate the interrupts and deactivate the watchdog, in
which case the startup file does not need to perform these activities. In the EPROM
version however, a monitor is not normally used, so these jobs must be correctly
executed in the startup file. If this is not done, the problems drescibed above may
occur.
8VLQJ3[PRQ3[PRQ57
A debugger is usually used to test running programs for errors. It communicates e.g.
over a serial interface with a firmware monitor on the target system. The program can
be loaded and started, breakpoints can be set, assembler code evaluated, and
variables can be read and modified.
To do this, the program must first be stopped. This can cause problems for applications
that communicate with other equipment. When the program is stopped, timeouts may
run out on the other end, and in some cases connections are dismantled. Furthermore,
it is difficult to receive PXROS-specific information from a standard debugger, e.g. the
condition of tasks, resource usage or the contents of mailboxes.
3;PRQ is a special task provides PXROS-specific data while the V\VWHP LV UXQQLQJ. It
can also acces numerous firmware monitor services, for example to alter variables. It
can not be used to set breakpoints, single step the application, etc. Since PXmon is
part of the actual application, it FDQQRW be used to load the program into the target
system.
PXmons most important function is providing PXROS-specific data. This can be used
to determine a tasks stack requirements, or to report the amount of memory or objects
in use. PXmon can also display the scheduling behaviour over a certain time period, or
the sum of the tasks running time. The realtime monitor can temporarily suspend the
tasks execution, which can be used to provoke problem situations and thereby test the
applications reaction. Furthermore, PXmon can influence the running system with user-
defined commands.
3;526DQG&
In GNU-CC, the operator "new" is typically mapped to the library function "malloc()",
operator "delete" to the library function "free()". These functions must be reentrant
coded to be usable in a PXROS multitasking environment. For this reason one must
use special versions that come with a PXROS release.
Object oriented languages, such as C++, use so-called FRQVWUXFWRUV to statically
instanciate (object) classes. Constructors are performed before the program flow
reaches "main()".
A serious synchronization problem arises if a constructor in a PXROS system makes
use of the operator "new", since the memory management of PXROS isnt initialized at
that time.
The GNU & compiler handles constructors within a helper function called
"BBPDLQ", that is automatically called when "main()" is compiled.
To ship around the above mentioned synchronization problem, one has to compile the
"main()" function with the & compiler (that doesnt call __main() ). After the initialization
of PXROS, one has to call __main() explicitly. No access or reference to the static
object classes are allowed between main() and PxInit()!
void
main(void) {
InitHardware();
...
PxInit (...);
__main(); // handle global constructors
...
}
&UHDWLQJD3;526$SSOLFDWLRQ
This chapter describes how a PXROS application is created with the GNU development
tools. It does not go into great detail, and not all applications are mentioned. The
purpose of this chapter is to enable the user to create a simple PXROS application as
quickly as possible. Processor-specific features are dealt with in chapter 18.
To create a PXROS application, one theoretically need only link the interrupt interface
modules and the desired PXROS libraries to the compiled modules.
6LHPHQV&[3URFHVVRUV
0DNHILOH
This section describes a simple makefile that creates a PXROS application for this
processor. The makefile is provided in ASCII form in the directory JHQHUDWHF[. It
was saved as PDNHILOH[. It was designed for use on an UNIX system. Certain
modifications are required for MS-DOS systems, especially the definition of 93$7+.
With UNIX, directories are separated with a colon (":"). In contrast, MSDOS uses the
semicolon (";") since the path name often contains a colon (":"). Details are provided in
the GNU handbook in the chapter JPDNH.
In the following description, compiler calls and options are not explained as they are
beyond the scope of the Users Guide. If certain points are unclear, please refer to the
relevant parts of the development tools handbook. Before continuing, a few comments:
A makefile contains the general rules to control certain processes. In this case, these
rules are used to create a program and the objects that belong to it. The rules specified
in the makefile have the following form:
e.g.:
module.o: module.c
gcc166 -g -0 -c -mregparm -mspecmed module.c
or
When creating a makefile, macros can be quite useful. These allow one to globally
change the values associated with path and another variable names. They also serve
to provide the makefile with the clearer structure. Macros are defined in makefile as
follows:
PXROS = /home/pxros
CC = gcc166
COPTS = -g -o
and are accessed by a dollar sign ("$") followed by the macros name in parens:
$(MACRONAME)
They can be used within the definition of another macro. For example:
#
# Makefile of a PXROS application for C16x processor
#
#
# Macro definitions:
# Memory model
MODEL = specmed
EXT = _x
# PXROS paths
PXROS = /home/pxros/pxros$(EXT)
PXINC = $(PXROS)/include
PXSRC = $(PXROS)/src
PXLIB = $(PXROS)/lib/pxutils$(EXT) .a $(PXROS)/lib/pxdbg$(EXT)
.a
# Compiler configuration
CINCS = -I$(PXINC) -I../include
COPTS = -c -g -0 -Wall -m7
CDEFS = -DTEST
CFLAGS = $(CINCS) $(CDEFS) $(COPTS)
CC = gcc166 -m$(MODEL) -mromable-code -mregparm
# Linker Configuration
LD = $(CC)
LDFLAGS = -map prg16x.map -loc prg16x.loc
# Modules:
TRAPOBJS = addr.o pxtrap.o pxtrp$(EXT).o
OBJECTS = $(TRAPOBJS) mod1.o mod2.o
HighTec EDV-Systeme GmbH 150 20. Mai 1996
PXROS V4 Users Guide Version 1.0
# Directory paths. The source files contain
VPATH = $(PXSRC):../src
'HVFULSWLRQ
At the beginning of the makefile, various macros are defined. These correspond to the
memory model used to create the application:
MODEL = specmed
EXT = _x
PXROS = /home/pxros/pxros$(EXT)
PXINC = $(PXROS)/include
PXSRC = $(PXROS)/src
PXLIB = $(PXROS)/lib/pxutils$(EXT) .a
$(PXROS)/lib/pxdbg$(EXT) .a
The following lines in the makefile are used to configure the compiler, e.g. compiler
options for the paths that contains the headers to be included.
LD = $(CC)
LDFLAGS = -map prg16x.map -loc prg16x.loc
Now a macro is defined for hte objects that make up an application. This is used to
facilitate access to these objects.
93$7+ specifies the directories in which source files are located. These files are used
to create objects. As mentioned above, the individual directories must be separated
with a colon (":") under UNIX, and by a semicolon (";") on MS-DOS systems.
After the macro definitions, the rules for creating the program follow. The macros
defined earlier are used extensively in this section:
prg: $(OBJECTS)
$(LD) $(LDFLSGS) -m$(MODEL) -o prg $(OBJECTS) $(PXLIB)
This sample makefile only contains rules for creating one object. Other objects are
made with gmakes LPSOLFLW UXOH. This means a standard process is used to create every
object that does not have exclusive rules. To create the object ;;;R, the directories
specified by the macro 93$7+ are searched for the file ;;;F. If ;;;F is found, the
object ;;;R is created as follows:
Notice why the macros for configuring the compiler were given earlier. The implicit rule
is advantageous for applications with many individual objects.
6SHFLDO1RWHV
Applications for C16x processors can be created in various memory models. Single
objects must be created with the appropriate options. For this reason, PXROS is
provided in different versions for the individual memory models. These models can be
recognized by their extensions BV, B[, BO, etc.
The map file informs the linker where text, data, or BBS are located on the target
hardware (i.e. the address area). Keep in mind that for different memory models
(compact and specmed), the data page pointer of the processor should be defined in
the map file such that data and BBS areas are covered by the DPPs. It is also
important that '33 receives the value ; otherwise PXROS will not function properly.
A firmware monitor is usually used during the development phase, and in some cases it
must be loaded onto the target hardware. It requires memory for data, and these areas
may not be released for the application.
With the locater file, one can specify the address of where certain application
components are placed. In principle, the linker places application components
anywhere within the address area that is specified in the mapfile. Fixed definitions can
be made for the loc file. This is important for the interrupt vector table because it should
normally be located at the address .
If the makefile does not specify where to place the startup code, the interrupt vector
table, the map file, or the loc file, the standard files distributed with GNU are used.
These are nott necessarily compatible with the target hardware used. This can lead to
problems when trying to load the application onto the target system.
8WLOLW\/LEUDU\
0DQDJHPHQWRI*OREDO7DVN'DWD
PXROS allows the application to save task specific data, and thus implements a means
to access task-global data. If different modules use task-global data, the access to the
data must be strictly controlled, so that no data is overwritten or the wrong data is
inadvertently accessed. With this in mind, the data should not be saved to one location
with 3[6HW$SSLQIR; rather, the data should be placed in an expandable data structure
associated with each task. The module S[XDSSLQFcontains various services that allow
safe access to the application data.
3[X$SSLQIR6HW&RPS3[X$SSLQIR8SGDWH&RPS
&RPSRQHQW is the initial address of a memory area that contains the data to be saved.
&OHDQXS specifies the address of a function with e.g. releases resources when the task-
specific data is no longer needed. &OHDQXSs parameter contains the datas initial
address. If the FOHDQXS function is not required, is specified for this attribute.
3[X$SSLQIR*HW&RPS
3[X$SSLQIR*HW&RPS provides the initial address of the data saved at LQGH[. If no data
is present, is returned.
3[X$SSLQIR&OHDQXS&RPS
The data area specified in LQGH[ can be released with 3[X$SSLQIR&OHDQXS&RPS. This
service calls the cleanup function specified in the 3[X$SSLQIR6HW&RPS call. When
3[X$SSLQIR&OHDQXS is called, all task-specific data is erased, not just the data stored
at a specific index.
1HZ0HPRU\&ODVVHV
PXROS can manage the entire range of dynamically allocateable memory available to
the application. To improve data security and reduce processing time, this memory is
often split up into a number of PHPRU\ FODVVHV (see chapter 7). The services provided
in the modules S[XEONBIF and S[XEONBYF can be used to create new memory classes
and allocate the memory they hold.
3[X&UHDWH)L[EON3RRO
3[X&UHDWH)L[EON3RRO create a IL[HG block memory class of VL]H bytes. This memory
class contains QR memory blocks. Using the service 3[0F5HPRYH%ON, the memory is
taken from the memory class specified in VUFPF.
SRROPF contains the new memory
class Id. Once created, up to QR blocks are available from the new memory class. No
overhead is incurred for the memory management realized with this mechanism.
3[X&UHDWH9DUEON3RRO
3[X&UHDWH9DUEON3RRO creates a new YDULDEOH block memory class. This memory class
receives VL]H bytes of memory from its source memory class VUFPF
3RROPF contains
the new memory class Id. The new memory class can not distribute the entire VL]H
bytes of memory, since every request for a memory blockt requires additional bytes of
overhead for memory management.
&OHDQLQJ8S$IWHUDQ$ERUW
PXROS provides the means to abort an active function if certain predefined events
occur. The a ERUWPHFKDQLVP is implemented with the service 3[([SHFW$ERUW.
There are various methods of cleaning up after an abort. It is best if the function
recognizes what sort of cleanup is required. For this reason, special cleanup structures
have been developed. These structures are linked to FOHDQXS VWDFNV, which note what
sort of cleaning work is required after nested calls have occurred. In order to perform
the necessary work, the cleanup stack reside outside of the call to 3[([SHFW$ERUW.
These structures are associated with a cleanup stack, which holds the information
related to the cleanup functions. When an abort occurs, the corresponding cleanup
functions are activated. FOHDQXSBIXQ is the cleanup function itself, and FOHDQXSBDUJ
holds the argument to be passed on to the function. FOHDQXSBQH[W links these
structures together.
The cleanup structure must still be accessible from outside of the aborted function. In
other words, this structure cannot reside on the local stack. It must either be allocated
dynamically, or stored globally. FOHDQXSBPF specifies the memory class that the
structure was requested from. This is used to later release the memory used. If the
memory does not come from a memory class, the structure is static, and FOHDQXSBPF is
0.
The services are used to initialize a cleanup stack, extend it, to activate the functions
kept on the cleanup stack, and to dismantle the cleanup stack when it is no longer
needed. The cleanup stack is usually used as follows:
([DPSOH
PxuCleanup_T stack;
TaskCode()
{
(1) stack.cleanup_mc = 0;
....
/* deactivate abort*/
/* request cleanup structure */
PxMcTakeBlk (PXMcTaskdefault, &cleanup, sizeof
(PxuCleanup_T));
/* write values to cleanup1 */
cleanup->cleanup_mc = PXMcTaskdefault;
cleanup->cleanup_arg = ....
cleanup->cleanup_fun = ....
The initial cleanup stack is initialized with 3[X&OHDQXS,QLW ((1) and (2)). New cleanup
jobs are pushed on the stack with 3[X&OHDQXS3XVK. This returns an Id that shows the
current status of the cleanup stack. With this Id, all cleanups saved to the stack DIWHU
this status can be popped. All cleanup jobs listed prior to this Id will still be executed.
The abort may occur just as the cleanup structure is being taken off the cleanup stack.
With this in mind, cleanup functions must be set up to continue to function correctly,
even when the cleanup is finished.
3[X&OHDQXS,QLW
3[X&OHDQXS3XVK
track of current state of the cleanup stack. This identifier used to execute cleanup
functions, or to remove cleanup structures from the stack.
3[X&OHDQXS*HW,G
3[X&OHDQXS*HW,G returns the current identifier for the cleanup stack VWDFN. This
identifier is used to execute (i.e. with 3[X&OHDQXS$FWLYDWH) the cleaning functions that
are currently on the stack.
3[X&OHDQXS$FWLYDWH
3[X&OHDQXS3RS
This function pops all cleaning functions located beneath the point specified in
FOHDQXSBLG. It does not execute the associated functions.
:DLWLQJDW'LIIHUHQW0DLOER[HV6LPXOWDQHRXVO\
In some applications, a task may need to wait for messages at a number of different
mailboxes simultaneously. This is rarely the case, so PXROS does not support this
option directly; however, this goal can be achieved. PXROS supports so called PDLOER[
KDQGOHUV, which are activated whenever a message arrives in a mailbox (see chapter
9.3).
If a task waits at a mailbox for both messages DQG events, simultaneous waiting is
made possible with the service 3[0VJ5HFHLYHB(Y:DLW. The task installs mailbox
handlers at the other mailboxes, which in turn signal certain events if a message
arrives. If the task is actived by such signals, it evaluates the event and collects the
message from the corresponding mailbox.
The services provided in S[XPE[B
F allow the user to perform this function
comfortably and safely. To use these services, a structure of the type 3[X0E[,QIB7
must be alotted to every participating mailbox handler.
mailboxPE[.
PVJW\SH shows the type of message that activates the mailbox handler upon arrival.
PXROS currently recognizes the values: 3;0VJ$Q\0VJ, 3;0JV3ULR0VJ and
3;0VJ1RUPDO0VJ . PXMsgAnyMsg activates the mailbox handler, UHJDUGOHVV RI WKH
PHVVDJH W\SH. The message type 3;0JV3ULR0VJ activates the mailbox handler only
when a prioritized message arrives and 3;0VJ1RUPDO0VJ only activates the handler
when messages ZLWKRXWSULRULW\ arrive.
3[X0E[,QI,QLW installs the mailbox handler, which remains inactive until it is activated
by the call 3[X0E[,QI6WDUW. If the specified type of message arrives after this function
is called, the mailbox handler becomes active.
3[X0E[,QI6WRS is used to deactivate a mailbox handler. The handler does not become
active, even if the specified message type arrives, until the mailbox handler is
reactivated with 3[X0E[,QI6WDUW. In other words, the mailbox handler is still assigned
to the mailbox. The service 3[X0E[,QI&OHDU removes the mailbox handler completely.
3[X0E[,QI&KDQJH allows one to change the set up for the mailbox handler, i.e. to
change the values specified with 3[X0E[,QI,QLW. 3[X0E[,QI&KDQJH automatically
deactivates the mailbox handler. After the changes have been made, the handler must
be explicitely restarted with 3[X0E[,QI6WDUW, otherwise it will not be activated when
messages arrive.
0HVVDJH3RROV
The services in S[XPVJSOF are used to create and delete a message pool.
3[X0VJ3RRO'HOHWH deletes the message pool 3RRO0E[, along with all of the prepared
messages created for the mailbox. 3[X0VJ3RRO'HOHWH can only release those
messages that are in the mailbox. It is very important that DOO prepared messages are
returned to their release mailbox; otherwise, PxMsgRelease might cause a fatal
PXROS error since the message would no longer have a release mailbox to return to.
3[X0VJ3RRO'HOHWH also fails if there are tasks waiting for messages at the specified
mailbox.
3URWHFWHG'DWD
PXROS does not offer any direct assitance for protecting data from unauthorized
access; however, it offers a kind of semaphore which can be used to protect specific
data. This entails using SURWHFWHG REMHFWV. Functions for protected objects can be
available in the files S[XREMB
F.
3[X3REM&UHDWH3[X3REM'HOHWH
3[X3REM&UHDWH creates the protected object 3REM with a data area of REMVL]H bytes in
size. The protected object is accessed by requesting and releasing specific services
(see below).
3[X3REM'HOHWH deletes the protected object, 3REM, and releases the memory it used.
This service may only be called when QR RWKHU WDVN has the right to access 3REM, and
no other task tries to request the access rights. If this is not the case, a call to
3[X3REM'HOHWH leads to a fatal PXROS error.
3[X3REM5HTXHVW5HI'DWD
As with PXROS 3[5HTXHVW services, three different versions of this service are
available:
the events from the event pool HYHQWV is signalled to the calling task.
3[X3REM5HOHDVH5HI'DWD
This service releases exclusive access to the protected objects data (i.e. SREM).
Pointers received from a previous call to 3[X3REM5HOHDVH5HI'DWD FDQ QR ORQJHU EH
XVHG. This is not tested! If a task attempts references protected data after it is released,
0HPRU\5HTXHVWV
When using dynamically allocated memory, one must specify the same memory class
for every request and release. The task releasing the memory might not recognize the
memory class if it did not request the memory itself. For this reason, S[XPHPF offers
special services for requesting and releasing memory. These service solve this problem
internally, thus taking the burden off of the user. The prototypes for these services are
modelled after the standard C library services of the same name.
PDOORF
VL]Hbytes of memory are requested from the calling tasks default memory class. If the
request fails, 0 is returned.
UHDOORF
VL]H bytes of memory are requested from the calling tasks the default memory class.
When successful, the data is copied, beginning with the address ROG, and the memory
ROG is released. ROG must have been requested with FDOORF PDOORF or UHDOORF. If the
FDOORF
Memory is requested from the calling tasks default memory class for an array of Q
elements of the size VL]H bytes. The requested area is initialized to 0. If the request
fails, 0 is returned.
IUHH
Every memory area that was requested with PDOORF, FDOORF, or UHDOORF PXVW be
rereleased with the function IUHH. If the memory was requested in some other way (for
example, with 3[0F7DNH%ON), IUHH may QRW be used to release it.
3;526,QLWLDOL]DWLRQ
To ease the initialization process in PXROS, 3[X6WG,QLW (in the file S[XLQLWF ) serves as
a simple interface.
This functions parameters correspond to those in VWG,QLW (see chapter 15.2 for details).
3[X6WG,QLW initializes PXROS as configured in the given parameters.
7DVN&UHDWLRQ
To make creating tasks simple, the functions 3[X6WG7DVN (found in the files
S[XWVNB
F) offer a simple interface.
Because there are several versions of 3[X&UHDWH6WGWDVN, certain parameters are not
configured with default values:
3[X&UHDWH6WGWDVNB7EO does not set the tasks WEOLPLW to -; instead, WEOLPLt is used to
pass on this value. 3[X&UHDWH6WGWDVNB$ERUW defines DEWIUDPHV abort frames for the
task, thus allowing it to use the PXROS abort mechanism. Using
3[X&UHDWH6WGWDVNB(YHQWV , the created task is not immediately ready; rather, it waits
7LPH&RQYHUVLRQ
3;526 WLFNV are the time units used in PXROS. To create portable code, it is helpful
when real time units can be specified in the program source. In this way, the developer
need not convert time periods into PXROS ticks by hand. S[XWLPHF offers several
conversion routines from realtime units to PXROS ticks.
Before conversion routines can be used, 3[X7LPH6HW)UHT must be called. This service
defines the frequency PXROS uses for time. K] contains the number of PXROS ticks
per second. This information can be retrieved with the service 3[X7LPH*HW)UHT. The
other services convert seconds or milliseconds into PXROS ticks, or vice versa. The
conversion may require that the value be rounded off. Details about how values are
rounded can be found in the header S[XWLPHK.
5LQJ%XIIHUVZLWKZDNLQJIXQFWLRQV
Ring buffers are a useful medium for communicating information between handlers and
tasks. They are especially useful when the handler receives or passes a great deal of
data from or to a task. This is often the case when communication between the
application and a user is realized over a serial interface.
The header file S[XZUEK defines special macros to safely manage ring buffers with an
arbitrary number of elements. The ring buffer PXVW be used such that it is never read
from while it is being written to, and vice versa. This is the applications responsibility
since PXROS does not check it.
To keep the code size to a minimum, macros should be called via functions if they are
used repeatedly in the program. This does increase the run time slightly. Ring buffers
containing LQWHJHU and FKDU elements can utilize certain macros provided in the files
S[XZUEBLF and S[XZUEBFF. The ring buffer macros use a number of arguments. In
the following description, macros are treated like functions to illustrate the data types of
the individual arguments.
3;8:UE'HILQH7\SH
A control structure must be created to manage a ring buffer. This macro defines a new
data type QDPH to manage a ring buffer consisting of elements of the data type
EDVHW\SH.
([DPSOHIRUDKHDGHUHQWU\
The data type 3[X:UE,QWB7 is defined to manage a ring buffer consisting of LQW
,QLWLDOL]DWLRQ
The application must provide the memory for the ring buffers control structure. This
structure can be allocated either dynamically or globally. If it is placed on a functions
stack, the function may not be exited; otherwise the address area would become
invalid.
Before it is used, the complete structure must be initialized. This can be done in one
step using the macro 3;8:UE,QLW. The structure can also be initialized in successive
steps by calling 3;8:UE,QLW%XIIHU, 3;8:UE6HW3XW&RQWUROV , and
3;8:UE6HW*HW&RQWUROV . The main difference is that the memory for the ring buffer
must already be available for successive initialization. When initializing the structure
with 3;8:UE,QLW, memory is requested dynamically from the calling tasks default
memory class. The parameters have the same meaning, regardless of the initialization
procedure used.
3;8:UE,QLW3;8:UE&OHDU
ZUE is the address of the ring buffers control structure. Using 3;8:UE,QLW, the
structure is merely configured. In this case, the memory for the structure must be
provided beforehand. The ring buffer contains PD[BHOHPBQXP elements. When
choosing the buffer size, realize that although a small buffer requires little memory, it
increases the risk of a full buffer when an element must be inserted. As mentioned
above, the memory for the ring buffer is allocated dynamically.
Attempts to insert or remove an element can fail if the ring buffer is respectively full or
empty. Waking ring buffers react to user-defined ZDLW and ZDNHXS functions. The ZDLW
function is called if the service fails. Once the service can be called successfully, the
ZDNHXS function is activated. These functions allow the following reactions:
the assignment is "forgotten". In this case neither the ZDLW nor the ZDNHXS
function is necessary.
wait until the job can be processed. In this case, the ZDLW function waits for
one or more PXROS events. The corresponding ZDNHXS function signals
these events to the task. The ZDLW functions return value is important: if it is
, the calling task tries to execute the job again once the ZDLW function is
finished. This try is usually successful. If the return value GRHV QRW HTXDO ,
the assignment is "forgotten".
as soon as the job can be processed, do so. Until then, other duties are
performed. To implement this algorithm, only the ZDNHXS function is
required. It signals a specified event to the task. When the task reacts to this
event, the corresponding ring buffer job is called.
these functions use the arguments JHWBDUJ and JHWBDUJ. If neither a ZDLW or ZDNHXS
functions is required, its corresponding parameters are set to .
UHVXO
t reports whether or not initialization was successful (
UHVXOW = 0). The initialization
can only fail if the dynamic memory request for the buffer could not be fulfilled.
3;8:UE&OHDU releases the memory allocated for the ring buffer. When this function is
3;8:UEa,QLWB%XIIHUa6HW3XW&RQWUROVa6HW*HW&RQWURO
These three macros are used to successively initialize the ring buffer.
3;8:UE,QLWB%XIIHU PXVW be called first. This function allocates the memory area
ZUEEXIIHU as the buffer for the ring buffer structure
ZUE. ZUEEXIIHU is the starting
address of a memory block that offers space for PD[BHOHPBQXP elements of the type
EDVHW\SH. The control functions that can be called when inserting/removing elements
are set to . This could overwrite previous entries, which is why this macro must be
called before the other two.
3;8:UE*HW3;8:UE3XW
An element is read from a ring buffer with the macro 3;8:UE*HW. If the buffer is not
empty, the result is copied to the address YDU, and
UHVXOW is 0. If the buffer was empty,
but the job was succesfully performed after the ZDLW function returned, the empty buffer
remains unnoticed. If no ZDLW function was specified, or the wait-function returns a
value other than 0, than
UHVXOW returns a1.
If the buffer is read succesfully, the ring buffer contains one element less than before
the read. If an attempt to insert an element into the buffer failed because the buffer was
full, the SXWBZDNHXS function is called (assuming it was defined).
3;8:UE3XW inserts an element into the ring buffer. If the buffer is not full, the element
YDO is copied into the buffer and
UHVXOW is 0. If the buffer is full, but the assignment is
successfull after the ZDLW function returns, this full buffer remains unnoticed. If no ZDLW
function was specified, or the wait-function returns a value other than 0,
UHVXOW returns
a -1.
If the element is succesfully inserted, the ring buffer contains one element more than it
did before the write call. If an element was not removed because the buffer was empty,
the JHWBZDNHXS function is called, (assuming it was defined)
3;8:UE*HW5HDG3RLQWHU3;8:UE$GYDQFH5HDG3RLQWHU
When elements are read with 3;8:UE*HW, they are always copied. If the ring buffer
contains complex elements, copying them increases the run time. Often times, a
pointer to the buffer's next element is sufficient. This can be requested with
3;8:UE*HW5HDG3RLQWHU . When succesfully executed, this macro enters the address
of the next buffer element in
SWU. In contrast to 3;8:UE*HW, the element is not read.
3;8:UE$GYDQFH5HDG3RLQWHU actually reads the element as well. The SXWBZDNHXS
function can be activated with these macros are used, if space becomes available in
the buffer for a new element.
3;8:UE*HW:ULWH3RLQWHU3;8:UE$GYDQFH:ULWH3RLQWHU
Inserting elements with 3;8:UE3XW always requires the copying of elements. With ring
buffers consisting of complex elements, this can increase run time considerably since
the element must be built before it can be copied. In these cases, it is usually
preferable to request a pointer to the buffers next element. This avoid the need for
copying the complex element. When succesfully executed, 3;8:UE*HW:ULWH3RLQWHU
writes the address of the next free buffer in
SWU. The element is not truly entered until
3;8:UE$GYDQFH:ULWH3RLQWHU has been called. The JHWBZDNHXS function might also
3;8:UE*HW(OHP1XP3;8:UE,V)XOO3;8:UE,V(PSW\
0HDVXULQJWKH6\VWHP/RDG
3[X6\VORDG&DOLEUDWH
This function calibrates a scale for the basic system load. 3[X6\VORDG&DOLEUDWH is
called after PXROS has been initialized and the PXROS timer has been started, but
before any other system load is present. This function measures the applications basic
load.
WLPH defines a time period over which the system load is periodically measured. Based
on this interval, a delay handler is activated once the measurements begin. This
records and saves the average system load over this period of time.
3[X6\VORDG6WDUW0HDVXUH
3[X6\VORDG6WDUW0HDVXUH is normally called during the idle tasks endless loop. This
allows it to determine the remaining processing time. This function may not only be
activated once while the application runs.
3[X6\V/RDG*HW0HDVXUH
This function returns the average system load in the variable
$YJ This value indicates
the percentage that exeeds the basic load. The system load is measured in intervalls.
The time span of these intervalls is set in the parameter WLPH with the function
3[X6\VORDG&DOLEUDWH . Only the last 64 measurements are returned.
This function must be called by a task that has a higher priority than the task that called
3[X6\VORDG6WDUW0HDVXUH . The result of the measurements can be requested as
needed.
3[X6\VORDG(QG
0HVVDJHV
When tasks communicate with messages, it is useful to use similar data structures for
the messages (see chapter 5). The files S[XUHT
F contain functions that support this
method of communication. These functions offer comfortable interfaces for handling
messages that use a set structure. This structure of type 3[X5HTB7 is defined in
S[XUHTK and can be evaluated or configured with the various services provided. Job
specific data is written behind the structure, where the application can read and write to
it.
6\QFKURQRXV&RPPXQLFDWLRQ
3[XUHTVQF contains the function for synchronized communication, which are designed
to work correctly, even when aborted by the PXROS abort mechanism. The task-
specific data is used to accomplish this.
3[X5HT6\Q,QLW
Synchronized communication services use the tasks specific data. Using the
parameter LQGH[ (see section 23.1), 3[X5HT6\Q,QLW determines which data areas are
used. This function may only be used once, when initializing the application, and must
be used before the first service is called.
3[X5HT6\Q2SHQ
Each task must initialize its task-specific data with 3[X5HT6\Q2SHQ before any
messages can be sent.
3[X5HT6\Q
3[X5HT6\Q sends data to the server mailbox VUYPE[. The function then waits until the
receiving task responds to this request. This work is recognized when the receiver calls
3[X5HT$FN.
The waiting period can be aborted with PXROS abort mechanism. In this case PXROS
notes that the answer to the request is still out. If the answer arrives later, a future call
to 3[X5HT6\Q recognizes and releases the "old" answer, and continues to wait for the
answer to its request.
The calling function must provide the messages entire data area. It is VL]H bytes in size
and begins at the address UHT. A structure of type 3[X5HTB7 is located at the head of
the data area. This structure is not configured by the calling function. The job specific
data area is located directly behind this structure. The message receives the
assignment Id &RGH, which allows the receiver to interpret the data correctly.
3[X5HT6\Q&ORVH
3[X5HT6\Q&ORVH releases the resources being used for the task-specific data. The
function waits until all awaited messages have arrived. If the function is aborted with
the PXROS abort mechanism, 3[X5HT6\Q&ORVH may need to be called again.
$V\QFKURQRXVFRPPXQLFDWLRQ
The sender only requires the service 3[X5HT6HQG for asynchronized communication.
0VJ specifies an existing message that begins with a structure of type 3[X5HTB7. The
job specific data must already contain the desired information. This service only
configures the message head and sends the message to the maillbox VYUPE[. UHTW\SH
specifies the message type, and the message receives the Id UHTLG.
altered message is returned to the maillbox UHTDFNPE[ with the assignment type
UHTDFNW\SH.
5HFHLYHU6HUYLFHV
The receiver of an asynchronous message may also use certain functions on the
message. These are used to receive, evaluate and process the message.
3[X5HT5HFHLYH
3[X5HT5HFHLYH takes a message from the mailbox UFYPE[. If 5HT is not equal to 0,
5HT contains the address of a received messages data area.
UHTW\SH specifies the
message type, and ist Id is contained in *reqid, assuming these parameter do not point
to 0.
These services can only be used if the messages were sent to the mailbox with either
3[X5HT6HQG or 3[X5HT6\Q.
3[X5HT'HFRGH
3[X5HT'HFRGH returns the type of the received message PVJ. If 5HT is not equal to
0, then
5HT holds the address of the messages data area. This service can only be
used if the message was sent with either 3[X5HT6HQG or 3[X5HT6\Q.
3[X5HT$FN
After the message has been processed, the receiver calls 3[X5HT$FN. This function
evaluates the information contained in the message head. This should tell the receiver
what to do with the message after it has been processed. The message is either
released, or sent on to a mailbox. HUURU is then set to the messages error code.
*ORVVDU\
This glossary briefly describes important terms that are used in PXROS. Detailed
information can be found in the corresponding chapters.
'HOD\-REV
A delay job is a request to PXROS to activate a GHOD\ KDQGOHU after a certain time. This
mechanism can be used to implement timeouts and periodic events. A delay job is
always associated with a delay object.
(YHQWV
+DQGOHUV
All tasks are interrupted when a handler is executed. Handlers usually perform time
critical application jobs. Handlers use special versions of PXROS services, which are
recognized by the extension B+QG. A handler can communicate with a task by
signalling events to it, or by using shared global memory.
0DLOER[
A mailbox is a PXROS object that serves as a multi-in, multi-out buffer for messages. A
task sends a message to a mailbox, where it is received by another task. Messages are
usually kept in the mailbox in the order they arrive. They are released in the same
order. If tasks are waiting for a message at a mailbox, the task that has been waiting
longest receives a message first.
0DLOER[+DQGOHUV
0HPRU\&ODVVHV
The systems dynamically allocatable memory can be divided into different memory
classes. This is an efficient way to manage memory and limit resource consumption
problems to certain modules. When using fixed block memory classes, the access time
for a memory request and release is considerably shorter than that required for variable
block memory classes.
0HVVDJHV
Usually messages are saved on a first-in, first-out basis. In other words, the first
message to arrive is the first message to be released. Some messages are "labeled"
SULRULW\. Such messages are released before non-priority messages.
2EMHFWV
Objects are system resources that tasks can use to perform various duties. Unused
objects are stored in object pools until they are requested by tasks. Object types
include delay objects, message objects, mailboxes, memory classes and object pools.
In some PXROS versions, additional object types are available.
2EMHFW3RROV
An object pool stores unused PXROS objects. Tasks can request these object as they
are needed. This mechansim also serves to limit resource consumption problems to
certain system modules by allocating objects to various UHDO REMHFW SRROV. 9LUWXDO REMHFW
SRROV also limit a tasks access to objects, but without requiring the physical distribution
3ULYDWH0DLOER[
During creation, every task receives its own mailbox. This is called the tasks private
mailbox. A task usually waits for messages at its private mailbox.
3ULRULW\
Control over the processor is regulated by the tasks priority. Of all of the ready tasks
(i.e. those not waiting for an object or events), the task with the highest priority
executes its program code first. It is interrupted if a handler is activated, or if a task with
a higher priority becomes ready. It also relinquishes control of the processor if it enters
a wait state.
3;5267LFNV
A PXROS tick is the PXROS time unit, and is activated at regular intervals. The
PXROS system clock is increment with the periodic activation of the service
3[7LFN'HILQHB+QG . The length of these intervals defines a PXROS tick. Usually a
5HVRXUFH'LVWULEXWLRQ
7DVNV
The different tasks run in quasi-parallel. Only one task is active at any given moment,
and only its code is executed. PXROS allocates control of the processor based on the
tasks priority and its status (ready or waiting). This is referred to as priority-based
scheduling.
7LPH6OLFLQJ
,QGH[