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
3 changes: 3 additions & 0 deletions common/inc/tx_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ VOID _tx_mutex_initialize(VOID);

/* Define internal mutex management function prototypes. */

#ifdef TX_MUTEX_INHERIT_CHAIN_MAX
VOID _tx_mutex_priority_chain(TX_THREAD *thread_ptr, UINT new_priority);
#endif
VOID _tx_mutex_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence);
VOID _tx_mutex_thread_release(TX_THREAD *thread_ptr);
VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority);
Expand Down
11 changes: 10 additions & 1 deletion common/inc/tx_user_sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

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


/**************************************************************************/
/**************************************************************************/
/** */
Expand Down Expand Up @@ -262,6 +261,16 @@
#define TX_MUTEX_ENABLE_PERFORMANCE_INFO
*/

/* Determine if priority inheritance follows chains of mutexes. When a thread that inherits
a priority is itself waiting on a priority inheritance mutex, the owner of that mutex does
not inherit the priority unless the following is defined. Its value is the maximum number
of mutexes followed along one chain, which bounds the time tx_mutex_get spends passing
the priority on. */

/*
#define TX_MUTEX_INHERIT_CHAIN_MAX 8
*/

/* Determine if queue performance gathering is required by the application. When the following is
defined, ThreadX gathers various queue performance information. */

Expand Down
13 changes: 13 additions & 0 deletions common/src/tx_mutex_get.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
/* _tx_thread_system_suspend Suspend thread service */
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
/* _tx_mutex_priority_change Inherit thread priority */
/* _tx_mutex_priority_chain Inherit along mutex chain */
/* */
/* CALLED BY */
/* */
Expand Down Expand Up @@ -309,6 +310,12 @@ UINT status;
of the current thread. */
_tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);

#ifdef TX_MUTEX_INHERIT_CHAIN_MAX

/* Pass the priority on to the owner of any mutex the owner is waiting on. */
_tx_mutex_priority_chain(mutex_owner, thread_ptr -> tx_thread_priority);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This passes a priority boost to downstream owners, but I cannot find a matching update when the triggering waiter leaves or lowers its priority. In an H → L1 → L2 chain, L2 can retain H’s priority after H stops waiting, even if #807 restores L1. Could you update the affected chain on those paths and add regression coverage?

#endif

#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO

/* Increment the total mutex priority inheritance counter. */
Expand Down Expand Up @@ -368,6 +375,12 @@ UINT status;
of the current thread. */
_tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);

#ifdef TX_MUTEX_INHERIT_CHAIN_MAX

/* Pass the priority on to the owner of any mutex the owner is waiting on. */
_tx_mutex_priority_chain(mutex_owner, thread_ptr -> tx_thread_priority);
#endif

#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO

/* Increment the total mutex priority inheritance counter. */
Expand Down
121 changes: 121 additions & 0 deletions common/src/tx_mutex_priority_change.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,124 @@ UINT map_index;
}
}


