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?
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:
freertos_errno[Core_0]
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 . 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.