For any developer of real-time systems, the word “dynamic” should ring alarm bells, as it is generally a label for something that might compromise determinism. The best and easiest to appreciate example is dynamic memory allocation. Most programmers are familiar with malloc()/free(), but may be unaware of their pitfalls: non-deterministic behavior and ill-defined failure modes …
The first problem with malloc() is that many [perhaps most] implementations are non-deterministic – it is not possible to specify how long a memory allocation may take. The second one is allocation failure. Obviously, the function can fail because there is insufficient heap space and a NULL pointer is returned. How many developers routinely check for this? I hope that the answer is “most”. The more subtle problem is that malloc() can fail even if there is enough memory, if that memory is not contiguous. The obvious solution of “defragging” the heap is not possible, as C uses direct pointers and, in any case, it would compromise determinism.
A straightforward solution to this difficulty is provided with most RTOS products: a memory block [also called “partition”] allocation system. The idea is simple. An application has a number of “memory pools”, each of which contains a specific number of fixed size blocks. The code uses an API call to request a block and this allocation will be deterministic. If there are no free blocks available, an allocation failure will occur. This either results in an error response or task suspension, pending an available block. Fragmentation cannot occur.
In many RTOSes a pool is created dynamically. With Nucleus RTOS the prototype for the API call looks like this:
STATUS NU_Create_Partition_Pool(NU_PARTITION_POOL *pool CHAR *name, VOID *start_address, UNSIGNED pool_size, UNSIGNED partition_size, OPTION suspend_type)
Here is an example call:
status = NU_Create_Partition_Pool(&MyPool, “any name”, (VOID *) 0xB000, 2000, 40, NU_FIFO);
This specifies that the descriptor for the object is MyPool; it has 40-byte partitions/blocks; a 2000-byte memory area, which is located at 0xB000, and task suspension is in FIFO order.
Another API call is used to request the allocation of a block:
status = NU_Allocate_Partition(&MyPool, &ptr, NU_SUSPEND);
This requests an allocation of a partition from the pool described by MyPool. The pointer ptr will point to the allocated memory and the task should be suspended on allocation failure. Another call may be used to relinquish the block:
status = NU_Deallocate_Partition(ptr);