Partition memory – introduction and basic services

Memory partitions were introduced in a previous article, where a comparison with the standard C malloc() function was made. A partition is a memory area obtained from a partition pool. This offers a flexible means for tasks to obtain and release data storage in a deterministic and reliable fashion.

Using Partitions

In Nucleus SE, partition pools are configured at build time. There may be a maximum of 16 partition pools configured for an application. If no partition pools are configured, no data structures or service call code appertaining to partition pools are included in the application.

A partition pool is simply an area of memory, which is divided into a specific number of fixed sized partitions. The user has complete control over the size and number of partitions in each pool. Tasks may request to be allocated memory partitions and receive a pointer to the storage area. It is the task’s responsibility not to write data outside of the partition. The partition may be deallocated by any task by passing the pointer to an API function. Requesting the allocation of a partition, when no more are available, may result in an error or task suspension, depending on options selected in the API call and the Nucleus SE configuration.

Configuring Memory Partitions

Number of Partition Pools

As with most aspects of Nucleus SE, the configuration of partition pools is primarily controlled by #define statements in nuse_config.h . The key setting is NUSE_PARTITION_POOL_NUMBER , which determines how many partition pools are configured for the application. The default setting is 0 (i.e. no partition pools are in use) and you can set it to any value up to 16. An erroneous value will result in a compile time error, which is generated by a test in nuse_config_check.h (this is included into nuse_config.c and hence compiled with this module) resulting in a #error statement being compiled.

Choosing a non-zero value is the “master enable” for partition pools. This results in some data structures being defined and sized accordingly. Data structures in ROM require initializing to suitable values that characterize each partition pool. More on data structures in the next article. It also activates the API enabling settings.

API Enables

Every API function (service call) in Nucleus SE has an enabling #define symbol in nuse_config.h . For partition pools, these are:

NUSE_PARTITION_ALLOCATE

NUSE_PARTITION_DEALLOCATE

NUSE_PARTITION_POOL_INFORMATION

NUSE_PARTITION_POOL_COUNT

By default, all of these are set to FALSE , thus disabling each service call and inhibiting the inclusion of any implementation code. To configure partition pools for an application, you need to select the API calls that you want to use and set their enabling symbols to TRUE .

Here is an extract from the default nuse_config.h file:

A compile time error will result if a partition pool API function is enabled and no partition pools are configured (except for NUSE_Partition_Pool_Count() which is always permitted). If your code uses an API call, which has not been enabled, a link time error will result, as no implementation code will have been included in the application.

Partition Pool Service Calls

Nucleus RTOS supports seven service calls, which appertain to partition pools that provide the following functionality:

  • Allocate a partition: NU_Allocate_Partition() . Implemented by NUSE_Partition_Allocate() in Nucleus SE.

  • Deallocate a partition: NU_Deallocate_Partition() . Implemented by NUSE_Partition_Deallocate() in Nucleus SE.

  • Provide information about a specified partition pool: NU_Partition_Pool_Information() . Implemented by NUSE_Partition_Pool_Information() in Nucleus SE.

  • Return a count of how many partition pools are (currently) configured for the application: NU_Established_Partition_Pools() . Implemented by NUSE_Partition_Pool_Count() in Nucleus SE.

  • Add a new partition pool to the application (create): NU_Create_Partition_Pool() . Not implemented in Nucleus SE.

  • Remove a partition pool from the application (delete): NU_Delete_Partition_Pool() . Not implemented in Nucleus SE.

  • Return pointers to all the partition pools (currently) in the application: NU_Partition_Pool_Pointers() . Not implemented in Nucleus SE.

The implementation of each of these service calls is examined in detail.

It may be noted that no reset function is provided (in either Nucleus RTOS or Nucleus SE). This is intentional. It is very common practice for one task to allocate a partition and pass a pointer to another task (which will probably deallocate it later). If a partition pool were to be reset, all the partitions would be marked as unused, but there is no means of tracking and notifying all tasks that may be using the partitions.

Partition Allocation and Deallocation Services

The fundamental operations, which can be performed on a partition pool, are allocating a partition (i.e. marking a partition as used and returning its address) from it and deallocating a partition (i.e. marking a partition as unused). Nucleus RTOS and Nucleus SE each provide two basic API calls for these operations, which will be discussed here.

Allocating a Partition

The Nucleus RTOS API call for allocating a partition is very flexible, enabling you to suspend indefinitely, or with a timeout, if the operation cannot be completed immediately; i.e. you try to allocate a partition from a pool in which all partitions are currently allocated. Nucleus SE provides the same service, except task suspend is optional and timeout is not implemented.

Nucleus RTOS API Call for Partition Allocation

Service call prototype:

STATUS NU_Allocate_Partition(NU_PARTITION_POOL *pool,
VOID **return_pointer, UNSIGNED suspend);

Returns:

NU_SUCCESS – the call was completed successfully

NU_NO_PARTITION – no partitions are available

NU_INVALID_POOL – the partition pool pointer is invalid

NU_INVALID_POINTER – the data return pointer is NULL