#ifdef TX_MUTEX_INHERIT_CHAIN_MAX
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_mutex_priority_chain PORTABLE C */
/* */
/* DESCRIPTION */
/* */
/* This function passes an inherited priority along a chain of */
/* priority inheritance mutexes. While the thread is waiting on such a */
/* mutex, the mutex owner inherits the priority and the owner becomes */
/* the next thread in the chain. At most TX_MUTEX_INHERIT_CHAIN_MAX */
/* mutexes are followed. The walk ends at the first owner already at */
/* the priority or higher, so it also ends on a lock cycle. */
/* */
/* INPUT */
/* */
/* thread_ptr Thread that inherited priority */
/* new_priority Inherited priority */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_mutex_priority_change Inherit thread priority */
/* */
/* CALLED BY */
/* */
/* _tx_mutex_get Inherit priority */
/* */
/**************************************************************************/
VOID _tx_mutex_priority_chain(TX_THREAD *thread_ptr, UINT new_priority)
{

#ifndef TX_NOT_INTERRUPTABLE
TX_INTERRUPT_SAVE_AREA
#endif

TX_MUTEX *mutex_ptr;
TX_THREAD *owner_ptr;
UINT chain_length;


/* Follow the chain for at most TX_MUTEX_INHERIT_CHAIN_MAX mutexes. */
chain_length = ((UINT) 0);
while ((thread_ptr != TX_NULL) && (chain_length < ((UINT) TX_MUTEX_INHERIT_CHAIN_MAX)))
{

/* Default to the end of the chain. */
owner_ptr = TX_NULL;

#ifndef TX_NOT_INTERRUPTABLE

/* Disable interrupts. */
TX_DISABLE
#endif

/* Determine if this thread is waiting on a mutex. */
if ((thread_ptr -> tx_thread_state == TX_MUTEX_SUSP) && (thread_ptr -> tx_thread_suspend_cleanup != TX_NULL))
{

/* Pickup the mutex the thread is waiting on. */
mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);

/* Determine if priority inheritance is in effect. */
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
{

/* Determine if this is the highest priority to raise for this mutex. */
if (mutex_ptr -> tx_mutex_highest_priority_waiting > new_priority)
{

/* Remember this priority. */
mutex_ptr -> tx_mutex_highest_priority_waiting = new_priority;
}

/* Pickup the mutex owner. */
owner_ptr = mutex_ptr -> tx_mutex_owner;

/* Determine if we have to update inherit priority level of the mutex owner. */
if (owner_ptr -> tx_thread_inherit_priority > new_priority)
{

/* Remember the new priority inheritance priority. */
owner_ptr -> tx_thread_inherit_priority = new_priority;
}

/* Determine if the owner already runs at the priority or higher. */
if (owner_ptr -> tx_thread_priority <= new_priority)
{

/* Yes, the chain ends here. */
owner_ptr = TX_NULL;
}
}
}

#ifndef TX_NOT_INTERRUPTABLE

/* Restore interrupts. */
TX_RESTORE
#endif

/* Determine if there is an owner to raise. */
if (owner_ptr != TX_NULL)
{

/* Raise the owner's priority to the inherited priority. */
_tx_mutex_priority_change(owner_ptr, new_priority);
}

/* Move to the next thread in the chain. */
thread_ptr = owner_ptr;
chain_length++;
}
}
#endif
3 changes: 3 additions & 0 deletions common_smp/inc/tx_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ VOID _tx_mutex_initialize(VOID);

/* Define internal mutex management function prototypes. */

#ifdef TX_MUTEX_INHERIT_CHAIN_MAX
VOID _tx_mutex_priority_chain(TX_THREAD *thread_ptr, UINT new_priority);
#endif
VOID _tx_mutex_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence);
VOID _tx_mutex_thread_release(TX_THREAD *thread_ptr);
VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority);
Expand Down
11 changes: 10 additions & 1 deletion common_smp/inc/tx_user_sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

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


/**************************************************************************/
/**************************************************************************/
/** */
Expand Down Expand Up @@ -255,6 +254,16 @@
#define TX_MUTEX_ENABLE_PERFORMANCE_INFO
*/

/* Determine if priority inheritance follows chains of mutexes. When a thread that inherits
a priority is itself waiting on a priority inheritance mutex, the owner of that mutex does
not inherit the priority unless the following is defined. Its value is the maximum number
of mutexes followed along one chain, which bounds the time tx_mutex_get spends passing
the priority on. */

/*
#define TX_MUTEX_INHERIT_CHAIN_MAX 8
*/

/* Determine if queue performance gathering is required by the application. When the following is
defined, ThreadX gathers various queue performance information. */

Expand Down
13 changes: 13 additions & 0 deletions common_smp/src/tx_mutex_get.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
/* _tx_thread_system_suspend Suspend thread service */
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
/* _tx_mutex_priority_change Inherit thread priority */
/* _tx_mutex_priority_chain Inherit along mutex chain */
/* */
/* CALLED BY */
/* */
Expand Down Expand Up @@ -309,6 +310,12 @@ UINT status;
of the current thread. */
_tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);

#ifdef TX_MUTEX_INHERIT_CHAIN_MAX

/* Pass the priority on to the owner of any mutex the owner is waiting on. */
_tx_mutex_priority_chain(mutex_owner, thread_ptr -> tx_thread_priority);
#endif

#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO

/* Increment the total mutex priority inheritance counter. */
Expand Down Expand Up @@ -368,6 +375,12 @@ UINT status;
of the current thread. */
_tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);

#ifdef TX_MUTEX_INHERIT_CHAIN_MAX

/* Pass the priority on to the owner of any mutex the owner is waiting on. */
_tx_mutex_priority_chain(mutex_owner, thread_ptr -> tx_thread_priority);
#endif

