summaryrefslogtreecommitdiff
path: root/ports/linux/gnu
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-10-02 10:42:44 -0400
committerGitHub <[email protected]>2026-10-02 10:42:44 -0400
commit93387b0a60382a29579bbad5045c68328e3751df (patch)
tree42be790d602cb76f55090e5a7c418df7ea2b3428 /ports/linux/gnu
parent44d7c95c582d415c4ad84527180b29c93c3bf664 (diff)
parent28281cd5647d4671236ca08d19bd18ed15b2265a (diff)
Merge pull request #783 from eclipse-threadx/devv6.5.2.202603_rel
Merged changes ahead of the v6.5.2.202603 release
Diffstat (limited to 'ports/linux/gnu')
-rw-r--r--ports/linux/gnu/CMakeLists.txt10
-rw-r--r--ports/linux/gnu/example_build/CMakeLists.txt17
-rw-r--r--ports/linux/gnu/inc/tx_port.h33
-rw-r--r--ports/linux/gnu/src/tx_thread_schedule.c45
-rw-r--r--ports/linux/gnu/src/tx_thread_stack_build.c12
5 files changed, 108 insertions, 9 deletions
diff --git a/ports/linux/gnu/CMakeLists.txt b/ports/linux/gnu/CMakeLists.txt
index 4b517940..17138044 100644
--- a/ports/linux/gnu/CMakeLists.txt
+++ b/ports/linux/gnu/CMakeLists.txt
@@ -15,8 +15,16 @@ target_sources(${PROJECT_NAME}
)
target_include_directories(${PROJECT_NAME}
+ SYSTEM
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/inc
)
-target_compile_definitions(${PROJECT_NAME} PUBLIC "-D_GNU_SOURCE -DTX_LINUX_DEBUG_ENABLE") \ No newline at end of file
+target_compile_definitions(${PROJECT_NAME} PUBLIC "-D_GNU_SOURCE -DTX_LINUX_DEBUG_ENABLE")
+
+# The demo program beside the port. Off by default so the ordinary build
+# produces just the library; -DTHREADX_SAMPLE=ON adds the sample_threadx target.
+option(THREADX_SAMPLE "Build the sample program for this port" OFF)
+if(THREADX_SAMPLE)
+ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/example_build)
+endif()
diff --git a/ports/linux/gnu/example_build/CMakeLists.txt b/ports/linux/gnu/example_build/CMakeLists.txt
new file mode 100644
index 00000000..90d4078a
--- /dev/null
+++ b/ports/linux/gnu/example_build/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Build the sample_threadx program that ports/linux/gnu/Makefile builds, so the
+# CMake build can produce a runnable demo rather than only the library.
+#
+# Guarded by THREADX_SAMPLE in the parent so the default build stays a pure
+# library build.
+
+add_executable(sample_threadx)
+
+target_sources(sample_threadx PRIVATE ${CMAKE_CURRENT_LIST_DIR}/sample_threadx.c)
+
+target_include_directories(sample_threadx
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/../inc
+ ${CMAKE_CURRENT_LIST_DIR}/../../../../${TX_COMMON_DIR}/inc
+)
+
+target_link_libraries(sample_threadx PRIVATE threadx)
diff --git a/ports/linux/gnu/inc/tx_port.h b/ports/linux/gnu/inc/tx_port.h
index 842afe0f..def3e28f 100644
--- a/ports/linux/gnu/inc/tx_port.h
+++ b/ports/linux/gnu/inc/tx_port.h
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -317,13 +319,21 @@ void _tx_linux_debug_entry_insert(char *action, char *file, unsigned long lin
*/
-#ifndef TX_MISRA_ENABLE
+/* The clock below is read for every trace event in both builds. The MISRA form
+ of the in-line insert takes the time stamp as an argument rather than reading
+ it itself, so the macro has to be an expression; that is why it carries no
+ trailing semicolon. */
+
#ifndef TX_TRACE_TIME_SOURCE
-#define TX_TRACE_TIME_SOURCE ((ULONG) (_tx_linux_time_stamp.tv_nsec));
+#define TX_TRACE_TIME_SOURCE ((ULONG) (_tx_linux_time_stamp.tv_nsec))
#endif
-#else
+
+/* Declared here rather than used: this port supplies its own time stamp above,
+ but the generic definition in common/src/tx_misra.c is compiled for this port
+ and needs a declaration in scope. */
+
+#ifdef TX_MISRA_ENABLE
ULONG _tx_misra_time_stamp_get(VOID);
-#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get()
#endif
#ifndef TX_TRACE_TIME_MASK
@@ -501,7 +511,7 @@ VOID _tx_thread_interrupt_restore(UINT previous_posture);
#define TX_RESTORE _tx_linux_debug_entry_insert("RESTORE", __FILE__, __LINE__); \
_tx_thread_interrupt_restore(tx_saved_posture);
#endif /* TX_LINUX_DEBUG_ENABLE */
-#define tx_linux_mutex_lock(p) pthread_mutex_lock(&p)
+#define tx_linux_mutex_lock(p) _tx_linux_mutex_lock_retry(&p)
#define tx_linux_mutex_unlock(p) pthread_mutex_unlock(&p)
#define tx_linux_mutex_recursive_unlock(p) {\
int _recursive_count = (int)tx_linux_mutex_recursive_count;\
@@ -533,7 +543,7 @@ VOID _tx_thread_interrupt_restore(UINT previous_posture);
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
- "Copyright (c) Microsoft Corporation * ThreadX Linux/gcc Version 6.5.1.202602a *";
+ "Copyright (c) Microsoft Corporation * ThreadX Linux/gcc Version 6.5.2.202603 *";
#else
extern CHAR _tx_version_id[];
#endif
@@ -542,6 +552,17 @@ extern CHAR _tx_version_id[];
/* Define externals for the Linux port of ThreadX. */
extern pthread_mutex_t _tx_linux_mutex;
+
+/* Define how long a thread waits on the Linux mutex before retrying. A thread
+ parked on the mutex can be suspended by the port's signal handler and so never
+ act on the wake-up the next unlock sends it, which leaves the wake-up lost and
+ every other waiter parked on a mutex that is free. */
+
+#ifndef TX_LINUX_MUTEX_RETRY_NSEC
+#define TX_LINUX_MUTEX_RETRY_NSEC 1000000
+#endif
+
+void _tx_linux_mutex_lock_retry(pthread_mutex_t *mutex);
extern sem_t _tx_linux_semaphore;
extern sem_t _tx_linux_semaphore_no_idle;
extern ULONG _tx_linux_global_int_disabled_flag;
diff --git a/ports/linux/gnu/src/tx_thread_schedule.c b/ports/linux/gnu/src/tx_thread_schedule.c
index eeff680f..405ef4b8 100644
--- a/ports/linux/gnu/src/tx_thread_schedule.c
+++ b/ports/linux/gnu/src/tx_thread_schedule.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -201,6 +203,49 @@ struct timespec ts;
}
}
+/* Define the ThreadX Linux mutex lock function. The wait is timed and retried
+ rather than left to pthread_mutex_lock, because a thread can be signalled into
+ the port's suspend handler while it is parked on this mutex. That handler does
+ not return until the thread is resumed, so the wake-up the next unlock sends is
+ delivered to a thread that never retries and is lost. Any other thread parked
+ on the mutex then waits on a mutex that is free. Retrying on a timeout costs
+ nothing when the mutex is handed over normally, and turns that lost wake-up into
+ a delay of at most the retry period. */
+
+void _tx_linux_mutex_lock_retry(pthread_mutex_t *mutex)
+{
+
+INT linux_status;
+struct timespec ts;
+
+
+ do
+ {
+
+ /* Set the deadline for this attempt. */
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_nsec = ts.tv_nsec + TX_LINUX_MUTEX_RETRY_NSEC;
+ if (ts.tv_nsec >= 1000000000)
+ {
+
+ ts.tv_nsec = ts.tv_nsec - 1000000000;
+ ts.tv_sec++;
+ }
+
+ linux_status = pthread_mutex_timedlock(mutex, &ts);
+
+ /* Anything but the deadline expiring is a real failure to obtain the
+ mutex, so stop retrying. */
+ if ((linux_status != 0) && (linux_status != ETIMEDOUT))
+ {
+
+ break;
+ }
+
+ } while (linux_status != 0);
+}
+
+
void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_saved_posture)
{
INT linux_status;
diff --git a/ports/linux/gnu/src/tx_thread_stack_build.c b/ports/linux/gnu/src/tx_thread_stack_build.c
index cdadba6c..102ded32 100644
--- a/ports/linux/gnu/src/tx_thread_stack_build.c
+++ b/ports/linux/gnu/src/tx_thread_stack_build.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Portions of this file were generated with AI assistance.
+
/**************************************************************************/
/**************************************************************************/
@@ -79,6 +81,7 @@ void *_tx_linux_thread_entry(void *ptr);
/**************************************************************************/
VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
{
+ALIGN_TYPE fake_stack_ptr;
struct sched_param sp;
(VOID)function_ptr;
@@ -118,8 +121,13 @@ struct sched_param sp;
tx_interrupt_control nesting. */
thread_ptr -> tx_thread_linux_int_disabled_flag = 0;
- /* Setup a fake thread stack pointer. */
- thread_ptr -> tx_thread_stack_ptr = (VOID *) (((CHAR *) thread_ptr -> tx_thread_stack_end) - 8);
+ /* Setup a fake thread stack pointer. The stack end points at the last byte of the
+ thread's stack area and is therefore not necessarily aligned, so round the result
+ down to a ULONG boundary. This pointer is dereferenced as a ULONG below and is
+ also the starting value of the stack checking logic's highest used pointer. */
+ fake_stack_ptr = (ALIGN_TYPE) ((VOID *) (((CHAR *) thread_ptr -> tx_thread_stack_end) - 8));
+ fake_stack_ptr = fake_stack_ptr & (~((ALIGN_TYPE) (sizeof(ULONG) - 1)));
+ thread_ptr -> tx_thread_stack_ptr = (VOID *) ((ALIGN_TYPE) fake_stack_ptr);
/* Clear the first word of the stack. */
*(((ULONG *) thread_ptr -> tx_thread_stack_ptr) - 1) = 0;