26.2. Default Value Selection Philosophy

The user should be aware that the defaults are intentionally set as low as possible. By default, no application resources are configured. The <rtems/confdefs.h> file ensures that at least one application task or thread is configured and that at least one of the initialization task/thread tables is configured.

26.3. Sizing the RTEMS Workspace

The RTEMS Workspace is a user-specified block of memory reserved for use by RTEMS. The application should NOT modify this memory. This area consists primarily of the RTEMS data structures whose exact size depends upon the values specified in the Configuration Table. In addition, task stacks and floating point context areas are dynamically allocated from the RTEMS Workspace.

The <rtems/confdefs.h> mechanism calculates the size of the RTEMS Workspace automatically. It assumes that all tasks are floating point and that all will be allocated the minimum stack space. This calculation includes the amount of memory that will be allocated for internal use by RTEMS. The automatic calculation may underestimate the workspace size truly needed by the application, in which case one can use the CONFIGURE_MEMORY_OVERHEAD macro to add a value to the estimate. See Specify Memory Overhead for more details.

The memory area for the RTEMS Workspace is determined by the BSP. In case the RTEMS Workspace is too large for the available memory, then a fatal run-time error occurs and the system terminates.

The file <rtems/confdefs.h> will calculate the value of the work_space_size parameter of the Configuration Table. There are many parameters the application developer can specify to help <rtems/confdefs.h> in its calculations. Correctly specifying the application requirements via parameters such as CONFIGURE_EXTRA_TASK_STACKS and CONFIGURE_MAXIMUM_TASKS is critical for production software.

For each class of objects, the allocation can operate in one of two ways. The default way has an ceiling on the maximum number of object instances which can concurrently exist in the system. Memory for all instances of that object class is reserved at system initialization. The second way allocates memory for an initial number of objects and increases the current allocation by a fixed increment when required. Both ways allocate space from inside the RTEMS Workspace.

See Unlimited Objects for more details about the second way, which allows for dynamic allocation of objects and therefore does not provide determinism. This mode is useful mostly for when the number of objects cannot be determined ahead of time or when porting software for which you do not know the object requirements.

The space needed for stacks and for RTEMS objects will vary from one version of RTEMS and from one target processor to another. Therefore it is safest to use <rtems/confdefs.h> and specify your application’s requirements in terms of the numbers of objects and multiples of RTEMS_MINIMUM_STACK_SIZE, as far as is possible. The automatic estimates of space required will in general change when:

  • a configuration parameter is changed,

  • task or interrupt stack sizes change,

  • the floating point attribute of a task changes,

  • task floating point attribute is altered,

  • RTEMS is upgraded, or

  • the target processor is changed.

Failure to provide enough space in the RTEMS Workspace may result in fatal run-time errors terminating the system.

26.4. Potential Issues with RTEMS Workspace Size Estimation

The <rtems/confdefs.h> file estimates the amount of memory required for the RTEMS Workspace. This estimate is only as accurate as the information given to <rtems/confdefs.h> and may be either too high or too low for a variety of reasons. Some of the reasons that <rtems/confdefs.h> may reserve too much memory for RTEMS are:

  • All tasks/threads are assumed to be floating point.

Conversely, there are many more reasons that the resource estimate could be too low:

  • Task/thread stacks greater than minimum size must be accounted for explicitly by developer.

  • Memory for messages is not included.

  • Device driver requirements are not included.

  • Network stack requirements are not included.

  • Requirements for add-on libraries are not included.

In general, <rtems/confdefs.h> is very accurate when given enough information. However, it is quite easy to use a library and forget to account for its resources.

26.5. Configuration Example

In the following example, the configuration information for a system with a single message queue, four (4) tasks, and a timeslice of fifty (50) milliseconds is as follows:

#include <bsp.h>
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_MICROSECONDS_PER_TICK   1000 /* 1 millisecond */
#define CONFIGURE_TICKS_PER_TIMESLICE       50 /* 50 milliseconds */
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_MAXIMUM_TASKS 4
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 1
#define CONFIGURE_MESSAGE_BUFFER_MEMORY \
           CONFIGURE_MESSAGE_BUFFERS_FOR_QUEUE(20, sizeof(struct USER_MESSAGE))
#define CONFIGURE_INIT
#include <rtems/confdefs.h>

