Skip to main content

Design Concept

Runtime memory allocation in embedded systems is a design flaw

In embedded systems, runtime memory allocation should be regarded as a design flaw. All resources in the system should be allocated and configured as much as possible during the construction or initialization phase. This not only improves system predictability and stability, but also makes memory usage analysis and resource planning easier.

It is important to note that this principle does not mean banning dynamic memory allocation (such as malloc, new), but rather emphasizes that the timing of dynamic memory allocation must be during the system's initialization phase. After entering the main loop or starting task scheduling, no new memory allocation operations should occur. Otherwise, it introduces:

  • Unknown delays (such as fragmentation, etc.)
  • Hard-to-track memory leaks or boundary errors
  • Potential memory allocation failures

In other words, "dynamic allocation is allowed, but must be used at a static time."
Under this premise, you can even implement memory allocation with a write-only stack, making it very easy to monitor memory usage.

All callbacks/interrupts must be non-blocking

Callbacks are execution points across contexts. Whether triggered by interrupts, schedulers, or asynchronous cross-thread mechanisms, their responsibility should be extremely restrained. The design purpose of a callback is not to "handle", but to "handoff".

In LibXR, all callbacks are only allowed to perform the following two classes of operations:

  1. Notify threads: set state, release semaphores, publish events;
  2. Push data: write into lock-free queues, cache structures, or other pre-allocated data areas.

All other behaviors are strictly prohibited:

  • Blocking wait (such as semaphores, locks, sleep)
  • Business logic processing or invoking upper-layer interfaces
  • Dynamic memory allocation
  • Calling any function with unpredictable latency

Execution context (thread/isr) must be explicitly passed into callbacks

  • All callbacks must receive a bool in_isr parameter
  • OS-wrapped APIs are clearly split into Api() / ApiFromCallback(in_isr)
  • Users do not need to determine the current context; just propagate in_isr upward
  • Ensures all callbacks, task switching, and signaling interactions work safely under ISR / Thread modes
  • You never need to guess whether you're running inside an interrupt

Every I/O operation must bind a defined completion behavior

The key to I/O operations is not "issuing a request", but rather how to know when it completes, and how to handle the result afterward.

LibXR models I/O behaviors using the Operation type, binding the response mechanism at the time the operation is initiated:

ModeTypeDescription
CallbackCALLBACKCallback function triggered upon finish
BlockingBLOCKCurrent task blocks until complete/timeout
PollingPOLLINGUser actively checks completion status
IgnoreNONEFire and forget, no feedback expected
WriteOperation op_cb(callback);     // Async callback
WriteOperation op_block(sem, 100); // Blocking wait
WriteOperation op_poll(status); // Polling
WriteOperation op_none; // Ignore result

uart1.Write("Hello, world!", op_block);

An operation without a bound completion behavior is uncontrollable.

No platform-specific types should appear in interfaces

Users should never see platform-specific structs or dependencies in any interface. For example:

  • STM32's UART_HandleTypeDef*
  • ESP-IDF's uart_port_t
  • Linux's termios
  • FreeRTOS's TaskHandle_t, SemaphoreHandle_t

These types must only exist inside platform-specific implementations and should never appear in interface declarations, parameters, or return values.

Interfaces must remain platform-agnostic to ensure:

  • Swappability across different platforms
  • Testability and simulability of behavior
  • Code elimination for unused platform implementations

If a platform type appears in an interface, then that interface becomes non-reusable, unmaintainable, and causes upper-layer logic to depend on concrete implementations.