blob: 8e87c921745ed7772e3cbbd699dd0209d9e8856f [file] [log] [blame]
========================
XDC Runtime Architecture
========================
Revision History
================
+------------+------------+-------------------------------------------+
| Version | Date | Description |
+============+============+===========================================+
| 0.1 | 2/12/2019 | First draft |
+------------+------------+-------------------------------------------+
| 0.2 | 6/1/2019 | Added internal xdc.runtime.Core material |
+------------+------------+-------------------------------------------+
| 0.3 | 1/20/2020 | Added SysMin, Text, and Timestamp content |
+------------+------------+-------------------------------------------+
| 0.4 | 3/25/2020 | Added "Uses" diagram and API conventions |
+------------+------------+-------------------------------------------+
Introduction
============
Purpose & Scope
---------------
This document is intended to explain and illustrate the inner workings
of the xdc.runtime package.
Disclaimer
----------
While this document attempts to explain all the key details related to
the xdc.runtime package, certain details are bound to be left out. For
further explanation of such missing details, please refer to
`RTSCpedia <http://rtsc.eclipseprojects.io/docs-tip>`__ and or the source code
of xdc.runtime.
Terms & Abbreviations
---------------------
+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| package | A named collection of modules which forms a component |
+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| module | The RTSC equivalent of a Java or C++ class |
+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| interface | The RTSC equivalent of a Java Class |
+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| RTSC | Real-Time Software Components - a portable C based component model appropriate for resource constrained embedded systems. |
+-------------+-----------------------------------------------------------------------------------------------------------------------------+
| XDCtools | A collection of host tools for the development of RTSC components |
+-------------+-----------------------------------------------------------------------------------------------------------------------------+
References
----------
Much of the text and organization of this document is derived from the
xdc.runtime documentation maintained in the
`RTSCpedia <http://rtsc.eclipseprojects.io/docs-tip>`__ - a wiki provided by
`eclipse.org <https://www.eclipse.org/>`__ as part of the `Eclipse RTSC
project <https://projects.eclipse.org/projects/technology.rtsc>`__.
+------+-----------------------------------------------------------------------------------------------+---------------+
| # | Title | Author |
+------+-----------------------------------------------------------------------------------------------+---------------+
| 1. | `XDCtools User's Guide <http://rtsc.eclipseprojects.io/docs-tip/XDCtools_User%27s_Guide>`__ | David Russo |
+------+-----------------------------------------------------------------------------------------------+---------------+
| 2. | `RTSC Glossary <http://rtsc.eclipseprojects.io/docs-tip/Glossary>`__ | David Russo |
+------+-----------------------------------------------------------------------------------------------+---------------+
| 3. | `RTSC Bibliography <http://rtsc.eclipseprojects.io/docs-tip/Bibliography>`__ | David Russo |
+------+-----------------------------------------------------------------------------------------------+---------------+
xdc.runtime Package
===================
Functional Goals
----------------
The xdc.runtime package contains many low-level modules that work
together to provide "core" services appropriate for any embedded
C/C++ application:
- *memory management*: basic memory allocation and freeing from
multiple heaps
- *concurrency support*: low-level critical region protection
mechanisms
- *real-time diagnostics*: printf-like logging, error management, and
assertion support
- *system services*: system initialization and shutdown (exit(),
atexit(), abort(), etc.) and basic character output (printf())
- *core instance support*: common runtime functions that manage the
life-cycle of all instances defined by any module; e.g., support for
the static or dynamic creation and deletion of any module's instance
objects.
All of these services provide portable C interfaces that are
appropriate for virtually any 16, 32, and 64-bit embedded
microprocessor; from highly resource constrained 16-bit CPUs with as
little as 1K bytes of RAM and 32K bytes of Flash (MSP430F2274) to
64-bit CPUs with gigabyte address spaces (AM57x).
In addition to the services above, the xdc.runtime package provides
a low-level "internal" machine interface that supports the `RTSC
Interface Definition
Language <http://rtsc.eclipseprojects.io/docs-tip/Glossary#RTSC_IDL>`__
(IDL) compiler; see `Core Instance Support`_. This IDL allows module developers to formally specify the interface of
a module in a C-like declarative language. The IDL compiler then
generates both C and JavaScript "stubs" that reference implementation
functions provided by the module developer.
Interface Conventions
~~~~~~~~~~~~~~~~~~~~~
The services provided by the xdc.runtime package must be both highly
efficient and general enough to support a wide variety of applications
- from simple pedagogical examples to safty-critical real-time
applications. To balance these application requirements with a single
functional interface, all functions must:
- document all pre-conditions necessary for proper operation as well
as all parameters and return values
- return an error status when the pre-conditions are met but the
function fails
- support reentrant operation
xdc.runtime module functions are designed to maximize the C compiler's
static type checking ability by defining unique types for most input
and output parameters and using const wherever possible.
Finally, where static checks and preconditions are insufficient to
catch common programming mistakes, xdc.runtime modules may also provide input
parameter sanity checks. For example, all parameter structures passed
to an instance constructor are checked to ensure the parameter
initialization function was used to initialize the structure.
Architectural Introduction
--------------------------
The services provided by the xdc.runtime package are partitioned into
numerous modules. The relationship between the modules in the
xdc.runtime package and the services they provide is depicted in the
figure below.
|image0|
All of the modules and interfaces provided in the xdc.runtime
package are supplied in portable C source code form. In addition,
all of the modules are designed to be thread-safe and, where
necessary, use the Gate module to serialize access to global data
structures.
In order to ensure platform independence, those modules that require
platform-specific services are designed to support one (or more)
platform-specific "service providers". Each of these providers
implements one of the interfaces supplied. Simple implementations of
each service provider interface are also included in this package.
Memory Management
=================
Functional Goals
----------------
Memory management within embedded systems often requires
- explicit management of distinct memory "classes";
- control over alignment of critical buffers;
- deterministic memory allocation, support for variable length
allocation; and in some cases
- the ability to eliminate *all* runtime allocation and freeing of
memory
Explicit use of different "classes" of memory, such as high-speed
on-chip memory versus bulk external DRAM, is critical for embedded
real-time applications. For example, careful use and efficient
management of precious high-speed on-chip memory often determines
whether an application meets its real-time deadlines or not. Even
with different classes of memory, to get full entitlement from
modern CPU cores, it is important that critical buffers be allocated
on appropriate address boundaries - either for improved cache
performance or to take advantage of specialized "zero overhead"
looping constructs.
Different applications have widely differing "policy" requirements.
For example, traditional embedded applications do not need, nor can
they afford, extra memory management code to allow the system to
automatically free memory from a terminated thread. On the other
hand, some embedded systems allow for the execution of untrusted
(but not malicious) code. In this case, the robustness requirements
of the system all but require a memory manager that can track the
ownership of every allocated memory block. Similarly, because
real-time applications provide "guaranteed" response times for
certain events and variable length memory allocators often have
execution times that vary as a function of the number and size of
previous allocations, real-time applications generally take one of
two approaches to dynamic heap memory management:
1. use "fixed size" block allocation algorithms which have deterministic
execution times but have poor memory utilization, or
2. use a distinguished "low priority" thread to perform all functions
that require memory allocation so the "real-time" threads never
stall waiting to allocate or free memory.
From these examples, it's clear that embedded systems have unique
memory management requirements and that no one memory allocation
algorithm is appropriate for all embedded applications.
The xdc.runtime package provides core memory management functions
suitable for virtually any embedded application. In particular, it
includes a single module, Memory that supports
- multiple heaps and allows each heap to manage its memory in a
memory-specific or application-specific manner;
- aligned allocations on any boundary supported by the underlying
hardware;
- static placement of buffers required by other modules that create
objects at configuration-time; and
- zero-space-overhead allocations that do not require "allocation
header" information to be retained on each allocation.
Architecture Introduction
-------------------------
The xdc.runtime package contains several modules that work together
to provide modular and extensible memory management support. This
support is centered on the
`Memory <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Memory.html>`__
module that enables the application to allocate and free memory. All
memory allocations are eventually "handled" by a module that
implements the
`IHeap <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/IHeap.html>`__
interface. These modules are responsible for managing a region of
memory in a manner appropriate for the application.
Two such modules are provided in the xdc.runtime package:
1. `HeapMin <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/HeapMin.html>`__ - a module that simply maintains a "high water" mark for each managed memory block and never frees memory, and
2. `HeapStd <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/HeapStd.html>`__ - a module that uses the ANSI C standard library functions ``malloc()`` and ``free()``.
While it is possible to create new implementations of the IHeap
interface that provide more sophisticated or even
application-specific memory management policies, most users will
rely on IHeap implementations from their preferred RTOS (such as
TI's SYS/BIOS).
Architecture
------------
The Memory module's methods take a first parameter that identifies
the heap from which to allocate memory. This parameter may be NULL
and, in this case, a "default heap" will be used. The "default heap"
is specified by the developer by setting the Memory module's
defaultHeapInstance configuration parameter. If this parameter is
not explicitly set by the developer, an instance of
`xdc.runtime.HeapStd <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/HeapStd.html>`__
(of size
`Memory.defaultHeapSize <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Memory.html#default.Heap.Size>`__)
will be assigned to this parameter.
|image1|
The Memory module itself does very little work: it simply delegates
"real" memory management to the specified heap instance object. This
makes clients of Memory portable, but where do the heap instances
get created? If they are created by the application, the code that
creates these instances is not portable to other applications;
because it contains direct references to specific heap managers. Of
course, applications can factor this "non portable" code into a
single place and pass IHeap instance handles to other parts of the
application that need memory allocation services. But, an even
better solution is to entirely eliminate the runtime creation of
IHeap instances in favor of static creation. In this case, not only
do we eliminate unnecessary code, but we improve the portability of
the code by eliminating direct references to application-specific
heap managers.
Memory simply provides the "glue" between portable clients and
underlying modules, heap managers, which actually manage the memory.
But the xdc.runtime package only provides two heap managers, HeapMin
and HeapStd, and these modules have limited usefulness; HeapMin does
not reuse freed memory and HeapStd has no advantage over malloc()
and free(). So where do you get "real" heap managers that realize
the benefits promised by the xdc.runtime package's memory
architecture? Heap managers are available from RTOS providers (such
as TI's SYS/BIOS).
Concurrency Support
===================
Functional Goals
----------------
Each embedded application runs in a unique environment with specific
mechanisms for managing multiple threads; some use a real-time
operating system while others simply run a control loop that
coordinates with interrupt service routines. The Gate module
provides an RTOS independent interface that allows applications to
portably protect shared data structures in multi-threaded
environments by simply "entering a gate" prior to using the data and
"leaving the gate" once access is no longer required.
Gates are also used internally by the xdc.runtime package. In order
to allow the xdc.runtime functions to be called from different
threads, it is important that any global data managed by the
xdc.runtime modules is updated "atomically". The xdc.runtime package
atomically updates global data by always "entering the System gate"
(via
`Gate\_enterSystem() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html#enter.System>`__)
prior to accessing the global data and "leaving the System gate"
(via
`Gate\_leaveSystem() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html#leave.System>`__)
once the update is complete.
While gates make it easy to protect shared data structures and
ensure the functional correctness of a multi-threaded application,
it is important to minimize the time spent within a gate; the longer
a thread operates within a gate the greater the chance that this
thread will interfere with the timely operation of other threads in
the system. If two (or more) threads need to enter the same gate,
all but one will be suspended until the thread in the gate leaves
*even if the thread inside the gate has lower priority than the
blocked threads*. Worse, for performance reasons, some gates work by
disabling *all* scheduling while inside the gate; even threads that
are not trying to modify the data protected by the gate are
potentially affected.
By carefully selecting the type of gate used to protect shared data
structures and associating each shared data structure with a unique
gate, it is possible to strike a balance between the runtime
overhead caused by frequent gate method calls and the scheduling
latency engendered by unnecessarily blocking the execution of
threads that are operating on unrelated data.
The xdc.runtime package
- enables creation of portable thread-safe code with shared data
structures,
- provides a distinguished "System gate" to efficiently protect very
short critical sections,
- supports gates on both a per-module and a per-instance basis for
modules that need to operate within a gate for periods longer
than the worst-case scheduling latency allowed by the
application, and
- allows system integrators to configure gates to achieve the proper
balance between runtime overhead and scheduling latency for their
application.
Architecture Introduction
-------------------------
The xdc.runtime package contains modules that work together to
provide support for serializing access to shared data structures.
This section focuses on the
`Gate <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html>`__
module which is used to "enter" and "leave" critical sections of
code that access shared data.
Use of this module is illustrated by a series of examples that take
advantage of one other distinguished xdc.runtime module:
- `GateNull <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/GateNull.html>`__ - a module that is used to eliminate unnecessary serialization
overhead for those situations where data is known to be accessed
by one thread at a time; e.g., in single threaded systems or for
modules that are known to be used by just one thread in a
multi-threaded application.
Obviously the most interesting examples will require a "real" gate;
i.e., one that serializes access to a shared data structure in a
multi-threaded application. `Extending xdc.runtime
Gates <http://rtsc.eclipseprojects.io/docs-tip/Extending_xdc.runtime_Gates>`__
provides an example that uses `posix
mutexes <http://pubs.opengroup.org/onlinepubs/9699919799/>`__ and
illustrates how, using services commonly provided by an RTOS, the
xdc.runtime package can be made thread-safe with respect to that
RTOS.
Architecture
------------
.. Requirement
| REQ_TAG(SYSBIOS-921), REQ_TAG(SYSBIOS-922), REQ_TAG(SYSBIOS-923)
| REQ_TAG(SYSBIOS-924), REQ_TAG(SYSBIOS-925), REQ_TAG(SYSBIOS-926)
| REQ_TAG(SYSBIOS-927), REQ_TAG(SYSBIOS-928), REQ_TAG(SYSBIOS-929)
| REQ_TAG(SYSBIOS-930)
Any module may declare that it is
"`gated <http://rtsc.eclipseprojects.io/docs-tip/Glossary#GatedModule>`__";
i.e., that the module protects internal data shared among multiple
threads in the system via an xdc.runtime.Gate instance. Gated
modules always have at least one gate instance created implicitly.
However, it is possible to override the creation of this gate by
explicitly creating it and assigning it to the module's common$.gate
configuration parameter during configuration.
Modules enter and leave gates via the methods provided by the
`xdc.runtime.Gate <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html>`__
module. This Gate module provides methods that enable modules to
enter (and leave) their gate as well as dynamically create and
delete gates associated with their instance objects. Users of gated
modules don't need to use these methods (they are for use within the
implementation of RTSC modules) and should consult the documentation
of each gated module used to understand how best to balance the
module's need to protect shared data structures and the
application's scheduling latency requirements.
In addition to the services provided to implement thread-safe
modules, the Gate module also provides access to the distinguished
"System gate" via
`Gate\_enterSystem() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html#enter.System>`__
and
`Gate\_leaveSystem <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html#leave.System>`__.
In fact, this System gate is the gate associated with the gated
`xdc.runtime.System <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/System.html>`__
module. This one gate is used throughout the xdc.runtime package to
serialize access to global data and it's only used when the duration
of the critical section is known to be *deterministic and very
short*.
Using the System gate to protect logically independent data
structures is contrary to the design principle that, to minimize
scheduling latency effects, you should use a unique gate for
independent data structures. This exception exists because, *if* the
duration of time required to update these independent structures is
always very short (less than any application's maximum scheduling
latency requirements), the System gate can be implemented very
efficiently by simply disabling *all* scheduling while inside the
gate. While this may sound excessive, it often results in a
significant overall performance gain, keeps data space requirements
to a minimum with just one gate, and has no impact to scheduling
latency.
|image2|
Deadlocks
~~~~~~~~~
Although it is possible to "nest" gates - enter a gate while inside
another gate - care should be taken to avoid deadlocks; e.g., thread
1 enters gate a, thread 2 enters gate b, thread 1 tries to enter
gate b and blocks waiting for thread 2 to leave, but thread 2 tries
to enter gate a and blocks waiting for thread 1 to leave. One way to
avoid deadlocks is to ensure that nested gates are always entered in
the same order.
Since the System gate is used throughout the xdc.runtime and the
modules in this package are widely used, you should never enter
another gate while inside the System gate. If another thread enters
the same gate *and* makes a call to an xdc.runtime method, such as
System\_printf(), there is a risk of deadlock.
The System gate should *only* be used to protect low-level data
structures where the total execution time within the gate has a
constant upper bound independent of the data being protected.
Scheduling Latency
~~~~~~~~~~~~~~~~~~
Undisciplined use of gates can lead to scheduling latencies that
violate a system's real-time constraints. Since the System gate is
used to protect a wide variety of independent data structures, it is
important to keep the time within the System gate to an absolute
minimum. Similarly, when assigning gates to gated modules it's
important to minimize sharing gates between different modules; while
sharing can reduce your application's data footprint, you risk
creating unnecessary scheduling blockages.
Real-Time Diagnostics: Event Logging
====================================
Functional Goals
----------------
The xdc.runtime package's logging support enables developers to
embed "printf-like" Log statements virtually *anywhere* in an
embedded real-time code base. In addition to the traditional
printf() format string and arguments, each Log statement is
associated with a calling module and an "event mask" - a bit mask
that identifies the "type" of statement. The Log statements
- provide all the functionality of a "normal" printf,
- can be enabled or disabled at runtime on a per-module and per-type
basis, and
- have fixed low execution time independent of the arguments passed.
Applications can be configured to eliminate the data space required
for the format strings, permanently disable (or enable) selected
statements, eliminate the code space required for runtime control,
and provide application-specific handling of the "events" produced
by these statements. All of these configuration options are possible
*without requiring re-compilation of any source code*.
Architecture Introduction
-------------------------
The xdc.runtime package contains several modules that work together
to provide rich application diagnostic support that can be
controlled in real-time within deployed systems. This section
focuses on those modules that are used to generate "events",
enable/disable their generation, and display the events:
`Log <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Log.html>`__,
`Diags <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Diags.html>`__,
and
`LoggerSys <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/LoggerSys.html>`__,
respectively.
Use of these modules is illustrated by a series of examples that
take advantage of two other distinguished xdc.runtime modules:
1. `Main <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Main.html>`__
- a module whose configuration applies to all code that is *not* a RTSC
module; e.g., existing C code bases, and
2. `Defaults <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Defaults.html>`__
- a module whose configuration applies to all RTSC modules (including Main),
unless explicitly overridden on a per-module basis.
Architecture
------------
Loggers
~~~~~~~
For the purpose of logging, *every line* of code in an application
is treated as being part of some RTSC module. All code falls into
one of three classes:
1. code that is part of a RTSC module
2. code that is part of a dynamically registered module. Code can
dynamically register itself as a module through the
`xdc.runtime.Registry <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Registry.html>`__
module.
3. all other code. Any code that is not part of a RTSC module or a
registered module is considered to be part of the distinguished
`xdc.runtime.Main <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Main.html>`__
module.
All RTSC target modules, including
`xdc.runtime.Main <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Main.html>`__,
have a
- current "event mask" - a set of event categories that are enabled for
the module,
- an optional
`ILogger <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/ILogger.html>`__
service provider - a module that handles events generated by the
module, and
- an optional string name used to display the source of events
All dynamically registered modules also have an event mask and a
required string name.
The
`Log\_print <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Log.html#print6>`__
or
`Log\_write <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Log.html#write8>`__
methods are used to generate or log "events". These methods are
simply in-line macros that conditionally invoke the calling module's
underlying ILogger service provider to "handle" the events. This
service provider is called only if:
1. the module has a non-null ILogger service provider, and
2. the mask argument passed to Log\_print (or the mask of the event
passed to Log\_write) anded with the calling module's current
"event mask" is non-zero
The initial value of a module's event mask is specified during
configuration and may be changed at runtime via
`Diags\_setMask() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Diags.html#set.Mask>`__.
Beyond the parameters passed to Log\_print (or Log\_write), the id
of the module that called Log\_print (or Log\_write) is communicated
to the ILogger service provider so that it knows the source of the
events. This information, possibly in addition to a timestamp
recorded by the ILogger service provider, can be used to correlate
events from multiple sources (even from different CPUs).
Two ILogger service providers are included in the xdc.runtime
package:
1. `LoggerBuf <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/LoggerBuf.html>`__
- copies events to a circular buffer in a fixed small number of
cycles and is suitable for real-time high-frequency event
sources, and
2. `LoggerSys <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/LoggerSys.html>`__
- outputs events as they occur using
`System\_printf() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/System.html#printf>`__
and is suitable for initial development or low-rate non-real-time
event sources.
Custom ILogger service providers can easily be created to address
platform or application specific needs. These custom providers can,
of course, filter events and call LoggerBuf or LoggerSys. For
information about creating and deploying a custom logger see
`Extending xdc.runtime
Logging <http://rtsc.eclipseprojects.io/docs-tip/Extending_xdc.runtime_Logging>`__.
As part of an application's configuration step, developers "bind"
zero or more ILogger service providers to the modules that comprise
the application. Each module in a system can have a different
ILogger service provider or they can all share the same provider.
Events generated by modules *without* an ILogger service provider
are silently ignored.
Timestamps
~~~~~~~~~~
.. Requirement
| REQ_TAG(SYSBIOS-881), REQ_TAG(SYSBIOS-882), REQ_TAG(SYSBIOS-883)
| REQ_TAG(SYSBIOS-884), REQ_TAG(SYSBIOS-885)
By definition, real-time systems require some means to track and
measure elapsed time. However, different systems use very different
methods. Some systems leverage platform-specific timer peripherals
while others use application-specific data streams that are known to
produce data at a fixed rate (i.e., telephony TDM data). The choice of
how to measure time is application and platform specific, so it is
important that the timer services provided by xdc.runtime enable the
system integrator to specify an appropriate time source.
In addition to variations in how time is measured, different
applications have very different precision and range
requirements. Applications that only require millisecond precision
often don't require more than 32-bits of range (almost 50 days),
whereas measurements used to causally relate events in a multi-core
system requires near nanosecond precision (yielding less than 5
seconds of range from a 32-bit value). In fact, it is not unusual for
a single application to require more than one timer with different
precision and range requirements.
The xdc.runtime package contains several modules that need timestamps;
e.g., LoggerBuf and LoggerSys. These modules obtain timestamps from
other modules that implement the xdc.runtime.ITimestampProvider
interface. Two such modules are provided in the xdc.runtime package:
1. `TimestampNull <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/TimestampNull.html>`__
- a timestamp provider that always returns a timestamp of 0, and
2. `TimestampStd <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/TimestampStd.html>`__
- a timestamp provider that uses the ANSI C Standard Library function clock() to obtain timestamps.
The xdc.runtime.Timestamp module provides a platform-independent
interface that is sufficient for simple timestamping needs. This
module makes use of platform-specific implementations which can take
advantage of underlying hardware support, for example. Rather than
define a single "provider" interface that is sufficient for the needs
of the Timestamp module, the xdc.runtime package defines two
interfaces:
1. `ITimestampClient <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/ITimestampClient.html>`__
- defines the platform-independent interface provided by Timestamp, and
2. `ITimestampProvider <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/ITimestampProvider.html>`__
- defines the interface provided by platform-specific implementations and inherits from ITimestampClient
While it may seem odd that underlying timestamp provider
implementations must implement the same interface as ITimestampClient,
this design enables applications to call timestamp providers directly,
when necessary, to leverage platform-specific capabilities. Suppose
there is device specific timestamp provider, say Timestamp64, that
provides additional methods that put an underlying timer into special
low-power modes. Since this Timestamp64 module must implement
ITimestampClient (because ITimestampProvider inherits from
ITimestampClient), developers that need to leverage the low-power
functionality can mechanically replace existing calls to Timestamp
methods with calls to Timestamp64 methods and be sure the application
will continue to function properly. The figure below illustrates the
relationship between the the various timestamp interfaces and modules
provided by xdc.runtime as well as this hypothetical Timestamp64
timestamp.
|RuntimeTime|
Real-Time Diagnostics: Error Handling
=====================================
Functional Goals
----------------
Each embedded application runs in a unique environment with specific
resource requirements and, as a result, adopts application-specific
*policies* for managing runtime errors; e.g., reset-and-reboot,
catch-and-retry, log-and-continue, or a combination of these
policies for different parts of the system. The xdc.runtime package
provides a set of mechanisms for raising and handling runtime errors
that enables code to be written once and used in *any* application -
independent of the application's error handling policies.
Architecture Introduction
-------------------------
The xdc.runtime package contains several modules that work together
to provide rich application diagnostic support that can be
controlled in real-time within deployed systems. This section
focuses on those modules that are used to raise and handle errors
and provide assertion support:
`Error <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Error.html>`__
and
`Assert <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Assert.html>`__,
respectively.
Use of these modules is illustrated by a series of examples that
take advantage of two other distinguished xdc.runtime modules:
1. `Main <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Main.html>`__
- a module whose configuration applies to all code that is *not*
a RTSC module; e.g., existing C code bases, and
2. `Defaults <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Defaults.html>`__
- a module whose configuration applies to all RTSC modules
(including Main), unless explicitly overridden on a per-module
basis.
Architecture
------------
.. Requirement
| REQ_TAG(SYSBIOS-852), REQ_TAG(SYSBIOS-853), REQ_TAG(SYSBIOS-854)
| REQ_TAG(SYSBIOS-855), REQ_TAG(SYSBIOS-856), REQ_TAG(SYSBIOS-857)
| REQ_TAG(SYSBIOS-858), REQ_TAG(SYSBIOS-859), REQ_TAG(SYSBIOS-860)
| REQ_TAG(SYSBIOS-861), REQ_TAG(SYSBIOS-862), REQ_TAG(SYSBIOS-863)
| REQ_TAG(SYSBIOS-864), REQ_TAG(SYSBIOS-865), REQ_TAG(SYSBIOS-866)
| REQ_TAG(SYSBIOS-867), REQ_TAG(SYSBIOS-868), REQ_TAG(SYSBIOS-869)
| REQ_TAG(SYSBIOS-870), REQ_TAG(SYSBIOS-959)
The xdc.runtime package supports two distinct "categories" of error:
1. *errors* that are explicitly checked for and handled by the code, and
2. *assertion violations* that arise when the current application state
is inconsistent with the range of states required by a piece of
code.
The first category of errors is managed by the Error module and the
second category is managed by the Assert module. Rather than use
simple fixed-length error numbers, the xdc.runtime package uniformly
employs an opaque Error\_Block structure to "raise" errors via
`Error\_raise() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Error.html#raise>`__.
Functions that raise errors are passed a pointer to an Error\_Block
structure which is passed to Error\_raise() when an error is
detected. When an error is raised, the Error\_Block structure
records the source of the error, a unique ID for for the error, a
message format string, and up to two arguments associated with this
particular occurrence.
Using an Error\_Block structure has several advantages. Perhaps most
importantly, the information about the source of the error as well
as data specific to the particular occurrence is efficiently copied
into the structure for later processing. In effect, Error\_raise()
combines the efficiency of a simple error code with the richness of
a printf at the site of the error. Since the error information is
simply recorded in the Error\_Block structure, the application
developer can control when and how the information will be formatted
and displayed.
Similar to the standard C assert() macro, the Assert module's
methods are interspersed with other code to add runtime checks -
primarily during early development - that ensure the code is being
called in the appropriate context. Unlike the standard C assert
support, the Assert module provides greater flexibility in managing
the messages displayed, the message string space overhead, and the
runtime handling of failures. In addition, because the Assert
methods build atop the Diags module, you can precisely control which
assertions remain in the final application, if any.
When an assertion violation is detected, an
`Assert.E\_assertFailed <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Assert.html#/.E_assert/.Failed>`__
error is raised (via Error\_raise()) with a NULL Error\_Block
reference; so, assertions are handled using the same error handling
hooks as "normal" errors.
Real-Time Diagnostics: Text
===========================
Functional Goals
----------------
Adding "printf-like" statements to a C code base not only increases
code space (the instructions to put arguments in registers and call a
function) but it can significantly increase an application's data
space requirements; each "printf-like" format string is added to a
data section reserved for constants and the size of section can grow
quickly as more and more logging statements are added. While it's not
possible to stop the strings used in Log_print() statements from
taking up space in the target, it is possible to completely eliminate
the
* format strings by used by Log_write(),
* error messages emitted by Error_raise(), and
* assertion messages triggered by Assert_isTrue()
Since each of these strings is declared in the RTSC specification,
it's possible to sequester these strings into a compressed table that
*does not* need to be loaded on to the embedded system for normal
operation. These statically declared strings can be "encoded" into a
single 32-bit quantity that encodes _references_ to both the string
itself and where the string is defined. These references can be
interpreted by a host computer to display to the user the complete
message while the embedded system can enjoy the benefits of detailed
tracing and understandable error messages produced deterministically
and with small footprint.
While the logger architecture enables deterministic execution time for
logging, there is a need to also minimize the overall footprint
overhead for these diagnostics.
Architecture
------------
.. Requirement
| REQ_TAG(SYSBIOS-886), REQ_TAG(SYSBIOS-887), REQ_TAG(SYSBIOS-888)
| REQ_TAG(SYSBIOS-889), REQ_TAG(SYSBIOS-890), REQ_TAG(SYSBIOS-891)
| REQ_TAG(SYSBIOS-892), REQ_TAG(SYSBIOS-893), REQ_TAG(SYSBIOS-894)
| REQ_TAG(SYSBIOS-895), REQ_TAG(SYSBIOS-896), REQ_TAG(SYSBIOS-897)
| REQ_TAG(SYSBIOS-898)
In lieu of a mask and a format string as initial arguments,
Log_write() takes a Log_Event. A Log_Event is an opaque reference to a
structure that contains a mask and a format string. How does this
help? By eliminating direct references to literal strings in the C
sources, the C compiler only sees an integer index being passed to
Log_write() and never needs to allocate space for the constant format
string. During configuration, it's possible to generate a table of all
Log_Event format strings, define Log_Event as an index into this
table, and arrange for this table to loaded in a separate output
section. Since this table is only needed when the event is "decoded",
the table (with the strings) does not need to be loaded into the
target's memory; events can be decoded by host-based development tools
which simply lookup the event based on the index supplied by
Log_write().
The Error and Assert modules follow a similar pattern and *all*
"event" strings are included in a single table that is created
and managed by the `xdc.runtime.Text <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Text.html>`__ module.
To eliminate the runtime strings you must configure the Text module to
place all strings in a special section that will not be loaded onto
the target.
.. code-block:: c
:name: Text_isLoaded
var Text = xdc.module("xdc.runtime.Text");
Text.isLoaded = false;
In addtion to providing the ability to remove the many of the static
strings from the embeded application's runtime image, the Text module
provides a functional interface used in the implementation of other
module's to generate output buffers with the fully qualified names of
any module in the system using a 16-bit Id; e.g., the single 37 byte
string ``"ti/sysbios/family/arm/a15/smp/Cache"`` is represented by
just 2 bytes on the target.
System Services
===============
Functional Goals
----------------
Each embedded application runs in a unique environment with specific
resource requirements and, as a result, adopts application-specific
*policies* for basic character output, application startup, and
shutdown. The xdc.runtime package provides an extensible
platform-independent framework for application startup (from
processor boot), initialization, and shutdown. In addition, it
provides a platform-independent interface for character output which
allows for platform-specific implementations that can range from
simple memory writes to a circular buffer to flow-controlled output
via a platform-specific I/O device.
The System and Startup modules provide the foundation for early
application "bring up", and continue to serve in deployed
applications to manage the initialization of higher-level services
and provide simple "fail-safe" diagnostics. These modules together
with, say, the SysMin system support module are sufficient to enable
complete C-based application development using "printf" debugging.
Because Startup and System are platform-independent, entire embedded
applications can be ported to alternative execution environments
(Unix or Windows workstations, for example) without making any
change to their sources. Porting to a different environment involves
a simple reconfiguration of the application to replace the System
support module with an implementation appropriate for the new
execution environment; no change to the application's sources are
required and, if you're porting between
`platforms <http://rtsc.eclipseprojects.io/docs-tip/Glossary#PlatformDefinition>`__
with the same
`target <http://rtsc.eclipseprojects.io/docs-tip/Glossary#TargetDefinition>`__,
no recompilation is required.
Architecture Introduction
-------------------------
The xdc.runtime package contains two modules that together provide
the minimal set of services necessary to enable modular application
startup and shutdown as well as basic message display.
1. `Startup <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Startup.html>`__
- a module that provides a framework for the orderly
initialization of modules *prior* to main(), and
2. `System <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/System.html>`__
- a module that provides exit handling similar to the ANSI C
atexit() mechanism as well as basic printf() message output.
Use of these modules is illustrated by a series of examples that use
one of two other distinguished xdc.runtime modules that provide the
"back end" support functions required by the System module:
1. `SysMin <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/SysMin.html>`__
- a self-contained module appropriate for deeply embedded
applications or early system development, and
2. `SysStd <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/SysStd.html>`__
- a module that relies on standard ANSI C runtime library
functions such as putchar() and fflush() and is appropriate for
systems with an already functional ANSI C Standard I/O library.
Startup Architecture
--------------------
.. Requirement
| REQ_TAG(SYSBIOS-949), REQ_TAG(SYSBIOS-950), REQ_TAG(SYSBIOS-951)
| REQ_TAG(SYSBIOS-952), REQ_TAG(SYSBIOS-953), REQ_TAG(SYSBIOS-954)
| REQ_TAG(SYSBIOS-955), REQ_TAG(SYSBIOS-956)
Every module in an application can optionally supply a "startup"
function that *must* be run prior to the first use of the module by
application code. This startup function might read memory mapped
registers necessary to initialize the module's internal data
structures, for example. Modules specify that they have startup
functions via the
`@ModuleStartup <http://rtsc.eclipseprojects.io/docs-tip/XDCspec_-_%40ModuleStartup>`__
attribute in their module specification file. The Startup module
runs these startup functions prior to the application's main() entry
point and provides numerous configuration parameters to enable the
developer to augment the startup process with custom C functions.
The System module, on the other hand, provides mechanisms for
modules (initialized under the control of Startup) to shutdown.
Between the initialization of the application's modules and shutdown
of the application, System is also used to perform simple character
output via "printf-like" methods. By not supporting all the format
specifications required by a full ANSI C Standard implementation of
printf(), these methods provide a much smaller and faster
implementation that satisfies most uses and can be embedded in very
small applications.
Finally, the System module also provides a low-level "gate" that is
used to protect global data structures maintained within the
xdc.runtime package; this gate allows multi-threaded applications to
safely use the xdc.runtime package's modules concurrently. This same
gate can also be used by application code.
Startup and initialization
~~~~~~~~~~~~~~~~~~~~~~~~~~
The Startup module provides a standard mechanism for the orderly
initialization of all modules within an application *before* main()
begins. The Startup module defines just two entry points that need
to be integrated into the execution environment's startup code. Once
this is done, Startup handles the initialization of all other
modules in the application - xdc.runtime modules as well as any
other modules used by the application.
Boot Sequence and Control Points
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section describes the sequence of events that occurs
immediately after a device is reset until execution reaches the
application's main() function. It also identifies the specific
points during this boot sequence at which user provided functions
("boot hooks") are called.
|image3|
All targets follow the same set of boot sequence steps. In outline,
the target independent boot sequence steps are:
1. Immediately after CPU reset, perform target-specific CPU
initialization to, at a minimum, setup a C call stack.
2. Run user-supplied reset function (see
`Startup.resetFxn <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Startup.html#reset/.Fxn>`__).
3. Perform additional target-specific initialization to a complete C
execution environment for subsequent steps.
4. Run user-supplied "first functions" (See
`Startup.firstFxns <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Startup.html#first/.Fxns>`__).
5. Run all module initialization functions.
6. Run user-supplied last functions (See
`Startup.lastFxns <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Startup.html#last/.Fxns>`__).
7. Call main().
The reset function (in step 2 above) is run as early as possible in
the boot sequence. In fact, for some targets it is called before the
C environment is fully initialized; static variables may not be
fully initialized, for example. To maximize portability, reset
functions should only assume that a C stack is initialized.
Although the functions in steps 4-6 are C functions, they are run
during normal C++ static object initialization. This has two
consequences:
1. Since the ANSI C++ Language Standard does not provide a means to
control the order of execution of static constructors, the
initialization of application modules may not run before a C++
constructor runs. If you need to use a **module** (for memory
allocation, for example) before step 6 completes and all modules
are initialized, your code must explicitly call Startup\_exec()
before using any other module in the system. It is safe to call
Startup\_exec() more than once. So, you may call it from each C++
constructor that needs a module's services.
2. If you are using a target that does not support C++, you must
explicitly call Startup\_exec() prior to using any module's
services. You can simply call Startup\_exec() as the first step
in main(), for example.
Specific information about each environment's startup sequence is
provided by the topics indexed in the table below.
+----------------------+---------------------------------------------------------------------------------------------------------------------------------+
| **Target Family** | **Detailed Boot Sequence Information** |
+======================+=================================================================================================================================+
| TI | `TI Compiler Runtime Startup Sequence <http://rtsc.eclipseprojects.io/docs-tip/Using_xdc.runtime_Startup/TI>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------------+
| Gnu Unix | `GNU Native Compiler Runtime Startup Sequence <http://rtsc.eclipseprojects.io/docs-tip/Using_xdc.runtime_Startup/GNU>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------------+
| Microsoft | `Microsoft Compiler Runtime Startup Sequence <http://rtsc.eclipseprojects.io/docs-tip/Using_xdc.runtime_Startup/Microsoft>`__ |
+----------------------+---------------------------------------------------------------------------------------------------------------------------------+
Module Initialization
~~~~~~~~~~~~~~~~~~~~~
Every module can optionally define a startup function which is
called before main(). Modules declare that they want to participate
in this startup sequence via the
`@ModuleStartup <http://rtsc.eclipseprojects.io/docs-tip/XDCspec_-_%40ModuleStartup>`__
attribute in the module's spec file. Modules that use this attribute
must also implement the following startup function:
.. code-block:: c
:name: Mod_Module_startup
Int Mod_Module_startup(Int state);
where "Mod" is the name of the module requesting startup support.
The parameter to the startup function serves as "state variable"
whose initial value will be Startup\_NOTDONE (0) and whose final
value will eventually be Startup\_DONE (-1). If startup() returns a
value other than Startup\_DONE, it will be called in a subsequent
pass with this return value passed in as state. To ensure this
process terminates, no startup function is ever called more than
`Startup.maxPasses <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Startup.html#max/.Passes>`__
times.
For situations in which the startup of one module depends upon
another having completed its startup processing, the following
function is automatically defined for all modules and proxies:
.. code-block:: c
:name: Mod_Module_starupDone
Bool Mod_Module_startupDone();
where "Mod" is the name of some module or proxy. These predicates
can be used as guards inside of a startup function to probe whether
a particular module has completed its own startup processing. As a
convenience, the function Startup\_rtsDone() probes the necessary
set of xdc.runtime modules required to support a module instance
create, and should be called before any startup-time instance
creation and/or memory allocation is performed.
.. code-block:: c
:name: Mod_Module_startup_example
Int Mod_Module_startup(Int state)
{
if (!Startup_rtsDone()) {
return (Startup_NOTDONE);
}
// other code
return (Startup_DONE);
}
System Module Architecture
--------------------------
.. Requirement
| REQ_TAG(SYSBIOS-899), REQ_TAG(SYSBIOS-900), REQ_TAG(SYSBIOS-901)
| REQ_TAG(SYSBIOS-902), REQ_TAG(SYSBIOS-903), REQ_TAG(SYSBIOS-904)
| REQ_TAG(SYSBIOS-906), REQ_TAG(SYSBIOS-907), REQ_TAG(SYSBIOS-908)
| REQ_TAG(SYSBIOS-909), REQ_TAG(SYSBIOS-910), REQ_TAG(SYSBIOS-911)
| REQ_TAG(SYSBIOS-912), REQ_TAG(SYSBIOS-1069), REQ_TAG(SYSBIOS-1070)
| REQ_TAG(SYSBIOS-1071), REQ_TAG(SYSBIOS-1072), REQ_TAG(SYSBIOS-1073)
The System module provides mechanisms for modules (initialized under
the control of Startup) to shutdown. Between the initialization of
the application's modules and shutdown of the application, System is
also used to perform simple character output via "printf-like"
methods. By not supporting all the format specifications required by
a full ANSI C Standard implementation of printf(), these methods
provide a much smaller and faster implementation that satisfies most
uses and can be embedded in very small applications.
Finally, the System module also provides a low-level "gate" that is
used to protect global data structures maintained within the
xdc.runtime package; this gate allows multi-threaded applications to
safely use the xdc.runtime package's modules concurrently. This same
gate can also be used by application code.
System Character output and shutdown
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The System module provides a facade for two key system level areas:
character output and program termination. Since application
termination and basic character output can be very different
depending on the product and stage of development, the System module
relies on a user supplied module that implements these very basic
functions (defined by the
`ISystemSupport <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/ISystemSupport.html>`__
interface). Developers specify the module that implements these
functions by setting the
`System.SupportProxy <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/System.html#.Support.Proxy>`__
configuration parameter.
|image4|
The xdc.runtime package includes two system support proxy options:
SysMin and SysStd. These modules are sufficient for early
development but, because they are written to be 100% portable, they
don't take advantage of any platform-specific features (such as an
embedded UART). Fortunately it is easy to create a custom system
support module that can be bound to System as easily as SyMin or
SysStd and takes full advantage advantage of your platform's
execution environment.
Customizing the System module requires that the end-user specify a
module that implements the ISystemSupport interface as the "proxy"
for the required platform or application-specific services.
The relationship between the System module and an ISystemSupport
proxy is illustrated in the figure below.
|image5|
SysMin
^^^^^^
.. Requirement
| REQ_TAG(SYSBIOS-913), REQ_TAG(SYSBIOS-914), REQ_TAG(SYSBIOS-915)
| REQ_TAG(SYSBIOS-916), REQ_TAG(SYSBIOS-917), REQ_TAG(SYSBIOS-918)
| REQ_TAG(SYSBIOS-919), REQ_TAG(SYSBIOS-920)
The SysStd module uses putchar() and fflush() for basic character output.
However, SysMin simply copies characters to a pre-configured static buffer
for character output and provides a configuration parameter that allows you
to specify how these characters are output when System_flush() is called. As
a result, SysMin can be used in applications that need to avoid all
references to the ANSI C Standard Library I/O functions.
With the exception of exit(), atexit(), and abort(), the System module does
not directly reference any ANSI C Standard Library functions; any other
references are the result of the System module's supporting module
System.SupportProxy. If the System.SupportProxy configuration parameter is
not set, it defaults to SysMin.
By default, the SysMin support module will call fwrite() to output characters
written to its internal buffer. To eliminate this reference, it is sufficient
to define your own output function, say myOutputFxn, and set SysMin.outputFxn
to reference this function.
.. code-block:: c
:linenos:
var System = xdc.useModule("xdc.runtime.System");
var SysMin = xdc.useModule("xdc.runtime.SysMin");
SysMin.outputFxn = "&myOutputFxn";
System.SupportProxy = SysMin; /* not really necessary since this is the default */
Of course there may be other reasons why the use of SysMin is not
appropriate. For example, you may want to output characters at the time they
are generated rather than buffering them. In this case, you'll need to create
your own ISystemProvider module. For information about how to create a new
ISystemProvider module see Extending xdc.runtime System.
System Concurrency support
~~~~~~~~~~~~~~~~~~~~~~~~~~
The System module is a `gated
module <http://rtsc.eclipseprojects.io/docs-tip/Glossary#GatedModule>`__.
The gate associated with the System module, also called the "System
gate", is a used for two purposes:
1. to protect critical regions within the xdc.runtime package by
serializing concurrent accesses to global data; and
2. to protect small critical regions within the application via the
`Gate\_enterSystem() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html#enter.System>`__
and
`Gate\_leaveSystem() <http://rtsc.eclipseprojects.io/cdoc-tip/index.html#xdc/runtime/Gate.html#leave.System>`__
APIs.
|image6|
For more information about using the xdc.runtime package in
multi-threaded applications, see `Multi-Threading
Support <http://rtsc.eclipseprojects.io/docs-tip/Working_with_xdc.runtime#Multi-Threading_Support>`__.
`Using xdc.runtime
Gates <http://rtsc.eclipseprojects.io/docs-tip/Using_xdc.runtime_Gates>`__
contains more details about gates, how to protect shared data
structures using gates, and how to create new gates.
Core Instance Support
=====================
Functional Goals
----------------
The RTSC runtime model is intended support any real-time embedded system
and to usefully scale down to systems with extremely tight memory
constraints - as little as 1KB of RAM and 32KB of Flash - while
providing a uniform modular object oriented API for all target code. To
make this possible, RTSC module instances can be created statically,
dynamically using the heap, or dynamically using *any* memory managed by
the application. This allows applications to work with object oriented
APIs *without requiring any runtime heap memory management*.
It's also important that low-level module instance objects, such as
queues and semaphores, are capable of being dynamically created entirely
from stack memory. Stack memory management can be done
*deterministically*, with effectively *no runtime overhead*, and without
any possibility of fragmentation issues inherent in heap memory
management. This makes stack memory ideal for small embedded systems
with must operate in a fail-safe manner within strict real-time
constraints. Thus, the non-heap instance construction methods must also
support memory dynamically allocated by the runtime stack (i.e.,
ordinary C automatic variables).
Finally, it's important to ensure that a single module implementation be
able support the full range of embedded applications - from the largest
embedded system to tiny 1KB RAM systems. It must be easy for modules to
support *all* forms of instance creation *without any additional
runtime* code.
Architecture Introduction
-------------------------
All RTSC modules share a common design pattern similar to C++ or Java
classes: each module is associated with a module state object and
optionally defines an instance constructor. Both modules and instances
optionally supply methods that implicitly operate on the state of the
module or instance. Unlike instance objects that may be conditionally
created at runtime, module state objects are singletons that are
statically defined just once (i.e., before the application starts).
The purpose of xdc.runtime.Core module is to provide common code for the
implementation of all module constructors and destructors, simplifying
their implementation, minimizing the total application runtime
footprint, and ensuring consistent behavior. Moreover, this design also
enables efficient trace of the lifecycle of any module's instances via
`Event Logging <#real\-time-diagnostics-event-logging>`__.
The xdc.runtime.Core module is simple a collection of functions used in
the creation and destruction of *all* module instances. But, this module
is itself *never* directly called by application-level code; it is only
used in the *implementation* of RTSC modules. The figure below
illustrates the relationship between Core and all other RTSC modules,
including the xdc.runtime modules.
|Runtime_use|
This figure depicts several important aspects of the xdc.runtime modules
- *all* modules that define instances (represented by the *ModX* node)
do so via the Core module
- with the exception of the platform specific adapters (e.g.,
HeapMin), the xdc.runtime modules are "static only"; i.e., they do
not directly define instances
- there are two modules, Text and Core, which are not intended to be
directly used by applications. Their APIs are designed specifically
for the needs of the xdc.runtime package and the RTSC IDL code
generator where performance and footprint are prioritized over ease
of use.
- some of the xdc.runtime modules make use of one another
Note: to keep this figure understandable, not all "Uses" relations are
depicted. For example, the modules represented by *ModX* can directly
use Memory, Timestamp, System, Assert, etc.
Architecture
-------------
.. Requirement
| REQ_TAG(SYSBIOS-871), REQ_TAG(SYSBIOS-872), REQ_TAG(SYSBIOS-873)
| REQ_TAG(SYSBIOS-874), REQ_TAG(SYSBIOS-875), REQ_TAG(SYSBIOS-876)
| REQ_TAG(SYSBIOS-878), REQ_TAG(SYSBIOS-879)
All RTSC module instance constructor methods follow a common pattern:
- arguments that lack a reasonable default appear first,
- if it's possible for the constructor to fail, an Error\_Block pointer
is passed as the last argument,
- all other arguments are encapsulated in a "Params" structure and
passed as a pointer to the constructor,
- if the Params pointer is NULL, the module's specified default values
for these parameters are used, otherwise, the referenced "Params"
structure must be initialized via a *Mod*\ \_Params\_init() function
and only parameters of interest need be updated prior to invoking the
module's constructor,
- memory for heap-based instance objects is allocated by the module's
"create" method whereas memory for stack-based and static objects is
allocated by the caller and passed as the first parameter to the
module's "construct" method.
Leveraging this common pattern, the xdc.runtime.Core module defines a
small set of functions that encapsulates the common code for all
instance object memory management in the system. To ensure the
xdc.runtime.Core functions are applicable to *any* module's instances, a
uniform description of each instance type, in the form of a const
xdc\_runtime\_Core\_ObjDesc structure, is passed to the construction
methods.
.. code-block:: c
:name: Core_ObjDesc
struct xdc_runtime_Core_ObjDesc {
CPtr fxnTab; /* pointer to module fxns */
Types_Link *modLink; /* link to runtime instances */
SizeT objAlign; /* alignment of instance object */
IHeap_Handle objHeap; /* heap from which obj is allocated */
SizeT objName; /* offset into obj for name pointer */
SizeT objSize; /* sizeof obj (including header) */
CPtr prmsInit; /* pointer to default Mod_Params */
SizeT prmsSize; /* size of these default parameters */
};
The xdc\_runtime\_Core\_ObjDesc structure together with a static
constant structure of module-specific parameter defaults provide *all*
the information necessary for the Core module's functions to create
instances for any RTSC module. This includes the management of optional
parameters to a module's instance constructors.
It is up to each module to define its own the static and dynamic
constructors that are directly invoked by the application. In practice,
these functions are nothing more than a few lines of code which "wrap"
calls to the xdc.runtime.Core module's functions followed by a call to a
module-specific instance state initialization function.
The figure below illustrates the general instance construction pattern
as well as the relationship between a module, say ModX, its constant
descriptor structure, and the xdc.runtime.Core module's functions.
|image7|
The sections below illustrate, in greater detail, how a hypothetical
module, *ModA*, uses the xdc.runtime.Core functions to implement its
constructors. To simplify these sections, we do not show every possible
variation allowed by xdc.runtime.Core; e.g., although the possibility of
errors occurring in constructors is supported by xdc.runtime.Core, the
examples below assume *ModA*\ \_construct never fails.
Instance construct/destruct
~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section illustrates the use of xdc.runtime.Core functions in the
implementation of the construct/destruct methods of a hypothetical
module named *ModA*. To support module instance objects that are not
necessarily allocated from the heap, a pointer to a *ModA*\ \_Struct is
passed from the application to the constructor; allocation this
structure is the responsibility of the caller.
For the purpose of this example, we suppose that *ModA* supplies two
functions: *ModA*\ \_Instance\_init and *ModA*\ \_Instance\_finalize
which are called to perform any module-specific initialization or
finalization of *ModA* instances.
**ModA\_Params\_init**
.. code-block:: c
:name: ModA_Params_init
void ModA_Params_init(ModA_Params *prms)
{
if (prms != NULL) {
xdc_runtime_Core_assignParams__I(
prms,
&ModA_Object__PARAMS__C,
sizeof(ModA_Params),
sizeof(xdc_runtime_IInstance_Params)
);
}
}
**ModA\_construct**
.. code-block:: c
:name: ModA_construct
void ModA_construct(ModA_Struct *obj,
const ModA_Params *paramsPtr);
{
ModA_Params prms;
/* common instance initialization */
xdc_runtime_Core_constructObject__I(
&ModA_Object__DESC__C, /* instance description */
obj, /* memory for instance object */
&prms, /* tmp memory for all params */
(xdc_CPtr)paramsPtr, /* params supplied by caller */
0, /* unused (for backward compat) */
NULL /* optional error block */
);
/* module-specific initialization */
ModA_Instance_init((xdc_Ptr)obj, &prms);
}
**ModA\_destruct**
.. code-block:: c
:name: ModA_destruct
void ModA_destruct(ModA_Struct *obj)
{
xdc_runtime_Core_deleteObject__I(
&ModA_Object__DESC__C,
obj,
(xdc_Fxn)ModA_Instance_finalize,
-1,
TRUE
);
}
The methods defined above support the instance lifecycle pattern shown
below.
.. code-block:: c
:name: ModA_construct_lifecycle
ModA_Struct inst; /* alloc space for instance */
ModA_Params params; /* alloc space for params */
ModA_Params_init(&params); /* init params to defaults */
params.foo = 3; /* change one or more params ... */
:
ModA_construct(&inst, &params); /* fully initialize inst */
ModA_doSomething(&inst, ...); /* invoke ModA methods ... */
:
ModA_destruct(&inst); /* finalize inst */
Instance create/delete
~~~~~~~~~~~~~~~~~~~~~~
This section illustrates the use of xdc\_runtime\_Core functions in the
implementation of the create/delete methods of a hypothetical module
named *ModA*. Recall that create/delete supports module instance
lifecycles that use heap memory.
However, many similarities exist between this implementation and the
construct/destruct implementation illustrated
`above <#instance-construct-destruct-support>`__. In fact, the
*ModA*\ \_Params\_init() method is identical and is omitted below. The
primary difference between the two forms of instance creation is that
create/delete must handle to case where memory is not available and
simply return a failure to the caller.
As above, we suppose that *ModA* supplies two functions:
*ModA*\ \_Instance\_init and *ModA*\ \_Instance\_finalize which are
called to perform any module-specific initialization or finalization of
*ModA* instances.
**ModA\_create**
.. code-block:: c
:name: ModA_create
ModA_Handle ModA_create(const ModA_Params *paramsPtr,
xdc_runtime_Error_Block *eb)
{
ModA_Params prms;
ModA_Object *obj;
/* common instance initialization */
obj = xdc_runtime_Core_createObject(
&ModA_Object__DESC__C, /* instance description */
NULL, /* memory for instance object */
&prms, /* tmp memory for all params */
(xdc_CPtr)paramsPtr, /* params supplied by caller */
0, /* unused (for backward compat) */
eb); /* needed for heap alloc failures */
if (obj == NULL) {
return NULL;
}
/* module-specific initialization */
ModA_Instance_init(obj, &prms);
return obj;
}
**ModA\_delete**
.. code-block:: c
:name: ModA_delete
void ModA_delete(ModA_Handle *instp)
{
xdc_runtime_Core_deleteObject(
&ModA_Object__DESC__C,
*((ModA_Object**)instp),
NULL,
-1,
FALSE);
*((ModA_Handle*)instp) = NULL;
}
The methods defined above support the instance lifecycle pattern shown
below.
.. code-block:: c
:name: ModA_create_lifecycle
ModA_Handle inst; /* handle returned by create */
ModA_Params params; /* alloc space for params */
ModA_Params_init(&params); /* init params to defaults */
params.foo = 3; /* change one or more params ... */
:
inst = ModA_create(&params, NULL); /* fully initialize inst */
ModA_doSomething(inst, ...); /* invoke ModA methods ... */
:
ModA_delete(&inst); /* finalize inst */
.. |image0| image:: ./media/image4.png
:width: 6.48958in
:height: 3.28125in
.. |image1| image:: ./media/image5.png
:width: 7.26042in
:height: 2.72917in
.. |image2| image:: ./media/image6.png
:width: 6.66667in
:height: 3.15625in
.. |image3| image:: ./media/image7.png
:width: 6.41667in
:height: 5.32292in
.. |image4| image:: ./media/image8.png
:width: 7.30208in
:height: 2.80208in
.. |image5| image:: ./media/image9.png
:width: 6.20833in
:height: 4.72917in
.. |image6| image:: ./media/image10.png
:width: 4.75000in
:height: 4.58333in
.. |image7| image:: ./media/image11.png
:width: 5.66667in
:height: 4.20833in
.. |RuntimeTime| image:: ./media/RuntimeTime.png
:width: 5.66667in
:height: 4.20833in
.. |Runtime_use| image:: ./media/Runtime_use.png
:width: 5.66667in
:height: 4.20833in