In this example, only a few configuration parameters are specified. The impact of these are as follows:

  • The example specified CONFIGURE_RTEMS_INIT_TASKS_TABLE but did not specify any additional parameters. This results in a configuration of an application which will begin execution of a single initialization task named Init which is non-preemptible and at priority one (1).

  • By specifying CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER, this application is configured to have a clock tick device driver. Without a clock tick device driver, RTEMS has no way to know that time is passing and will be unable to support delays and wall time. Further configuration details about time are provided. Per CONFIGURE_MICROSECONDS_PER_TICK and CONFIGURE_TICKS_PER_TIMESLICE, the user specified they wanted a clock tick to occur each millisecond, and that the length of a timeslice would be fifty (50) milliseconds.

  • By specifying CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER, the application will include a console device driver. Although the console device driver may support a combination of multiple serial ports and display and keyboard combinations, it is only required to provide a single device named /dev/console. This device will be used for Standard Input, Output and Error I/O Streams. Thus when CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER is specified, implicitly three (3) file descriptors are reserved for the Standard I/O Streams and those file descriptors are associated with /dev/console during initialization. All console devices are expected to support the POSIX*termios* interface.

  • The example above specifies via CONFIGURE_MAXIMUM_TASKS that the application requires a maximum of four (4) simultaneously existing Classic API tasks. Similarly, by specifying CONFIGURE_MAXIMUM_MESSAGE_QUEUES, there may be a maximum of only one (1) concurrently existent Classic API message queues.

  • The most surprising configuration parameter in this example is the use of CONFIGURE_MESSAGE_BUFFER_MEMORY. Message buffer memory is allocated from the RTEMS Workspace and must be accounted for. In this example, the single message queue will have up to twenty (20) messages of type struct USER_MESSAGE.

  • The CONFIGURE_INIT constant must be defined in order to make <rtems/confdefs.h> instantiate the configuration data structures. This can only be defined in one source file per application that includes <rtems/confdefs.h> or the symbol table will be instantiated multiple times and linking errors produced.

This example illustrates that parameters have default values. Among other things, the application implicitly used the following defaults:

  • All unspecified types of communications and synchronization objects in the Classic and POSIX Threads API have maximums of zero (0).

  • The filesystem will be the default filesystem which is the In-Memory File System (IMFS).

  • The application will have the default number of priority levels.

  • The minimum task stack size will be that recommended by RTEMS for the target architecture.

26.6. Unlimited Objects

In real-time embedded systems the RAM is normally a limited, critical resource and dynamic allocation is avoided as much as possible to ensure predictable, deterministic execution times. For such cases, see Sizing the RTEMS Workspace for an overview of how to tune the size of the workspace. Frequently when users are porting software to RTEMS the precise resource requirements of the software is unknown. In these situations users do not need to control the size of the workspace very tightly because they just want to get the new software to run; later they can tune the workspace size as needed.

The following object classes in the Classic API can be configured in unlimited mode:

  • Barriers

  • Message Queues

  • Partitions

  • Periods

  • Ports

  • Regions

  • Semaphores

  • Tasks

  • Timers

Additionally, the following object classes from the POSIX API can be configured in unlimited mode:

  • Keys – pthread_key_create()

  • Key Value Pairs – pthread_setspecific()

  • Message Queues – mq_open()

  • Named Semaphores – sem_open()

  • Shared Memory – shm_open()

  • Threads – pthread_create()

  • Timers – timer_create()

Warning

The following object classes can not be configured in unlimited mode:

  • Drivers

  • File Descriptors

  • POSIX Queued Signals

  • User Extensions

Due to the memory requirements of unlimited objects it is strongly recommended to use them only in combination with the unified work areas. See Separate or Unified Work Areas for more information on unified work areas.

The following example demonstrates how the two simple configuration defines for unlimited objects and unified works areas can replace many seperate configuration defines for supported object classes:

#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_UNIFIED_WORK_AREAS
#define CONFIGURE_UNLIMITED_OBJECTS
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>

Users are cautioned that using unlimited objects is not recommended for production software unless the dynamic growth is absolutely required. It is generally considered a safer embedded systems programming practice to know the system limits rather than experience an out of memory error at an arbitrary and largely unpredictable time in the field.

26.6.1. Unlimited Objects by Class

When the number of objects is not known ahead of time, RTEMS provides an auto-extending mode that can be enabled individually for each object type by using the macro rtems_resource_unlimited(). This takes a value as a parameter, and is used to set the object maximum number field in an API Configuration table. The value is an allocation unit size. When RTEMS is required to grow the object table it is grown by this size. The kernel will return the object memory back to the RTEMS Workspace when an object is destroyed. The kernel will only return an allocated block of objects to the RTEMS Workspace if at least half the allocation size of free objects remain allocated. RTEMS always keeps one allocation block of objects allocated. Here is an example of using rtems_resource_unlimited():

#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited( 5 )

Object maximum specifications can be evaluated with the rtems_resource_is_unlimited() and rtems_resource_maximum_per_allocation() macros.

26.6.2. Unlimited Objects by Default

To ease the burden of developers who are porting new software RTEMS also provides the capability to make all object classes listed above operate in unlimited mode in a simple manner. The application developer is only responsible for enabling unlimited objects (CONFIGURE_UNLIMITED_OBJECTS) and specifying the allocation size (CONFIGURE_UNLIMITED_ALLOCATION_SIZE).

#define CONFIGURE_UNLIMITED_OBJECTS
#define CONFIGURE_UNLIMITED_ALLOCATION_SIZE 5