NU_INVALID_SUSPEND – suspend was attempted from a non-task thread

NU_TIMEOUT – no partition is available even after suspending for the specified timeout period

NU_POOL_DELETED – partition pool was deleted while the task was suspended

Nucleus SE API Call for Allocating

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

STATUS NUSE_Partition_Allocate(NUSE_PARTITION_POOL pool, ADDR *return_pointer, U8 suspend);  

Parameters:

pool – the index (ID) of the partition pool to be utilized

return_pointer – a pointer to a variable of type ADDR which will receive the address of the allocated partition

suspend – specification for task suspend; may be NUSE_NO_SUSPEND or NUSE_SUSPEND

Returns:

NUSE_SUCCESS – the call was completed successfully

NUSE_NO_PARTITION – no partitions are available

NUSE_INVALID_POOL – the partition pool index is invalid

NUSE_INVALID_POINTER – the data return pointer is NULL

NUSE_INVALID_SUSPEND – suspend was attempted from a non-task thread or when blocking API calls were not enabled

Nucleus SE Implementation of Partition Allocation

The bulk of the code of the NUSE_Partition_Allocate() API function – after parameter checking – is selected by conditional compilation, dependent on whether support for blocking (task suspend) API calls is enabled. We will look at the two variants separately here.

If blocking is not enabled, the code for this API call is quite straightforward:

First, the availability of free partitions is checked and an error returned (NUSE_ NO_PARTITION ) if there is none. The partitions are then stepped through, inspecting the first byte for a zero value (meaning unused). When this is found, an in-use flag is written, incorporating the index of the partition pool (see Deallocating a Partition below), and a pointer to the next byte (the start of the real data area) returned. For an explanation of the partition pool data structures, see Data Structures later in the next article.

If blocking is enabled, the code for this API call is a little more complex:

The code is enclosed in a do…while loop, which continues while the parameter suspend has the value NUSE_SUSPEND .

If a partition is available, it is marked as being in use, as described above, and the data pointer is set up. The suspend variable is set to NUSE_NO_SUSPEND and the API call exits with NUSE_SUCCESS .

If no partitions are available and suspend is set to NUSE_NO_SUSPEND , the API call exits with NUSE_ NO_PARTITION . If suspend was set to NUSE_SUSPEND , the task is suspended. On return (i.e. when the task is woken up), if the return value is NUSE_SUCCESS , indicating that the task was woken because a partition has been deallocated, the code loops back to the top. Of course, since there is no reset API function for partition pools, this is the only possible reason for the task to be woken, but the process of checking NUSE_Task_Blocking_Return[] is retained for consistency with the handling of blocking with other object types.

Deallocating a Partition

Deallocating a partition in Nucleus RTOS and Nucleus SE simply makes it available for allocation again. No check is made (or could be made) on whether any task is still using the partition; this is the responsibility of the applications programmer. Only the pointer to the data area is required in order to deallocate a partition.

Nucleus RTOS API Call for Partition Deallocation

Service call prototype:

STATUS NU_Deallocate_Partition(VOID *partition);

Parameters:

partition – pointer to the data area (as returned by NU_Allocate_Partition() ) of the partition to be deallocated

Returns:

NU_SUCCESS – the call was completed successfully

NU_INVALID_POINTER – the partition pointer is NULL or does not appear to point to a valid, in-use partition

Nucleus SE API Call for Partition Deallocation

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

STATUS NUSE_Partition_Deallocate(ADDR partition);

Parameters:

partition – pointer to the data area (as returned by NUSE_Partition_Allocate() ) of the partition to be deallocated

Returns:

NUSE_SUCCESS – the call was completed successfully

NUSE_INVALID_POINTER – the partition pointer is NULL or does not appear to point to a valid, in-use partition

Implementation

Instead of being implemented in blocking and non-blocking forms, the NUSE_Partition_Deallocate() API function simply contains a conditionally compiled section which deals with task unblocking. This code implements the actual partition deallocation:

First the index of the partition pool is extracted from the partition status byte. Then, the status is set to “unused”, the usage count decremented and success reported on return.

If task blocking is enabled, this code is included to take care of waking up any tasks waiting upon the partition pool:

If any tasks are blocked on allocation of a partition in this pool, the first in the table is woken. 

The next article will cover some additional API calls associated with partition memory, along with the relevant data structures.


Colin Walls has over thirty years experience in the electronics industry, largely dedicated to embedded software. A frequent presenter at conferences and seminars and author of numerous technical articles and two books on embedded software, Colin is an embedded software technologist with Mentor Embedded [the Mentor Graphics Embedded Software Division], and is based in the UK. His regular blog is located at: http://blogs.mentor.com/colinwalls. He may be reached by email at colin_walls@mentor.com

2 thoughts on “Partition memory – introduction and basic services

  1. “Colin, you refer to memory partitions being introduced in a previous article. Could you provide a link to that article? I have looked diligently through embedded.com and come up empty handed. I would like to see your comparison to malloc() and free().”

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.