Can FreeRTOS-POSIX be used with SMP

Hi

FreeRTOS POSIX V1.1.0 was launched four years ago, but SMP was launched this year with v11. Can FreeRTOS + POSIX be used for FreeRTOS SMP?

FreeRTOS-POSIX is a labs project which implements a small subset of POSIX APIs. It does not expose the SMP specific functionality currently. Other than that it should theoretically work but we never tested it with SMP. Why do you want to use FreeRTOS-POSIX and not native FreeRTOS APIs directly?

Sorry for the late reply. Our client is exploring POSIX compatibility, and we’ve been modifying POSIX APIs to adapt to the V11.1 SMP environment. However, we’ve encountered an issue with errno handling in SMP scenarios.

The problem:
We’re trying to replace the global errno variable with a per-core array like freertos_errno[configNUMBER_OF_CORES], but there’s a race condition during assignment. When determining the core ID for errno updates, a context switch might occur between reading the core ID and writing to the array. This could lead to the errno value being written to the wrong core’s slot if the thread migrates between cores during the switch.

We’re considering atomic operations to ensure core ID consistency during assignment, but we’re wondering are there alternative approaches to handle it?

Making errno core specific doesn’t actually do anything about the problem, as if the task could change during the setting, it could change just after the setting and the task wouldn’t see it had been set.

Normally, errno is made per thread/task, not per-core.

Yes, that is the point. While the current implement saves/restores errno through the iTaskError field in the TCB during context switches vTaskSwitchContext().

 #if ( configUSE_POSIX_ERRNO == 1 )
+#if ( configNUMBER_OF_CORES> 1 )
+    volatile int FreeRTOS_errnos[ configNUMBER_OF_CORES] = { 0 };
+    #define FreeRTOS_errno    FreeRTOS_errnos[ portGET_CORE_ID() ]
+#else
        int FreeRTOS_errno = 0;
+#endif /* configNUMBER_OF_CORES> 1 */
 #endif

Use array to avoid FreeRTOS_errno modified by multi-core, but this approach creates a hazardous race condition in SMP environments:

  1. Pre-Switch Phase:
  • Task_A on Core_0 writes to freertos_errno[Core_0]
  • Context switch triggered before TCB update
  1. Post-Switch Phase:
  • Task_A migrates to Core_1
  • Scheduler restores stale iTaskError from TCB (now mapped to freertos_errno[Core_1])

Should we just have one copy in the TCB and always read/write that?

That’s a good suggestion, but since the TCB_t structure is defined internally in the .c file (not exposed in headers), POSIX layers and applications can’t directly access pxTCB->iTaskErrno for errno operations.
How about store errno in the pthread structure itself?

typedef struct pthread_internal
{
    pthread_attr_internal_t xAttr;        /**< Thread attributes. */
    void * ( *pvStartRoutine )( void * ); /**< Application thread function. */
    void * xTaskArg;                      /**< Arguments for application thread function. */
    TaskHandle_t xTaskHandle;             /**< FreeRTOS task handle. */
    StaticSemaphore_t xJoinBarrier;       /**< Synchronizes the two callers of pthread_join. */
    StaticSemaphore_t xJoinMutex;         /**< Ensures that only one other thread may join this thread. */
    void * xReturn;                       /**< Return value of pvStartRoutine. */
+   int32_t errno;                         /**< Error number. */
} pthread_internal_t;

Allow direct access via pthread_self()->errno without exposing implementation details.

This suggestion sounds good to me!

Sorry,pthread_internal_t is also defined in the .c file :cold_sweat:. If adding new APIs in FreeRTOS_POSIX_pthread.c and pthread.h to read errors, it seems inconsistent with the pthread specification.

How about adding an xTaskGetERRNO API in tasks.c to retrieve tcb->iTaskError

#if ( configUSE_POSIX_ERRNO == 1 )
    extern int *xTaskGetERRNO( void );
    #define errno    *xTaskGetERRNO()
#endif

We won’t be deviating from the spec but just add some APIs, right? Since errno is related to POSIX, it makes more sense to keep it in the FreeRTOS_POSIX_pthread code.