#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO

/* Increment the total mutex priority inheritance counter. */
Expand Down
121 changes: 121 additions & 0 deletions common_smp/src/tx_mutex_priority_change.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,3 +484,124 @@ UINT finished;
#endif
}


#ifdef TX_MUTEX_INHERIT_CHAIN_MAX
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_mutex_priority_chain PORTABLE C */
/* */
/* DESCRIPTION */
/* */
/* This function passes an inherited priority along a chain of */
/* priority inheritance mutexes. While the thread is waiting on such a */
/* mutex, the mutex owner inherits the priority and the owner becomes */
/* the next thread in the chain. At most TX_MUTEX_INHERIT_CHAIN_MAX */
/* mutexes are followed. The walk ends at the first owner already at */
/* the priority or higher, so it also ends on a lock cycle. */
/* */
/* INPUT */
/* */
/* thread_ptr Thread that inherited priority */
/* new_priority Inherited priority */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_mutex_priority_change Inherit thread priority */
/* */
/* CALLED BY */
/* */
/* _tx_mutex_get Inherit priority */
/* */
/**************************************************************************/
VOID _tx_mutex_priority_chain(TX_THREAD *thread_ptr, UINT new_priority)
{

#ifndef TX_NOT_INTERRUPTABLE
TX_INTERRUPT_SAVE_AREA
#endif

TX_MUTEX *mutex_ptr;
TX_THREAD *owner_ptr;
UINT chain_length;


/* Follow the chain for at most TX_MUTEX_INHERIT_CHAIN_MAX mutexes. */
chain_length = ((UINT) 0);
while ((thread_ptr != TX_NULL) && (chain_length < ((UINT) TX_MUTEX_INHERIT_CHAIN_MAX)))
{

/* Default to the end of the chain. */
owner_ptr = TX_NULL;

#ifndef TX_NOT_INTERRUPTABLE

/* Disable interrupts. */
TX_DISABLE
#endif

/* Determine if this thread is waiting on a mutex. */
if ((thread_ptr -> tx_thread_state == TX_MUTEX_SUSP) && (thread_ptr -> tx_thread_suspend_cleanup != TX_NULL))
{

/* Pickup the mutex the thread is waiting on. */
mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);

/* Determine if priority inheritance is in effect. */
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
{

/* Determine if this is the highest priority to raise for this mutex. */
if (mutex_ptr -> tx_mutex_highest_priority_waiting > new_priority)
{

/* Remember this priority. */
mutex_ptr -> tx_mutex_highest_priority_waiting = new_priority;
}

/* Pickup the mutex owner. */
owner_ptr = mutex_ptr -> tx_mutex_owner;

/* Determine if we have to update inherit priority level of the mutex owner. */
if (owner_ptr -> tx_thread_inherit_priority > new_priority)
{

/* Remember the new priority inheritance priority. */
owner_ptr -> tx_thread_inherit_priority = new_priority;
}

/* Determine if the owner already runs at the priority or higher. */
if (owner_ptr -> tx_thread_priority <= new_priority)
{

/* Yes, the chain ends here. */
owner_ptr = TX_NULL;
}
}
}

#ifndef TX_NOT_INTERRUPTABLE

/* Restore interrupts. */
TX_RESTORE
#endif

/* Determine if there is an owner to raise. */
if (owner_ptr != TX_NULL)
{

/* Raise the owner's priority to the inherited priority. */
_tx_mutex_priority_change(owner_ptr, new_priority);
}

/* Move to the next thread in the chain. */
thread_ptr = owner_ptr;
chain_length++;
}
}
#endif
2 changes: 1 addition & 1 deletion test/smp/cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ endif()

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.")
set(default_build_coverage TX_QUEUE_MESSAGE_MAX_SIZE=32)
set(default_build_coverage TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_MUTEX_INHERIT_CHAIN_MAX=2)
set(disable_notify_callbacks_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_DISABLE_NOTIFY_CALLBACKS)
set(stack_checking_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_STACK_CHECKING)
set(stack_checking_rand_fill_build TX_QUEUE_MESSAGE_MAX_SIZE=32 TX_ENABLE_STACK_CHECKING TX_ENABLE_RANDOM_NUMBER_STACK_FILLING)
Expand Down
Loading
Loading