8. Execution environment

8.1. Introduction

.intro: This document describes how the MPS is designed to work in different execution environments (see standard.ansic section 5.1.2).

8.2. Discussion

.std: These are the relevant statements from the International Standard ISO/IEC 9899:1990 “Programming languages — C”, with tags added:

  1. Compliance

[…]

.std.com.hosted: A “conforming hosted implementation” shall accept any strictly conforming program. .std.com.free: A “conforming freestanding implementation” shall accept any strictly conforming program in which the use of the features specified in the library clause (clause 7) is confined to the contents of the standard headers <float.h>, <limits.h>, <stdarg.h>, and <stddef.h>. A conforming implementation may have extensions (including additional library functions), provided they do not alter the behaviour of any strictly conforming program.

[…]

5.1.2 Execution environments

.std.def: Two execution environments are defined: “freestanding” and “hosted”. […]

.std.init: All objects in static storage shall be “initialized” (set to their initial values) before program startup. The manner and timing of such initialization are otherwise unspecified. […]

.std.term: “Program termination” returns control to the execution environment. […]

5.1.2.1 Freestanding environment

.std.free.lib: Any library facilities available to a freestanding environment are implementation-defined.

.std.free.term: The effect of program termination in a free-standing environment is implementation-defined.

8.3. Interpretation

.int.free: We interpret the “freestanding environment” as being the sort of environment you’d expect in an embedded system. The classic example is a washing machine. There are no library facilities available, only language facilities.

.int.free.lib: We assume that the headers <float.h>, <limits.h>, <stdarg.h> and <stddef.h> are available in the freestanding environment, because they define only language features and not library calls. We assume that we may not make use of definitions in any other headers in freestanding parts of the system.

.int.free.term: We may not terminate the program in a freestanding environment, and therefore we may not call abort(). We can’t call abort() anyway, because it’s not defined in the headers listed above (.int.free.lib).

.int.free.term.own: We can add an interface for asserting, that is, reporting an error and not returning, for use in debugging builds only. This is because the environment can implement this in a way that does not return to the MPS, but doesn’t terminate, either. We need this if debugging builds are to run in a (possibly simulated or emulated) freestanding environment at all.

8.4. Requirements

.req: It should be possible to make use of the MPS in a freestanding environment such as an embedded controller.

.req.conf: There can be configurations of the MPS that are not freestanding (such as using a VM arena).

8.5. Architecture

.arch: Like Gaul, the MPS is divided into three parts: the core, the platform, and the plinth.

.arch.core: The core consists of the Memory Pool Manager (the core data structures and algorithms) and the built-in Pool Classes. The core must be freestanding.

.arch.platform: The platform provides the core with interfaces to features of the operating system and processor (locks, memory protection, protection mutator context, stack probing, stack and register scanning, thread management, and virtual memory). The platform is specialized to a particular environment and so can safely use whatever features are available in that environment.

.arch.plinth: The plinth provides the core with interfaces to features of the user environment (time, assertions, and logging). See design.mps.io and design.mps.lib.

.arch.distinction: The distinction between plinth and platform is that end users will need to customize the features provided by the plinth for most programs that use the MPS (and so the interface needs to be simple, documented and supported), whereas implementing the platform interface is a specialized task that will typically be done once for each platform and then maintained alongside the core.