Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion ports/linux/gnu/inc/tx_port.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,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;\
Expand Down Expand Up @@ -552,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;
Expand Down
45 changes: 45 additions & 0 deletions ports/linux/gnu/src/tx_thread_schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/

// Portions of this file were generated with AI assistance.


/**************************************************************************/
/**************************************************************************/
Expand Down Expand Up @@ -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;
Expand Down