add SMP, Modules, and more processor/tools releases
This commit is contained in:
372
common_smp/src/tx_block_allocate.c
Normal file
372
common_smp/src/tx_block_allocate.c
Normal file
@@ -0,0 +1,372 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
#include "tx_thread.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_allocate PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function allocates a block from the specified memory block */
|
||||
/* pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* block_ptr Pointer to place allocated block */
|
||||
/* pointer */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Suspend thread */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_allocate(TX_BLOCK_POOL *pool_ptr, VOID **block_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
TX_THREAD *thread_ptr;
|
||||
UCHAR *work_ptr;
|
||||
UCHAR *temp_ptr;
|
||||
UCHAR **next_block_ptr;
|
||||
UCHAR **return_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
TX_TRACE_BUFFER_ENTRY *entry_ptr;
|
||||
ULONG time_stamp = ((ULONG) 0);
|
||||
#endif
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
UCHAR *log_entry_ptr;
|
||||
ULONG upper_tbu;
|
||||
ULONG lower_tbu;
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable interrupts to get a block from the pool. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total allocations counter. */
|
||||
_tx_block_pool_performance_allocate_count++;
|
||||
|
||||
/* Increment the number of allocations on this pool. */
|
||||
pool_ptr -> tx_block_pool_performance_allocate_count++;
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* If trace is enabled, save the current event pointer. */
|
||||
entry_ptr = _tx_trace_buffer_current_ptr;
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_ALLOCATE, pool_ptr, 0, wait_option, pool_ptr -> tx_block_pool_available, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Save the time stamp for later comparison to verify that
|
||||
the event hasn't been overwritten by the time the allocate
|
||||
call succeeds. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
time_stamp = entry_ptr -> tx_trace_buffer_entry_time_stamp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
log_entry_ptr = *(UCHAR **) _tx_el_current_event;
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_ALLOCATE_INSERT
|
||||
|
||||
/* Store -1 in the third event slot. */
|
||||
*((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) = (ULONG) -1;
|
||||
|
||||
/* Save the time stamp for later comparison to verify that
|
||||
the event hasn't been overwritten by the time the allocate
|
||||
call succeeds. */
|
||||
lower_tbu = *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET));
|
||||
upper_tbu = *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET));
|
||||
#endif
|
||||
|
||||
/* Determine if there is an available block. */
|
||||
if (pool_ptr -> tx_block_pool_available != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Yes, a block is available. Decrement the available count. */
|
||||
pool_ptr -> tx_block_pool_available--;
|
||||
|
||||
/* Pickup the current block pointer. */
|
||||
work_ptr = pool_ptr -> tx_block_pool_available_list;
|
||||
|
||||
/* Return the first available block to the caller. */
|
||||
temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
|
||||
return_ptr = TX_INDIRECT_VOID_TO_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*return_ptr = temp_ptr;
|
||||
|
||||
/* Modify the available list to point at the next block in the pool. */
|
||||
next_block_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
|
||||
pool_ptr -> tx_block_pool_available_list = *next_block_ptr;
|
||||
|
||||
/* Save the pool's address in the block for when it is released! */
|
||||
temp_ptr = TX_BLOCK_POOL_TO_UCHAR_POINTER_CONVERT(pool_ptr);
|
||||
*next_block_ptr = temp_ptr;
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the byte
|
||||
allocate event. In that case, do nothing here. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Is the time stamp the same? */
|
||||
if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
|
||||
{
|
||||
|
||||
/* Timestamp is the same, update the entry with the address. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
entry_ptr -> tx_trace_buffer_entry_info_2 = TX_POINTER_TO_ULONG_CONVERT(*block_ptr);
|
||||
#else
|
||||
entry_ptr -> tx_trace_buffer_entry_information_field_2 = TX_POINTER_TO_ULONG_CONVERT(*block_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
/* Store the address of the allocated block. */
|
||||
*((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) = (ULONG) *block_ptr;
|
||||
#endif
|
||||
|
||||
/* Set status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Default the return pointer to NULL. */
|
||||
return_ptr = TX_INDIRECT_VOID_TO_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*return_ptr = TX_NULL;
|
||||
|
||||
/* Determine if the request specifies suspension. */
|
||||
if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point, return error completion. */
|
||||
status = TX_NO_MEMORY;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total suspensions counter. */
|
||||
_tx_block_pool_performance_suspension_count++;
|
||||
|
||||
/* Increment the number of suspensions on this pool. */
|
||||
pool_ptr -> tx_block_pool_performance_suspension_count++;
|
||||
#endif
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_block_pool_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this pool control
|
||||
block. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) pool_ptr;
|
||||
|
||||
/* Save the return block pointer address as well. */
|
||||
thread_ptr -> tx_thread_additional_suspend_info = (VOID *) block_ptr;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Pickup the number of suspended threads. */
|
||||
suspended_count = (pool_ptr -> tx_block_pool_suspended_count);
|
||||
|
||||
/* Increment the number of suspended threads. */
|
||||
(pool_ptr -> tx_block_pool_suspended_count)++;
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
pool_ptr -> tx_block_pool_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = pool_ptr -> tx_block_pool_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_BLOCK_MEMORY;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the byte
|
||||
allocate event. In that case, do nothing here. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Is the time-stamp the same? */
|
||||
if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
|
||||
{
|
||||
|
||||
/* Timestamp is the same, update the entry with the address. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
entry_ptr -> tx_trace_buffer_entry_info_2 = TX_POINTER_TO_ULONG_CONVERT(*block_ptr);
|
||||
#else
|
||||
entry_ptr -> tx_trace_buffer_entry_information_field_2 = TX_POINTER_TO_ULONG_CONVERT(*block_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
/* Check that the event time stamp is unchanged and the call is about
|
||||
to return success. A different timestamp means that a later event
|
||||
wrote over the block allocate event. A return value other than
|
||||
TX_SUCCESS indicates that no block was available. In those cases,
|
||||
do nothing here. */
|
||||
if (lower_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) &&
|
||||
upper_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) &&
|
||||
((thread_ptr -> tx_thread_suspend_status) == TX_SUCCESS))
|
||||
{
|
||||
|
||||
/* Store the address of the allocated block. */
|
||||
*((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) = (ULONG) *block_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Immediate return, return error completion. */
|
||||
status = TX_NO_MEMORY;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
213
common_smp/src/tx_block_pool_cleanup.c
Normal file
213
common_smp/src/tx_block_pool_cleanup.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_cleanup PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes block allocate timeout and thread terminate */
|
||||
/* actions that require the block pool data structures to be cleaned */
|
||||
/* up. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to suspended thread's */
|
||||
/* control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_timeout Thread timeout processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* _tx_thread_wait_abort Thread wait abort processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_block_pool_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_BLOCK_POOL *pool_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts to remove the suspended thread from the block pool. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the cleanup is still required. */
|
||||
if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_block_pool_cleanup))
|
||||
{
|
||||
|
||||
/* Check for valid suspension sequence. */
|
||||
if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
|
||||
{
|
||||
|
||||
/* Setup pointer to block pool control block. */
|
||||
pool_ptr = TX_VOID_TO_BLOCK_POOL_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
|
||||
/* Check for a NULL byte pool pointer. */
|
||||
if (pool_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Check for valid pool ID. */
|
||||
if (pool_ptr -> tx_block_pool_id == TX_BLOCK_POOL_ID)
|
||||
{
|
||||
|
||||
/* Determine if there are any thread suspensions. */
|
||||
if (pool_ptr -> tx_block_pool_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
#else
|
||||
|
||||
/* Setup pointer to block pool control block. */
|
||||
pool_ptr = TX_VOID_TO_BLOCK_POOL_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
#endif
|
||||
|
||||
/* Yes, we still have thread suspension! */
|
||||
|
||||
/* Clear the suspension cleanup flag. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Decrement the suspended count. */
|
||||
pool_ptr -> tx_block_pool_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = pool_ptr -> tx_block_pool_suspended_count;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
pool_ptr -> tx_block_pool_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same suspension list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Determine if we need to update the head pointer. */
|
||||
if (pool_ptr -> tx_block_pool_suspension_list == thread_ptr)
|
||||
{
|
||||
|
||||
/* Update the list head pointer. */
|
||||
pool_ptr -> tx_block_pool_suspension_list = next_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we need to determine if this cleanup is from a terminate, timeout,
|
||||
or from a wait abort. */
|
||||
if (thread_ptr -> tx_thread_state == TX_BLOCK_MEMORY)
|
||||
{
|
||||
|
||||
/* Timeout condition and the thread still suspended on the block pool.
|
||||
Setup return error status and resume the thread. */
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total timeouts counter. */
|
||||
_tx_block_pool_performance_timeout_count++;
|
||||
|
||||
/* Increment the number of timeouts on this block pool. */
|
||||
pool_ptr -> tx_block_pool_performance_timeout_count++;
|
||||
#endif
|
||||
|
||||
/* Setup return status. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_NO_MEMORY;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
213
common_smp/src/tx_block_pool_create.c
Normal file
213
common_smp/src/tx_block_pool_create.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_create PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a pool of fixed-size memory blocks in the */
|
||||
/* specified memory area. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* name_ptr Pointer to block pool name */
|
||||
/* block_size Number of bytes in each block */
|
||||
/* pool_start Address of beginning of pool area */
|
||||
/* pool_size Number of bytes in the block pool */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
|
||||
VOID *pool_start, ULONG pool_size)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT blocks;
|
||||
UINT status;
|
||||
ULONG total_blocks;
|
||||
UCHAR *block_ptr;
|
||||
UCHAR **block_link_ptr;
|
||||
UCHAR *next_block_ptr;
|
||||
TX_BLOCK_POOL *next_pool;
|
||||
TX_BLOCK_POOL *previous_pool;
|
||||
|
||||
|
||||
/* Initialize block pool control block to all zeros. */
|
||||
TX_MEMSET(pool_ptr, 0, (sizeof(TX_BLOCK_POOL)));
|
||||
|
||||
/* Round the block size up to something that is evenly divisible by
|
||||
an ALIGN_TYPE (typically this is a 32-bit ULONG). This helps guarantee proper alignment. */
|
||||
block_size = (((block_size + (sizeof(ALIGN_TYPE))) - ((ALIGN_TYPE) 1))/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
|
||||
|
||||
/* Round the pool size down to something that is evenly divisible by
|
||||
an ALIGN_TYPE (typically this is a 32-bit ULONG). */
|
||||
pool_size = (pool_size/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
|
||||
|
||||
/* Setup the basic block pool fields. */
|
||||
pool_ptr -> tx_block_pool_name = name_ptr;
|
||||
pool_ptr -> tx_block_pool_start = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
pool_ptr -> tx_block_pool_size = pool_size;
|
||||
pool_ptr -> tx_block_pool_block_size = (UINT) block_size;
|
||||
|
||||
/* Calculate the total number of blocks. */
|
||||
total_blocks = pool_size/(block_size + (sizeof(UCHAR *)));
|
||||
|
||||
/* Walk through the pool area, setting up the available block list. */
|
||||
blocks = ((UINT) 0);
|
||||
block_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
next_block_ptr = TX_UCHAR_POINTER_ADD(block_ptr, (block_size + (sizeof(UCHAR *))));
|
||||
while(blocks < (UINT) total_blocks)
|
||||
{
|
||||
|
||||
/* Yes, we have another block. Increment the block count. */
|
||||
blocks++;
|
||||
|
||||
/* Setup the link to the next block. */
|
||||
block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*block_link_ptr = next_block_ptr;
|
||||
|
||||
/* Advance to the next block. */
|
||||
block_ptr = next_block_ptr;
|
||||
|
||||
/* Update the next block pointer. */
|
||||
next_block_ptr = TX_UCHAR_POINTER_ADD(block_ptr, (block_size + (sizeof(UCHAR *))));
|
||||
}
|
||||
|
||||
/* Save the remaining information in the pool control block. */
|
||||
pool_ptr -> tx_block_pool_available = blocks;
|
||||
pool_ptr -> tx_block_pool_total = blocks;
|
||||
|
||||
/* Quickly check to make sure at least one block is in the pool. */
|
||||
if (blocks != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Backup to the last block in the pool. */
|
||||
block_ptr = TX_UCHAR_POINTER_SUB(block_ptr,(block_size + (sizeof(UCHAR *))));
|
||||
|
||||
/* Set the last block's forward pointer to NULL. */
|
||||
block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*block_link_ptr = TX_NULL;
|
||||
|
||||
/* Setup the starting pool address. */
|
||||
pool_ptr -> tx_block_pool_available_list = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
|
||||
/* Disable interrupts to place the block pool on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Setup the block pool ID to make it valid. */
|
||||
pool_ptr -> tx_block_pool_id = TX_BLOCK_POOL_ID;
|
||||
|
||||
/* Place the block pool on the list of created block pools. First,
|
||||
check for an empty list. */
|
||||
if (_tx_block_pool_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created block pool list is empty. Add block pool to empty list. */
|
||||
_tx_block_pool_created_ptr = pool_ptr;
|
||||
pool_ptr -> tx_block_pool_created_next = pool_ptr;
|
||||
pool_ptr -> tx_block_pool_created_previous = pool_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_pool = _tx_block_pool_created_ptr;
|
||||
previous_pool = next_pool -> tx_block_pool_created_previous;
|
||||
|
||||
/* Place the new block pool in the list. */
|
||||
next_pool -> tx_block_pool_created_previous = pool_ptr;
|
||||
previous_pool -> tx_block_pool_created_next = pool_ptr;
|
||||
|
||||
/* Setup this block pool's created links. */
|
||||
pool_ptr -> tx_block_pool_created_previous = previous_pool;
|
||||
pool_ptr -> tx_block_pool_created_next = next_pool;
|
||||
}
|
||||
|
||||
/* Increment the created count. */
|
||||
_tx_block_pool_created_count++;
|
||||
|
||||
/* Optional block pool create extended processing. */
|
||||
TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr)
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_BLOCK_POOL, pool_ptr, name_ptr, pool_size, block_size)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_CREATE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(pool_start), blocks, block_size, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_POOL_CREATE_INSERT
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enough memory for one block, return appropriate error. */
|
||||
status = TX_SIZE_ERROR;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
207
common_smp/src/tx_block_pool_delete.c
Normal file
207
common_smp/src/tx_block_pool_delete.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function deletes the specified block pool. All threads */
|
||||
/* suspended on the block pool are resumed with the TX_DELETED status */
|
||||
/* code. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_pool_delete(TX_BLOCK_POOL *pool_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
UINT suspended_count;
|
||||
TX_BLOCK_POOL *next_pool;
|
||||
TX_BLOCK_POOL *previous_pool;
|
||||
|
||||
|
||||
/* Disable interrupts to remove the block pool from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_DELETE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_POOL_DELETE_INSERT
|
||||
|
||||
/* Optional block pool delete extended processing. */
|
||||
TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(pool_ptr)
|
||||
|
||||
/* Clear the block pool ID to make it invalid. */
|
||||
pool_ptr -> tx_block_pool_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the number of block pools. */
|
||||
_tx_block_pool_created_count--;
|
||||
|
||||
/* See if the block pool is the only one on the list. */
|
||||
if (_tx_block_pool_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created block pool, just set the created list to NULL. */
|
||||
_tx_block_pool_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_pool = pool_ptr -> tx_block_pool_created_next;
|
||||
previous_pool = pool_ptr -> tx_block_pool_created_previous;
|
||||
next_pool -> tx_block_pool_created_previous = previous_pool;
|
||||
previous_pool -> tx_block_pool_created_next = next_pool;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_block_pool_created_ptr == pool_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_block_pool_created_ptr = next_pool;
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Pickup the suspension information. */
|
||||
thread_ptr = pool_ptr -> tx_block_pool_suspension_list;
|
||||
pool_ptr -> tx_block_pool_suspension_list = TX_NULL;
|
||||
suspended_count = pool_ptr -> tx_block_pool_suspended_count;
|
||||
pool_ptr -> tx_block_pool_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the block pool suspension list to resume any and all threads suspended
|
||||
on this block pool. */
|
||||
while (suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_DELETED. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_DELETED;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move to next thread. */
|
||||
thread_ptr = next_thread;
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_BLOCK_POOL_DELETE_PORT_COMPLETION(pool_ptr)
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release previous preempt disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
146
common_smp/src/tx_block_pool_info_get.c
Normal file
146
common_smp/src/tx_block_pool_info_get.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified block pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to block pool control blk */
|
||||
/* name Destination for the pool name */
|
||||
/* available_blocks Number of free blocks in pool */
|
||||
/* total_blocks Total number of blocks in pool */
|
||||
/* first_suspended Destination for pointer of first */
|
||||
/* thread suspended on block pool */
|
||||
/* suspended_count Destination for suspended count */
|
||||
/* next_pool Destination for pointer to next */
|
||||
/* block pool on the created list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_pool_info_get(TX_BLOCK_POOL *pool_ptr, CHAR **name, ULONG *available_blocks,
|
||||
ULONG *total_blocks, TX_THREAD **first_suspended,
|
||||
ULONG *suspended_count, TX_BLOCK_POOL **next_pool)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_INFO_GET, pool_ptr, 0, 0, 0, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_POOL_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the block pool. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = pool_ptr -> tx_block_pool_name;
|
||||
}
|
||||
|
||||
/* Retrieve the number of available blocks in the block pool. */
|
||||
if (available_blocks != TX_NULL)
|
||||
{
|
||||
|
||||
*available_blocks = (ULONG) pool_ptr -> tx_block_pool_available;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of blocks in the block pool. */
|
||||
if (total_blocks != TX_NULL)
|
||||
{
|
||||
|
||||
*total_blocks = (ULONG) pool_ptr -> tx_block_pool_total;
|
||||
}
|
||||
|
||||
/* Retrieve the first thread suspended on this block pool. */
|
||||
if (first_suspended != TX_NULL)
|
||||
{
|
||||
|
||||
*first_suspended = pool_ptr -> tx_block_pool_suspension_list;
|
||||
}
|
||||
|
||||
/* Retrieve the number of threads suspended on this block pool. */
|
||||
if (suspended_count != TX_NULL)
|
||||
{
|
||||
|
||||
*suspended_count = (ULONG) pool_ptr -> tx_block_pool_suspended_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to the next block pool created. */
|
||||
if (next_pool != TX_NULL)
|
||||
{
|
||||
|
||||
*next_pool = pool_ptr -> tx_block_pool_created_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
129
common_smp/src/tx_block_pool_initialize.c
Normal file
129
common_smp/src/tx_block_pool_initialize.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
#ifndef TX_INLINE_INITIALIZATION
|
||||
|
||||
/* Locate block pool component data in this file. */
|
||||
|
||||
/* Define the head pointer of the created block pool list. */
|
||||
|
||||
TX_BLOCK_POOL * _tx_block_pool_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created block pools. */
|
||||
|
||||
ULONG _tx_block_pool_created_count;
|
||||
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of block allocates. */
|
||||
|
||||
ULONG _tx_block_pool_performance_allocate_count;
|
||||
|
||||
|
||||
/* Define the total number of block releases. */
|
||||
|
||||
ULONG _tx_block_pool_performance_release_count;
|
||||
|
||||
|
||||
/* Define the total number of block pool suspensions. */
|
||||
|
||||
ULONG _tx_block_pool_performance_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of block pool timeouts. */
|
||||
|
||||
ULONG _tx_block_pool_performance_timeout_count;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block pool_initialize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the block pool component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_block_pool_initialize(VOID)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the head pointer of the created block pools list and the
|
||||
number of block pools created. */
|
||||
_tx_block_pool_created_ptr = TX_NULL;
|
||||
_tx_block_pool_created_count = TX_EMPTY;
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize block pool performance counters. */
|
||||
_tx_block_pool_performance_allocate_count = ((ULONG) 0);
|
||||
_tx_block_pool_performance_release_count = ((ULONG) 0);
|
||||
_tx_block_pool_performance_suspension_count = ((ULONG) 0);
|
||||
_tx_block_pool_performance_timeout_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
201
common_smp/src/tx_block_pool_performance_info_get.c
Normal file
201
common_smp/src/tx_block_pool_performance_info_get.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_block_pool.h"
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* block pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to block pool control blk */
|
||||
/* allocates Destination for the number of */
|
||||
/* allocations from this pool */
|
||||
/* releases Destination for the number of */
|
||||
/* blocks released back to pool */
|
||||
/* suspensions Destination for number of */
|
||||
/* suspensions on this pool */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* on this pool */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_pool_performance_info_get(TX_BLOCK_POOL *pool_ptr, ULONG *allocates, ULONG *releases,
|
||||
ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (pool_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Block pool pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the pool ID is invalid. */
|
||||
else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID)
|
||||
{
|
||||
|
||||
/* Block pool pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_PERFORMANCE_INFO_GET, pool_ptr, 0, 0, 0, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the number of allocations from this block pool. */
|
||||
if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
*allocates = pool_ptr -> tx_block_pool_performance_allocate_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of blocks released to this block pool. */
|
||||
if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
*releases = pool_ptr -> tx_block_pool_performance_release_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of thread suspensions on this block pool. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = pool_ptr -> tx_block_pool_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of thread timeouts on this block pool. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = pool_ptr -> tx_block_pool_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return successful completion. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
#else
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (pool_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
173
common_smp/src/tx_block_pool_performance_system_info_get.c
Normal file
173
common_smp/src/tx_block_pool_performance_system_info_get.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_block_pool.h"
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves block pool performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* allocates Destination for the total number */
|
||||
/* of block allocations */
|
||||
/* releases Destination for the total number */
|
||||
/* of blocks released */
|
||||
/* suspensions Destination for the total number */
|
||||
/* of suspensions */
|
||||
/* timeouts Destination for total number of */
|
||||
/* timeouts */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_pool_performance_system_info_get(ULONG *allocates, ULONG *releases, ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the total number of block allocations. */
|
||||
if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
*allocates = _tx_block_pool_performance_allocate_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of blocks released. */
|
||||
if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
*releases = _tx_block_pool_performance_release_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of block pool thread suspensions. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = _tx_block_pool_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of block pool thread timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_block_pool_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
249
common_smp/src/tx_block_pool_prioritize.c
Normal file
249
common_smp/src/tx_block_pool_prioritize.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_pool_prioritize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places the highest priority suspended thread at the */
|
||||
/* front of the suspension list. All other threads remain in the same */
|
||||
/* FIFO suspension order. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_pool_prioritize(TX_BLOCK_POOL *pool_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *priority_thread_ptr;
|
||||
TX_THREAD *head_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT list_changed;
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_PRIORITIZE, pool_ptr, pool_ptr -> tx_block_pool_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_POOL_PRIORITIZE_INSERT
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = pool_ptr -> tx_block_pool_suspended_count;
|
||||
|
||||
/* Determine if there are fewer than 2 suspended threads. */
|
||||
if (suspended_count < ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Determine if there how many threads are suspended on this block memory pool. */
|
||||
else if (suspended_count == ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Pickup the head pointer and the next pointer. */
|
||||
head_ptr = pool_ptr -> tx_block_pool_suspension_list;
|
||||
next_thread = head_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Determine if the next suspended thread has a higher priority. */
|
||||
if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
|
||||
{
|
||||
|
||||
/* Yes, move the list head to the next thread. */
|
||||
pool_ptr -> tx_block_pool_suspension_list = next_thread;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = pool_ptr -> tx_block_pool_suspension_list;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the list changed flag to false. */
|
||||
list_changed = TX_FALSE;
|
||||
|
||||
/* Search through the list to find the highest priority thread. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Is the current thread higher priority? */
|
||||
if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, remember that this thread is the highest priority. */
|
||||
priority_thread_ptr = thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if any changes to the list have occurred while
|
||||
interrupts were enabled. */
|
||||
|
||||
/* Is the list head the same? */
|
||||
if (head_ptr != pool_ptr -> tx_block_pool_suspension_list)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is the suspended count the same? */
|
||||
if (suspended_count != pool_ptr -> tx_block_pool_suspended_count)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the list has changed. */
|
||||
if (list_changed == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Move the thread pointer to the next thread. */
|
||||
thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = pool_ptr -> tx_block_pool_suspension_list;
|
||||
suspended_count = pool_ptr -> tx_block_pool_suspended_count;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Reset the list changed flag. */
|
||||
list_changed = TX_FALSE;
|
||||
}
|
||||
|
||||
} while (thread_ptr != head_ptr);
|
||||
|
||||
/* Release preemption. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Now determine if the highest priority thread is at the front
|
||||
of the list. */
|
||||
if (priority_thread_ptr != head_ptr)
|
||||
{
|
||||
|
||||
/* No, we need to move the highest priority suspended thread to the
|
||||
front of the list. */
|
||||
|
||||
/* First, remove the highest priority thread by updating the
|
||||
adjacent suspended threads. */
|
||||
next_thread = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = priority_thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Now, link the highest priority thread at the front of the list. */
|
||||
previous_thread = head_ptr -> tx_thread_suspended_previous;
|
||||
priority_thread_ptr -> tx_thread_suspended_next = head_ptr;
|
||||
priority_thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = priority_thread_ptr;
|
||||
head_ptr -> tx_thread_suspended_previous = priority_thread_ptr;
|
||||
|
||||
/* Move the list head pointer to the highest priority suspended thread. */
|
||||
pool_ptr -> tx_block_pool_suspension_list = priority_thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
|
||||
/* Return successful status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
204
common_smp/src/tx_block_release.c
Normal file
204
common_smp/src/tx_block_release.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Block Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_block_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_block_release PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function returns a previously allocated block to its */
|
||||
/* associated memory block pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* block_ptr Pointer to memory block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_block_release(VOID *block_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_BLOCK_POOL *pool_ptr;
|
||||
TX_THREAD *thread_ptr;
|
||||
UCHAR *work_ptr;
|
||||
UCHAR **return_block_ptr;
|
||||
UCHAR **next_block_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
/* Disable interrupts to put this block back in the pool. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup the pool pointer which is just previous to the starting
|
||||
address of the block that the caller sees. */
|
||||
work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
work_ptr = TX_UCHAR_POINTER_SUB(work_ptr, (sizeof(UCHAR *)));
|
||||
next_block_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
|
||||
pool_ptr = TX_UCHAR_TO_BLOCK_POOL_POINTER_CONVERT((*next_block_ptr));
|
||||
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total releases counter. */
|
||||
_tx_block_pool_performance_release_count++;
|
||||
|
||||
/* Increment the number of releases on this pool. */
|
||||
pool_ptr -> tx_block_pool_performance_release_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_RELEASE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(block_ptr), pool_ptr -> tx_block_pool_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&work_ptr), TX_TRACE_BLOCK_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BLOCK_RELEASE_INSERT
|
||||
|
||||
/* Determine if there are any threads suspended on the block pool. */
|
||||
thread_ptr = pool_ptr -> tx_block_pool_suspension_list;
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* Decrement the number of threads suspended. */
|
||||
(pool_ptr -> tx_block_pool_suspended_count)--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = (pool_ptr -> tx_block_pool_suspended_count);
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
pool_ptr -> tx_block_pool_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
pool_ptr -> tx_block_pool_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Return this block pointer to the suspended thread waiting for
|
||||
a block. */
|
||||
return_block_ptr = TX_VOID_TO_INDIRECT_UCHAR_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*return_block_ptr = work_ptr;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No thread is suspended for a memory block. */
|
||||
|
||||
/* Put the block back in the available list. */
|
||||
*next_block_ptr = pool_ptr -> tx_block_pool_available_list;
|
||||
|
||||
/* Adjust the head pointer. */
|
||||
pool_ptr -> tx_block_pool_available_list = work_ptr;
|
||||
|
||||
/* Increment the count of available blocks. */
|
||||
pool_ptr -> tx_block_pool_available++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Return successful completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
409
common_smp/src/tx_byte_allocate.c
Normal file
409
common_smp/src/tx_byte_allocate.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
#include "tx_thread.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_allocate PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function allocates bytes from the specified memory byte */
|
||||
/* pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* memory_ptr Pointer to place allocated bytes */
|
||||
/* pointer */
|
||||
/* memory_size Number of bytes to allocate */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Suspend thread service */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* _tx_byte_pool_search Search byte pool for memory */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, ULONG memory_size, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
TX_THREAD *thread_ptr;
|
||||
UCHAR *work_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT finished;
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
TX_TRACE_BUFFER_ENTRY *entry_ptr;
|
||||
ULONG time_stamp = ((ULONG) 0);
|
||||
#endif
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
UCHAR *log_entry_ptr;
|
||||
ULONG upper_tbu;
|
||||
ULONG lower_tbu;
|
||||
#endif
|
||||
|
||||
|
||||
/* Round the memory size up to the next size that is evenly divisible by
|
||||
an ALIGN_TYPE (this is typically a 32-bit ULONG). This guarantees proper alignment. */
|
||||
memory_size = (((memory_size + (sizeof(ALIGN_TYPE)))-((ALIGN_TYPE) 1))/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total allocations counter. */
|
||||
_tx_byte_pool_performance_allocate_count++;
|
||||
|
||||
/* Increment the number of allocations on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_allocate_count++;
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* If trace is enabled, save the current event pointer. */
|
||||
entry_ptr = _tx_trace_buffer_current_ptr;
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_ALLOCATE, pool_ptr, 0, memory_size, wait_option, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Save the time stamp for later comparison to verify that
|
||||
the event hasn't been overwritten by the time the allocate
|
||||
call succeeds. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
time_stamp = entry_ptr -> tx_trace_buffer_entry_time_stamp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
log_entry_ptr = *(UCHAR **) _tx_el_current_event;
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_ALLOCATE_INSERT
|
||||
|
||||
/* Store -1 in the fourth event slot. */
|
||||
*((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = (ULONG) -1;
|
||||
|
||||
/* Save the time stamp for later comparison to verify that
|
||||
the event hasn't been overwritten by the time the allocate
|
||||
call succeeds. */
|
||||
lower_tbu = *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET));
|
||||
upper_tbu = *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET));
|
||||
#endif
|
||||
|
||||
/* Set the search finished flag to false. */
|
||||
finished = TX_FALSE;
|
||||
|
||||
/* Loop to handle cases where the owner of the pool changed. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Indicate that this thread is the current owner. */
|
||||
pool_ptr -> tx_byte_pool_owner = thread_ptr;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* At this point, the executing thread owns the pool and can perform a search
|
||||
for free memory. */
|
||||
work_ptr = _tx_byte_pool_search(pool_ptr, memory_size);
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_BYTE_ALLOCATE_EXTENSION
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if we are finished. */
|
||||
if (work_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, we have found a block the search is finished. */
|
||||
finished = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No block was found, does this thread still own the pool? */
|
||||
if (pool_ptr -> tx_byte_pool_owner == thread_ptr)
|
||||
{
|
||||
|
||||
/* Yes, then we have looked through the entire pool and haven't found the memory. */
|
||||
finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
} while (finished == TX_FALSE);
|
||||
|
||||
/* Copy the pointer into the return destination. */
|
||||
*memory_ptr = (VOID *) work_ptr;
|
||||
|
||||
/* Determine if memory was found. */
|
||||
if (work_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the byte
|
||||
allocate event. In that case, do nothing here. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Is the timestamp the same? */
|
||||
if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
|
||||
{
|
||||
|
||||
/* Timestamp is the same, update the entry with the address. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
entry_ptr -> tx_trace_buffer_entry_info_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
|
||||
#else
|
||||
entry_ptr -> tx_trace_buffer_entry_information_field_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the byte
|
||||
allocate event. In that case, do nothing here. */
|
||||
if (lower_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) &&
|
||||
upper_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)))
|
||||
{
|
||||
/* Store the address of the allocated fragment. */
|
||||
*((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = (ULONG) *memory_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Set the status to success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No memory of sufficient size was found... */
|
||||
|
||||
/* Determine if the request specifies suspension. */
|
||||
if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_NO_MEMORY;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total suspensions counter. */
|
||||
_tx_byte_pool_performance_suspension_count++;
|
||||
|
||||
/* Increment the number of suspensions on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_suspension_count++;
|
||||
#endif
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_byte_pool_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this pool control
|
||||
block. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) pool_ptr;
|
||||
|
||||
/* Save the return memory pointer address as well. */
|
||||
thread_ptr -> tx_thread_additional_suspend_info = (VOID *) memory_ptr;
|
||||
|
||||
/* Save the byte size requested. */
|
||||
thread_ptr -> tx_thread_suspend_info = memory_size;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Pickup the number of suspended threads. */
|
||||
suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
|
||||
|
||||
/* Increment the suspension count. */
|
||||
(pool_ptr -> tx_byte_pool_suspended_count)++;
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
pool_ptr -> tx_byte_pool_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_BYTE_MEMORY;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the byte
|
||||
allocate event. In that case, do nothing here. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Is the timestamp the same? */
|
||||
if (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp)
|
||||
{
|
||||
|
||||
/* Timestamp is the same, update the entry with the address. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
entry_ptr -> tx_trace_buffer_entry_info_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
|
||||
#else
|
||||
entry_ptr -> tx_trace_buffer_entry_information_field_2 = TX_POINTER_TO_ULONG_CONVERT(*memory_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_LOGGING
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the byte
|
||||
allocate event. In that case, do nothing here. */
|
||||
if (lower_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) &&
|
||||
upper_tbu == *((ULONG *) (log_entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)))
|
||||
{
|
||||
|
||||
/* Store the address of the allocated fragment. */
|
||||
*((ULONG *) (log_entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = (ULONG) *memory_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Immediate return, return error completion. */
|
||||
status = TX_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
212
common_smp/src/tx_byte_pool_cleanup.c
Normal file
212
common_smp/src/tx_byte_pool_cleanup.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_cleanup PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes byte allocate timeout and thread terminate */
|
||||
/* actions that require the byte pool data structures to be cleaned */
|
||||
/* up. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to suspended thread's */
|
||||
/* control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_timeout Thread timeout processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* _tx_thread_wait_abort Thread wait abort processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_byte_pool_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_BYTE_POOL *pool_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts to remove the suspended thread from the byte pool. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the cleanup is still required. */
|
||||
if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_byte_pool_cleanup))
|
||||
{
|
||||
|
||||
/* Check for valid suspension sequence. */
|
||||
if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
|
||||
{
|
||||
|
||||
/* Setup pointer to byte pool control block. */
|
||||
pool_ptr = TX_VOID_TO_BYTE_POOL_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
|
||||
/* Check for a NULL byte pool pointer. */
|
||||
if (pool_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Check for valid pool ID. */
|
||||
if (pool_ptr -> tx_byte_pool_id == TX_BYTE_POOL_ID)
|
||||
{
|
||||
|
||||
/* Determine if there are any thread suspensions. */
|
||||
if (pool_ptr -> tx_byte_pool_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
#else
|
||||
|
||||
/* Setup pointer to byte pool control block. */
|
||||
pool_ptr = TX_VOID_TO_BYTE_POOL_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
#endif
|
||||
|
||||
/* Thread suspended for memory... Clear the suspension cleanup flag. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
pool_ptr -> tx_byte_pool_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
pool_ptr -> tx_byte_pool_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same suspension list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Determine if we need to update the head pointer. */
|
||||
if (pool_ptr -> tx_byte_pool_suspension_list == thread_ptr)
|
||||
{
|
||||
|
||||
/* Update the list head pointer. */
|
||||
pool_ptr -> tx_byte_pool_suspension_list = next_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we need to determine if this cleanup is from a terminate, timeout,
|
||||
or from a wait abort. */
|
||||
if (thread_ptr -> tx_thread_state == TX_BYTE_MEMORY)
|
||||
{
|
||||
|
||||
/* Timeout condition and the thread still suspended on the byte pool.
|
||||
Setup return error status and resume the thread. */
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total timeouts counter. */
|
||||
_tx_byte_pool_performance_timeout_count++;
|
||||
|
||||
/* Increment the number of timeouts on this byte pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_timeout_count++;
|
||||
#endif
|
||||
|
||||
/* Setup return status. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_NO_MEMORY;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
197
common_smp/src/tx_byte_pool_create.c
Normal file
197
common_smp/src/tx_byte_pool_create.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_create PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a pool of memory bytes in the specified */
|
||||
/* memory area. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* name_ptr Pointer to byte pool name */
|
||||
/* pool_start Address of beginning of pool area */
|
||||
/* pool_size Number of bytes in the byte pool */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start, ULONG pool_size)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UCHAR *block_ptr;
|
||||
UCHAR **block_indirect_ptr;
|
||||
UCHAR *temp_ptr;
|
||||
TX_BYTE_POOL *next_pool;
|
||||
TX_BYTE_POOL *previous_pool;
|
||||
ALIGN_TYPE *free_ptr;
|
||||
|
||||
|
||||
/* Initialize the byte pool control block to all zeros. */
|
||||
TX_MEMSET(pool_ptr, 0, (sizeof(TX_BYTE_POOL)));
|
||||
|
||||
/* Round the pool size down to something that is evenly divisible by
|
||||
an ULONG. */
|
||||
pool_size = (pool_size/(sizeof(ALIGN_TYPE))) * (sizeof(ALIGN_TYPE));
|
||||
|
||||
/* Setup the basic byte pool fields. */
|
||||
pool_ptr -> tx_byte_pool_name = name_ptr;
|
||||
|
||||
/* Save the start and size of the pool. */
|
||||
pool_ptr -> tx_byte_pool_start = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
pool_ptr -> tx_byte_pool_size = pool_size;
|
||||
|
||||
/* Setup memory list to the beginning as well as the search pointer. */
|
||||
pool_ptr -> tx_byte_pool_list = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
pool_ptr -> tx_byte_pool_search = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
|
||||
/* Initially, the pool will have two blocks. One large block at the
|
||||
beginning that is available and a small allocated block at the end
|
||||
of the pool that is there just for the algorithm. Be sure to count
|
||||
the available block's header in the available bytes count. */
|
||||
pool_ptr -> tx_byte_pool_available = pool_size - ((sizeof(VOID *)) + (sizeof(ALIGN_TYPE)));
|
||||
pool_ptr -> tx_byte_pool_fragments = ((UINT) 2);
|
||||
|
||||
/* Each block contains a "next" pointer that points to the next block in the pool followed by a ALIGN_TYPE
|
||||
field that contains either the constant TX_BYTE_BLOCK_FREE (if the block is free) or a pointer to the
|
||||
owning pool (if the block is allocated). */
|
||||
|
||||
/* Calculate the end of the pool's memory area. */
|
||||
block_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
block_ptr = TX_UCHAR_POINTER_ADD(block_ptr, pool_size);
|
||||
|
||||
/* Backup the end of the pool pointer and build the pre-allocated block. */
|
||||
block_ptr = TX_UCHAR_POINTER_SUB(block_ptr, (sizeof(ALIGN_TYPE)));
|
||||
|
||||
/* Cast the pool pointer into a ULONG. */
|
||||
temp_ptr = TX_BYTE_POOL_TO_UCHAR_POINTER_CONVERT(pool_ptr);
|
||||
block_indirect_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*block_indirect_ptr = temp_ptr;
|
||||
|
||||
block_ptr = TX_UCHAR_POINTER_SUB(block_ptr, (sizeof(UCHAR *)));
|
||||
block_indirect_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(block_ptr);
|
||||
*block_indirect_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
|
||||
/* Now setup the large available block in the pool. */
|
||||
temp_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
block_indirect_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(temp_ptr);
|
||||
*block_indirect_ptr = block_ptr;
|
||||
block_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(pool_start);
|
||||
block_ptr = TX_UCHAR_POINTER_ADD(block_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(block_ptr);
|
||||
*free_ptr = TX_BYTE_BLOCK_FREE;
|
||||
|
||||
/* Clear the owner id. */
|
||||
pool_ptr -> tx_byte_pool_owner = TX_NULL;
|
||||
|
||||
/* Disable interrupts to place the byte pool on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Setup the byte pool ID to make it valid. */
|
||||
pool_ptr -> tx_byte_pool_id = TX_BYTE_POOL_ID;
|
||||
|
||||
/* Place the byte pool on the list of created byte pools. First,
|
||||
check for an empty list. */
|
||||
if (_tx_byte_pool_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created byte pool list is empty. Add byte pool to empty list. */
|
||||
_tx_byte_pool_created_ptr = pool_ptr;
|
||||
pool_ptr -> tx_byte_pool_created_next = pool_ptr;
|
||||
pool_ptr -> tx_byte_pool_created_previous = pool_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_pool = _tx_byte_pool_created_ptr;
|
||||
previous_pool = next_pool -> tx_byte_pool_created_previous;
|
||||
|
||||
/* Place the new byte pool in the list. */
|
||||
next_pool -> tx_byte_pool_created_previous = pool_ptr;
|
||||
previous_pool -> tx_byte_pool_created_next = pool_ptr;
|
||||
|
||||
/* Setup this byte pool's created links. */
|
||||
pool_ptr -> tx_byte_pool_created_previous = previous_pool;
|
||||
pool_ptr -> tx_byte_pool_created_next = next_pool;
|
||||
}
|
||||
|
||||
/* Increment the number of created byte pools. */
|
||||
_tx_byte_pool_created_count++;
|
||||
|
||||
/* Optional byte pool create extended processing. */
|
||||
TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr)
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_BYTE_POOL, pool_ptr, name_ptr, pool_size, 0)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL_CREATE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(pool_start), pool_size, TX_POINTER_TO_ULONG_CONVERT(&block_ptr), TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_POOL_CREATE_INSERT
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
211
common_smp/src/tx_byte_pool_delete.c
Normal file
211
common_smp/src/tx_byte_pool_delete.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function deletes the specified byte pool. All threads */
|
||||
/* suspended on the byte pool are resumed with the TX_DELETED status */
|
||||
/* code. */
|
||||
/* */
|
||||
/* It is important to note that the byte pool being deleted, or the */
|
||||
/* memory associated with it should not be in use when this function */
|
||||
/* is called. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_pool_delete(TX_BYTE_POOL *pool_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
UINT suspended_count;
|
||||
TX_BYTE_POOL *next_pool;
|
||||
TX_BYTE_POOL *previous_pool;
|
||||
|
||||
|
||||
/* Disable interrupts to remove the byte pool from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL_DELETE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Optional byte pool delete extended processing. */
|
||||
TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(pool_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_POOL_DELETE_INSERT
|
||||
|
||||
/* Clear the byte pool ID to make it invalid. */
|
||||
pool_ptr -> tx_byte_pool_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the number of byte pools created. */
|
||||
_tx_byte_pool_created_count--;
|
||||
|
||||
/* See if the byte pool is the only one on the list. */
|
||||
if (_tx_byte_pool_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created byte pool, just set the created list to NULL. */
|
||||
_tx_byte_pool_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_pool = pool_ptr -> tx_byte_pool_created_next;
|
||||
previous_pool = pool_ptr -> tx_byte_pool_created_previous;
|
||||
next_pool -> tx_byte_pool_created_previous = previous_pool;
|
||||
previous_pool -> tx_byte_pool_created_next = next_pool;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_byte_pool_created_ptr == pool_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_byte_pool_created_ptr = next_pool;
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Pickup the suspension information. */
|
||||
thread_ptr = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
pool_ptr -> tx_byte_pool_suspension_list = TX_NULL;
|
||||
suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
|
||||
pool_ptr -> tx_byte_pool_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the byte pool list to resume any and all threads suspended
|
||||
on this byte pool. */
|
||||
while (suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_DELETED. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_DELETED;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move to next thread. */
|
||||
thread_ptr = next_thread;
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_BYTE_POOL_DELETE_PORT_COMPLETION(pool_ptr)
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release previous preempt disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
146
common_smp/src/tx_byte_pool_info_get.c
Normal file
146
common_smp/src/tx_byte_pool_info_get.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified byte pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to byte pool control block*/
|
||||
/* name Destination for the pool name */
|
||||
/* available_bytes Number of free bytes in byte pool */
|
||||
/* fragments Number of fragments in byte pool */
|
||||
/* first_suspended Destination for pointer of first */
|
||||
/* thread suspended on byte pool */
|
||||
/* suspended_count Destination for suspended count */
|
||||
/* next_pool Destination for pointer to next */
|
||||
/* byte pool on the created list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_pool_info_get(TX_BYTE_POOL *pool_ptr, CHAR **name, ULONG *available_bytes,
|
||||
ULONG *fragments, TX_THREAD **first_suspended,
|
||||
ULONG *suspended_count, TX_BYTE_POOL **next_pool)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL_INFO_GET, pool_ptr, 0, 0, 0, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_POOL_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the byte pool. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = pool_ptr -> tx_byte_pool_name;
|
||||
}
|
||||
|
||||
/* Retrieve the number of available bytes in the byte pool. */
|
||||
if (available_bytes != TX_NULL)
|
||||
{
|
||||
|
||||
*available_bytes = pool_ptr -> tx_byte_pool_available;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of bytes in the byte pool. */
|
||||
if (fragments != TX_NULL)
|
||||
{
|
||||
|
||||
*fragments = (ULONG) pool_ptr -> tx_byte_pool_fragments;
|
||||
}
|
||||
|
||||
/* Retrieve the first thread suspended on this byte pool. */
|
||||
if (first_suspended != TX_NULL)
|
||||
{
|
||||
|
||||
*first_suspended = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
}
|
||||
|
||||
/* Retrieve the number of threads suspended on this byte pool. */
|
||||
if (suspended_count != TX_NULL)
|
||||
{
|
||||
|
||||
*suspended_count = (ULONG) pool_ptr -> tx_byte_pool_suspended_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to the next byte pool created. */
|
||||
if (next_pool != TX_NULL)
|
||||
{
|
||||
|
||||
*next_pool = pool_ptr -> tx_byte_pool_created_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
147
common_smp/src/tx_byte_pool_initialize.c
Normal file
147
common_smp/src/tx_byte_pool_initialize.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
#ifndef TX_INLINE_INITIALIZATION
|
||||
|
||||
/* Locate byte pool component data in this file. */
|
||||
|
||||
/* Define the head pointer of the created byte pool list. */
|
||||
|
||||
TX_BYTE_POOL * _tx_byte_pool_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created byte pools. */
|
||||
|
||||
ULONG _tx_byte_pool_created_count;
|
||||
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of allocates. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_allocate_count;
|
||||
|
||||
|
||||
/* Define the total number of releases. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_release_count;
|
||||
|
||||
|
||||
/* Define the total number of adjacent memory fragment merges. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_merge_count;
|
||||
|
||||
|
||||
/* Define the total number of memory fragment splits. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_split_count;
|
||||
|
||||
|
||||
/* Define the total number of memory fragments searched during allocation. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_search_count;
|
||||
|
||||
|
||||
/* Define the total number of byte pool suspensions. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of byte pool timeouts. */
|
||||
|
||||
ULONG _tx_byte_pool_performance_timeout_count;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_initialize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the byte pool component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_byte_pool_initialize(VOID)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the head pointer of the created byte pools list and the
|
||||
number of byte pools created. */
|
||||
_tx_byte_pool_created_ptr = TX_NULL;
|
||||
_tx_byte_pool_created_count = TX_EMPTY;
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize byte pool performance counters. */
|
||||
_tx_byte_pool_performance_allocate_count = ((ULONG) 0);
|
||||
_tx_byte_pool_performance_release_count = ((ULONG) 0);
|
||||
_tx_byte_pool_performance_merge_count = ((ULONG) 0);
|
||||
_tx_byte_pool_performance_split_count = ((ULONG) 0);
|
||||
_tx_byte_pool_performance_search_count = ((ULONG) 0);
|
||||
_tx_byte_pool_performance_suspension_count = ((ULONG) 0);
|
||||
_tx_byte_pool_performance_timeout_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
253
common_smp/src/tx_byte_pool_performance_info_get.c
Normal file
253
common_smp/src/tx_byte_pool_performance_info_get.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_byte_pool.h"
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* byte pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to byte pool control block*/
|
||||
/* allocates Destination for number of */
|
||||
/* allocates on this pool */
|
||||
/* releases Destination for number of */
|
||||
/* releases on this pool */
|
||||
/* fragments_searched Destination for number of */
|
||||
/* fragments searched during */
|
||||
/* allocation */
|
||||
/* merges Destination for number of adjacent*/
|
||||
/* free fragments merged */
|
||||
/* splits Destination for number of */
|
||||
/* fragments split during */
|
||||
/* allocation */
|
||||
/* suspensions Destination for number of */
|
||||
/* suspensions on this pool */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* on this byte pool */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_pool_performance_info_get(TX_BYTE_POOL *pool_ptr, ULONG *allocates, ULONG *releases,
|
||||
ULONG *fragments_searched, ULONG *merges, ULONG *splits, ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (pool_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Byte pool pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the pool ID is invalid. */
|
||||
else if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID)
|
||||
{
|
||||
|
||||
/* Byte pool pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL_PERFORMANCE_INFO_GET, pool_ptr, 0, 0, 0, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the number of allocates on this byte pool. */
|
||||
if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
*allocates = pool_ptr -> tx_byte_pool_performance_allocate_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of releases on this byte pool. */
|
||||
if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
*releases = pool_ptr -> tx_byte_pool_performance_release_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of fragments searched in this byte pool. */
|
||||
if (fragments_searched != TX_NULL)
|
||||
{
|
||||
|
||||
*fragments_searched = pool_ptr -> tx_byte_pool_performance_search_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of fragments merged on this byte pool. */
|
||||
if (merges != TX_NULL)
|
||||
{
|
||||
|
||||
*merges = pool_ptr -> tx_byte_pool_performance_merge_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of fragment splits on this byte pool. */
|
||||
if (splits != TX_NULL)
|
||||
{
|
||||
|
||||
*splits = pool_ptr -> tx_byte_pool_performance_split_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of suspensions on this byte pool. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = pool_ptr -> tx_byte_pool_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of timeouts on this byte pool. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = pool_ptr -> tx_byte_pool_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (pool_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (fragments_searched != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (merges != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (splits != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
221
common_smp/src/tx_byte_pool_performance_system_info_get.c
Normal file
221
common_smp/src/tx_byte_pool_performance_system_info_get.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_byte_pool.h"
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves byte pool performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* allocates Destination for total number of */
|
||||
/* allocates */
|
||||
/* releases Destination for total number of */
|
||||
/* releases */
|
||||
/* fragments_searched Destination for total number of */
|
||||
/* fragments searched during */
|
||||
/* allocation */
|
||||
/* merges Destination for total number of */
|
||||
/* adjacent free fragments merged */
|
||||
/* splits Destination for total number of */
|
||||
/* fragments split during */
|
||||
/* allocation */
|
||||
/* suspensions Destination for total number of */
|
||||
/* suspensions */
|
||||
/* timeouts Destination for total number of */
|
||||
/* timeouts */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_pool_performance_system_info_get(ULONG *allocates, ULONG *releases,
|
||||
ULONG *fragments_searched, ULONG *merges, ULONG *splits, ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the total number of byte pool allocates. */
|
||||
if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
*allocates = _tx_byte_pool_performance_allocate_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of byte pool releases. */
|
||||
if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
*releases = _tx_byte_pool_performance_release_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of byte pool fragments searched. */
|
||||
if (fragments_searched != TX_NULL)
|
||||
{
|
||||
|
||||
*fragments_searched = _tx_byte_pool_performance_search_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of byte pool fragments merged. */
|
||||
if (merges != TX_NULL)
|
||||
{
|
||||
|
||||
*merges = _tx_byte_pool_performance_merge_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of byte pool fragment splits. */
|
||||
if (splits != TX_NULL)
|
||||
{
|
||||
|
||||
*splits = _tx_byte_pool_performance_split_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of byte pool suspensions. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = _tx_byte_pool_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of byte pool timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_byte_pool_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (allocates != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (releases != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (fragments_searched != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (merges != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (splits != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
249
common_smp/src/tx_byte_pool_prioritize.c
Normal file
249
common_smp/src/tx_byte_pool_prioritize.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_prioritize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places the highest priority suspended thread at the */
|
||||
/* front of the suspension list. All other threads remain in the same */
|
||||
/* FIFO suspension order. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_pool_prioritize(TX_BYTE_POOL *pool_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *priority_thread_ptr;
|
||||
TX_THREAD *head_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT list_changed;
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL_PRIORITIZE, pool_ptr, pool_ptr -> tx_byte_pool_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_POOL_PRIORITIZE_INSERT
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
|
||||
|
||||
/* Determine if there are fewer than 2 suspended threads. */
|
||||
if (suspended_count < ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Determine if there how many threads are suspended on this byte memory pool. */
|
||||
else if (suspended_count == ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Pickup the head pointer and the next pointer. */
|
||||
head_ptr = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
next_thread = head_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Determine if the next suspended thread has a higher priority. */
|
||||
if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
|
||||
{
|
||||
|
||||
/* Yes, move the list head to the next thread. */
|
||||
pool_ptr -> tx_byte_pool_suspension_list = next_thread;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the list changed flag to false. */
|
||||
list_changed = TX_FALSE;
|
||||
|
||||
/* Search through the list to find the highest priority thread. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Is the current thread higher priority? */
|
||||
if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, remember that this thread is the highest priority. */
|
||||
priority_thread_ptr = thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if any changes to the list have occurred while
|
||||
interrupts were enabled. */
|
||||
|
||||
/* Is the list head the same? */
|
||||
if (head_ptr != pool_ptr -> tx_byte_pool_suspension_list)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is the suspended count the same? */
|
||||
if (suspended_count != pool_ptr -> tx_byte_pool_suspended_count)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the list has changed. */
|
||||
if (list_changed == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Move the thread pointer to the next thread. */
|
||||
thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Reset the list changed flag. */
|
||||
list_changed = TX_FALSE;
|
||||
}
|
||||
|
||||
} while (thread_ptr != head_ptr);
|
||||
|
||||
/* Release preemption. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Now determine if the highest priority thread is at the front
|
||||
of the list. */
|
||||
if (priority_thread_ptr != head_ptr)
|
||||
{
|
||||
|
||||
/* No, we need to move the highest priority suspended thread to the
|
||||
front of the list. */
|
||||
|
||||
/* First, remove the highest priority thread by updating the
|
||||
adjacent suspended threads. */
|
||||
next_thread = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = priority_thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Now, link the highest priority thread at the front of the list. */
|
||||
previous_thread = head_ptr -> tx_thread_suspended_previous;
|
||||
priority_thread_ptr -> tx_thread_suspended_next = head_ptr;
|
||||
priority_thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = priority_thread_ptr;
|
||||
head_ptr -> tx_thread_suspended_previous = priority_thread_ptr;
|
||||
|
||||
/* Move the list head pointer to the highest priority suspended thread. */
|
||||
pool_ptr -> tx_byte_pool_suspension_list = priority_thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
378
common_smp/src/tx_byte_pool_search.c
Normal file
378
common_smp/src/tx_byte_pool_search.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Pool */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_pool_search PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function searches a byte pool for a memory block to satisfy */
|
||||
/* the requested number of bytes. Merging of adjacent free blocks */
|
||||
/* takes place during the search and a split of the block that */
|
||||
/* satisfies the request may occur before this function returns. */
|
||||
/* */
|
||||
/* It is assumed that this function is called with interrupts enabled */
|
||||
/* and with the tx_pool_owner field set to the thread performing the */
|
||||
/* search. Also note that the search can occur during allocation and */
|
||||
/* release of a memory block. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* pool_ptr Pointer to pool control block */
|
||||
/* memory_size Number of bytes required */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* UCHAR * Pointer to the allocated memory, */
|
||||
/* if successful. Otherwise, a */
|
||||
/* NULL is returned */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_byte_allocate Allocate bytes of memory */
|
||||
/* _tx_byte_release Release bytes of memory */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UCHAR *_tx_byte_pool_search(TX_BYTE_POOL *pool_ptr, ULONG memory_size)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UCHAR *current_ptr;
|
||||
UCHAR *next_ptr;
|
||||
UCHAR **this_block_link_ptr;
|
||||
UCHAR **next_block_link_ptr;
|
||||
ULONG available_bytes;
|
||||
UINT examine_blocks;
|
||||
UINT first_free_block_found = TX_FALSE;
|
||||
TX_THREAD *thread_ptr;
|
||||
ALIGN_TYPE *free_ptr;
|
||||
UCHAR *work_ptr;
|
||||
|
||||
#ifdef TX_BYTE_POOL_MULTIPLE_BLOCK_SEARCH
|
||||
UINT blocks_searched = ((UINT) 0);
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* First, determine if there are enough bytes in the pool. */
|
||||
if (memory_size >= pool_ptr -> tx_byte_pool_available)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Not enough memory, return a NULL pointer. */
|
||||
current_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup ownership of the byte pool. */
|
||||
pool_ptr -> tx_byte_pool_owner = thread_ptr;
|
||||
|
||||
/* Walk through the memory pool in search for a large enough block. */
|
||||
current_ptr = pool_ptr -> tx_byte_pool_search;
|
||||
examine_blocks = pool_ptr -> tx_byte_pool_fragments + ((UINT) 1);
|
||||
available_bytes = ((ULONG) 0);
|
||||
do
|
||||
{
|
||||
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total fragment search counter. */
|
||||
_tx_byte_pool_performance_search_count++;
|
||||
|
||||
/* Increment the number of fragments searched on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_search_count++;
|
||||
#endif
|
||||
|
||||
/* Check to see if this block is free. */
|
||||
work_ptr = TX_UCHAR_POINTER_ADD(current_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr);
|
||||
if ((*free_ptr) == TX_BYTE_BLOCK_FREE)
|
||||
{
|
||||
|
||||
/* Determine if this is the first free block. */
|
||||
if (first_free_block_found == TX_FALSE)
|
||||
{
|
||||
|
||||
/* This is the first free block. */
|
||||
pool_ptr->tx_byte_pool_search = current_ptr;
|
||||
|
||||
/* Set the flag to indicate we have found the first free
|
||||
block. */
|
||||
first_free_block_found = TX_TRUE;
|
||||
}
|
||||
|
||||
/* Block is free, see if it is large enough. */
|
||||
|
||||
/* Pickup the next block's pointer. */
|
||||
this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
|
||||
next_ptr = *this_block_link_ptr;
|
||||
|
||||
/* Calculate the number of bytes available in this block. */
|
||||
available_bytes = TX_UCHAR_POINTER_DIF(next_ptr, current_ptr);
|
||||
available_bytes = available_bytes - ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE)));
|
||||
|
||||
/* If this is large enough, we are done because our first-fit algorithm
|
||||
has been satisfied! */
|
||||
if (available_bytes >= memory_size)
|
||||
{
|
||||
|
||||
/* Get out of the search loop! */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Clear the available bytes variable. */
|
||||
available_bytes = ((ULONG) 0);
|
||||
|
||||
/* Not enough memory, check to see if the neighbor is
|
||||
free and can be merged. */
|
||||
work_ptr = TX_UCHAR_POINTER_ADD(next_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr);
|
||||
if ((*free_ptr) == TX_BYTE_BLOCK_FREE)
|
||||
{
|
||||
|
||||
/* Yes, neighbor block can be merged! This is quickly accomplished
|
||||
by updating the current block with the next blocks pointer. */
|
||||
next_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr);
|
||||
*this_block_link_ptr = *next_block_link_ptr;
|
||||
|
||||
/* Reduce the fragment total. We don't need to increase the bytes
|
||||
available because all free headers are also included in the available
|
||||
count. */
|
||||
pool_ptr -> tx_byte_pool_fragments--;
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total merge counter. */
|
||||
_tx_byte_pool_performance_merge_count++;
|
||||
|
||||
/* Increment the number of blocks merged on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_merge_count++;
|
||||
#endif
|
||||
|
||||
/* See if the search pointer is affected. */
|
||||
if (pool_ptr -> tx_byte_pool_search == next_ptr)
|
||||
{
|
||||
|
||||
/* Yes, update the search pointer. */
|
||||
pool_ptr -> tx_byte_pool_search = current_ptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Neighbor is not free so we can skip over it! */
|
||||
next_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr);
|
||||
current_ptr = *next_block_link_ptr;
|
||||
|
||||
/* Decrement the examined block count to account for this one. */
|
||||
if (examine_blocks != ((UINT) 0))
|
||||
{
|
||||
examine_blocks--;
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total fragment search counter. */
|
||||
_tx_byte_pool_performance_search_count++;
|
||||
|
||||
/* Increment the number of fragments searched on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_search_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Block is not free, move to next block. */
|
||||
this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
|
||||
current_ptr = *this_block_link_ptr;
|
||||
}
|
||||
|
||||
/* Another block has been searched... decrement counter. */
|
||||
if (examine_blocks != ((UINT) 0))
|
||||
{
|
||||
|
||||
examine_blocks--;
|
||||
}
|
||||
|
||||
#ifdef TX_BYTE_POOL_MULTIPLE_BLOCK_SEARCH
|
||||
|
||||
/* When this is enabled, multiple blocks are searched while holding the protection. */
|
||||
|
||||
/* Increment the number of blocks searched. */
|
||||
blocks_searched = blocks_searched + ((UINT) 1);
|
||||
|
||||
/* Have we reached the maximum number of blocks to search while holding the protection? */
|
||||
if (blocks_searched >= ((UINT) TX_BYTE_POOL_MULTIPLE_BLOCK_SEARCH))
|
||||
{
|
||||
|
||||
/* Yes, we have exceeded the multiple block search limit. */
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Reset the number of blocks searched counter. */
|
||||
blocks_searched = ((UINT) 0);
|
||||
}
|
||||
#else
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
/* Determine if anything has changed in terms of pool ownership. */
|
||||
if (pool_ptr -> tx_byte_pool_owner != thread_ptr)
|
||||
{
|
||||
|
||||
/* Pool changed ownership in the brief period interrupts were
|
||||
enabled. Reset the search. */
|
||||
current_ptr = pool_ptr -> tx_byte_pool_search;
|
||||
examine_blocks = pool_ptr -> tx_byte_pool_fragments + ((UINT) 1);
|
||||
|
||||
/* Setup our ownership again. */
|
||||
pool_ptr -> tx_byte_pool_owner = thread_ptr;
|
||||
}
|
||||
} while(examine_blocks != ((UINT) 0));
|
||||
|
||||
/* Determine if a block was found. If so, determine if it needs to be
|
||||
split. */
|
||||
if (available_bytes != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Determine if we need to split this block. */
|
||||
if ((available_bytes - memory_size) >= ((ULONG) TX_BYTE_BLOCK_MIN))
|
||||
{
|
||||
|
||||
/* Split the block. */
|
||||
next_ptr = TX_UCHAR_POINTER_ADD(current_ptr, (memory_size + ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE)))));
|
||||
|
||||
/* Setup the new free block. */
|
||||
next_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr);
|
||||
this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
|
||||
*next_block_link_ptr = *this_block_link_ptr;
|
||||
work_ptr = TX_UCHAR_POINTER_ADD(next_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr);
|
||||
*free_ptr = TX_BYTE_BLOCK_FREE;
|
||||
|
||||
/* Increase the total fragment counter. */
|
||||
pool_ptr -> tx_byte_pool_fragments++;
|
||||
|
||||
/* Update the current pointer to point at the newly created block. */
|
||||
*this_block_link_ptr = next_ptr;
|
||||
|
||||
/* Set available equal to memory size for subsequent calculation. */
|
||||
available_bytes = memory_size;
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total split counter. */
|
||||
_tx_byte_pool_performance_split_count++;
|
||||
|
||||
/* Increment the number of blocks split on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_split_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* In any case, mark the current block as allocated. */
|
||||
work_ptr = TX_UCHAR_POINTER_ADD(current_ptr, (sizeof(UCHAR *)));
|
||||
this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
|
||||
*this_block_link_ptr = TX_BYTE_POOL_TO_UCHAR_POINTER_CONVERT(pool_ptr);
|
||||
|
||||
/* Reduce the number of available bytes in the pool. */
|
||||
pool_ptr -> tx_byte_pool_available = (pool_ptr -> tx_byte_pool_available - available_bytes) - ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE)));
|
||||
|
||||
/* Determine if the search pointer needs to be updated. This is only done
|
||||
if the search pointer matches the block to be returned. */
|
||||
if (current_ptr == pool_ptr -> tx_byte_pool_search)
|
||||
{
|
||||
|
||||
/* Yes, update the search pointer to the next block. */
|
||||
this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
|
||||
pool_ptr -> tx_byte_pool_search = *this_block_link_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Adjust the pointer for the application. */
|
||||
current_ptr = TX_UCHAR_POINTER_ADD(current_ptr, (((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE)))));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Set current pointer to NULL to indicate nothing was found. */
|
||||
current_ptr = TX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the search pointer. */
|
||||
return(current_ptr);
|
||||
}
|
||||
|
||||
376
common_smp/src/tx_byte_release.c
Normal file
376
common_smp/src/tx_byte_release.c
Normal file
@@ -0,0 +1,376 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Byte Memory */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_byte_release PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function returns previously allocated memory to its */
|
||||
/* associated memory byte pool. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* memory_ptr Pointer to allocated memory */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* [TX_PTR_ERROR | TX_SUCCESS] Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* _tx_byte_pool_search Search the byte pool for memory */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_byte_release(VOID *memory_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
TX_BYTE_POOL *pool_ptr;
|
||||
TX_THREAD *thread_ptr;
|
||||
UCHAR *work_ptr;
|
||||
UCHAR *temp_ptr;
|
||||
UCHAR *next_block_ptr;
|
||||
TX_THREAD *susp_thread_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
ULONG memory_size;
|
||||
ALIGN_TYPE *free_ptr;
|
||||
TX_BYTE_POOL **byte_pool_ptr;
|
||||
UCHAR **block_link_ptr;
|
||||
UCHAR **suspend_info_ptr;
|
||||
|
||||
|
||||
/* Default to successful status. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Set the pool pointer to NULL. */
|
||||
pool_ptr = TX_NULL;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the memory pointer is valid. */
|
||||
work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(memory_ptr);
|
||||
if (work_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Back off the memory pointer to pickup its header. */
|
||||
work_ptr = TX_UCHAR_POINTER_SUB(work_ptr, ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE))));
|
||||
|
||||
/* There is a pointer, pickup the pool pointer address. */
|
||||
temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr);
|
||||
if ((*free_ptr) != TX_BYTE_BLOCK_FREE)
|
||||
{
|
||||
|
||||
/* Pickup the pool pointer. */
|
||||
temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
|
||||
byte_pool_ptr = TX_UCHAR_TO_INDIRECT_BYTE_POOL_POINTER(temp_ptr);
|
||||
pool_ptr = *byte_pool_ptr;
|
||||
|
||||
/* See if we have a valid pool pointer. */
|
||||
if (pool_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* See if we have a valid pool. */
|
||||
if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_PTR_ERROR;
|
||||
|
||||
/* Reset the pool pointer is NULL. */
|
||||
pool_ptr = TX_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the pointer is valid. */
|
||||
if (pool_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At this point, we know that the pointer is valid. */
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Indicate that this thread is the current owner. */
|
||||
pool_ptr -> tx_byte_pool_owner = thread_ptr;
|
||||
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total release counter. */
|
||||
_tx_byte_pool_performance_release_count++;
|
||||
|
||||
/* Increment the number of releases on this pool. */
|
||||
pool_ptr -> tx_byte_pool_performance_release_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_RELEASE, pool_ptr, TX_POINTER_TO_ULONG_CONVERT(memory_ptr), pool_ptr -> tx_byte_pool_suspended_count, pool_ptr -> tx_byte_pool_available, TX_TRACE_BYTE_POOL_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_BYTE_RELEASE_INSERT
|
||||
|
||||
/* Release the memory. */
|
||||
temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr);
|
||||
*free_ptr = TX_BYTE_BLOCK_FREE;
|
||||
|
||||
/* Update the number of available bytes in the pool. */
|
||||
block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
|
||||
next_block_ptr = *block_link_ptr;
|
||||
pool_ptr -> tx_byte_pool_available =
|
||||
pool_ptr -> tx_byte_pool_available + TX_UCHAR_POINTER_DIF(next_block_ptr, work_ptr);
|
||||
|
||||
/* Determine if the free block is prior to current search pointer. */
|
||||
if (work_ptr < (pool_ptr -> tx_byte_pool_search))
|
||||
{
|
||||
|
||||
/* Yes, update the search pointer to the released block. */
|
||||
pool_ptr -> tx_byte_pool_search = work_ptr;
|
||||
}
|
||||
|
||||
/* Determine if there are threads suspended on this byte pool. */
|
||||
if (pool_ptr -> tx_byte_pool_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Now examine the suspension list to find threads waiting for
|
||||
memory. Maybe it is now available! */
|
||||
while (pool_ptr -> tx_byte_pool_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Pickup the first suspended thread pointer. */
|
||||
susp_thread_ptr = pool_ptr -> tx_byte_pool_suspension_list;
|
||||
|
||||
/* Pickup the size of the memory the thread is requesting. */
|
||||
memory_size = susp_thread_ptr -> tx_thread_suspend_info;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* See if the request can be satisfied. */
|
||||
work_ptr = _tx_byte_pool_search(pool_ptr, memory_size);
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_BYTE_RELEASE_EXTENSION
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Indicate that this thread is the current owner. */
|
||||
pool_ptr -> tx_byte_pool_owner = thread_ptr;
|
||||
|
||||
/* If there is not enough memory, break this loop! */
|
||||
if (work_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Break out of the loop. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check to make sure the thread is still suspended. */
|
||||
if (susp_thread_ptr == pool_ptr -> tx_byte_pool_suspension_list)
|
||||
{
|
||||
|
||||
/* Also, makes sure the memory size is the same. */
|
||||
if (susp_thread_ptr -> tx_thread_suspend_info == memory_size)
|
||||
{
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* Decrement the number of threads suspended. */
|
||||
pool_ptr -> tx_byte_pool_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = pool_ptr -> tx_byte_pool_suspended_count;
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
pool_ptr -> tx_byte_pool_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = susp_thread_ptr -> tx_thread_suspended_next;
|
||||
pool_ptr -> tx_byte_pool_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = susp_thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Prepare for resumption of the thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
susp_thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Return this block pointer to the suspended thread waiting for
|
||||
a block. */
|
||||
suspend_info_ptr = TX_VOID_TO_INDIRECT_UCHAR_POINTER_CONVERT(susp_thread_ptr -> tx_thread_additional_suspend_info);
|
||||
*suspend_info_ptr = work_ptr;
|
||||
|
||||
/* Clear the memory pointer to indicate that it was given to the suspended thread. */
|
||||
work_ptr = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
susp_thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(susp_thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(susp_thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the memory was given to the suspended thread. */
|
||||
if (work_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* No, it wasn't given to the suspended thread. */
|
||||
|
||||
/* Put the memory back on the available list since this thread is no longer
|
||||
suspended. */
|
||||
work_ptr = TX_UCHAR_POINTER_SUB(work_ptr, (((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE)))));
|
||||
temp_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(UCHAR *)));
|
||||
free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(temp_ptr);
|
||||
*free_ptr = TX_BYTE_BLOCK_FREE;
|
||||
|
||||
/* Update the number of available bytes in the pool. */
|
||||
block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
|
||||
next_block_ptr = *block_link_ptr;
|
||||
pool_ptr -> tx_byte_pool_available =
|
||||
pool_ptr -> tx_byte_pool_available + TX_UCHAR_POINTER_DIF(next_block_ptr, work_ptr);
|
||||
|
||||
/* Determine if the current pointer is before the search pointer. */
|
||||
if (work_ptr < (pool_ptr -> tx_byte_pool_search))
|
||||
{
|
||||
|
||||
/* Yes, update the search pointer. */
|
||||
pool_ptr -> tx_byte_pool_search = work_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, threads suspended, restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
237
common_smp/src/tx_event_flags_cleanup.c
Normal file
237
common_smp/src/tx_event_flags_cleanup.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_cleanup PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes event flags timeout and thread terminate */
|
||||
/* actions that require the event flags data structures to be cleaned */
|
||||
/* up. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to suspended thread's */
|
||||
/* control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_timeout Thread timeout processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* _tx_thread_wait_abort Thread wait abort processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_event_flags_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_EVENT_FLAGS_GROUP *group_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *suspension_head;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts to remove the suspended thread from the event flags group. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the cleanup is still required. */
|
||||
if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_event_flags_cleanup))
|
||||
{
|
||||
|
||||
/* Check for valid suspension sequence. */
|
||||
if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
|
||||
{
|
||||
|
||||
/* Setup pointer to event flags control block. */
|
||||
group_ptr = TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
|
||||
/* Check for a NULL event flags control block pointer. */
|
||||
if (group_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Is the group pointer ID valid? */
|
||||
if (group_ptr -> tx_event_flags_group_id == TX_EVENT_FLAGS_ID)
|
||||
{
|
||||
|
||||
/* Determine if there are any thread suspensions. */
|
||||
if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
#else
|
||||
|
||||
/* Setup pointer to event flags control block. */
|
||||
group_ptr = TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
#endif
|
||||
|
||||
/* Yes, we still have thread suspension! */
|
||||
|
||||
/* Clear the suspension cleanup flag. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
|
||||
|
||||
/* Pickup the suspension head. */
|
||||
suspension_head = group_ptr -> tx_event_flags_group_suspension_list;
|
||||
|
||||
/* Determine if the cleanup is being done while a set operation was interrupted. If the
|
||||
suspended count is non-zero and the suspension head is NULL, the list is being processed
|
||||
and cannot be touched from here. The suspension list removal will instead take place
|
||||
inside the event flag set code. */
|
||||
if (suspension_head != TX_NULL)
|
||||
{
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* Decrement the local suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Store the updated suspended count. */
|
||||
group_ptr -> tx_event_flags_group_suspended_count = suspended_count;
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
group_ptr -> tx_event_flags_group_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same suspension list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Determine if we need to update the head pointer. */
|
||||
if (suspension_head == thread_ptr)
|
||||
{
|
||||
|
||||
/* Update the list head pointer. */
|
||||
group_ptr -> tx_event_flags_group_suspension_list = next_thread;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* In this case, the search pointer in an interrupted event flag set must be reset. */
|
||||
group_ptr -> tx_event_flags_group_reset_search = TX_TRUE;
|
||||
}
|
||||
|
||||
/* Now we need to determine if this cleanup is from a terminate, timeout,
|
||||
or from a wait abort. */
|
||||
if (thread_ptr -> tx_thread_state == TX_EVENT_FLAG)
|
||||
{
|
||||
|
||||
/* Timeout condition and the thread still suspended on the event flags group.
|
||||
Setup return error status and resume the thread. */
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total timeouts counter. */
|
||||
_tx_event_flags_performance_timeout_count++;
|
||||
|
||||
/* Increment the number of timeouts on this event flags group. */
|
||||
group_ptr -> tx_event_flags_group____performance_timeout_count++;
|
||||
#endif
|
||||
|
||||
/* Setup return status. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_NO_EVENTS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread! Check for preemption even though we are executing
|
||||
from the system timer thread right now which normally executes at the
|
||||
highest priority. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
141
common_smp/src/tx_event_flags_create.c
Normal file
141
common_smp/src/tx_event_flags_create.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_create PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a group of 32 event flags. All the flags are */
|
||||
/* initially in a cleared state. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to event flags group */
|
||||
/* control block */
|
||||
/* name_ptr Pointer to event flags name */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_EVENT_FLAGS_GROUP *next_group;
|
||||
TX_EVENT_FLAGS_GROUP *previous_group;
|
||||
|
||||
|
||||
/* Initialize event flags control block to all zeros. */
|
||||
TX_MEMSET(group_ptr, 0, (sizeof(TX_EVENT_FLAGS_GROUP)));
|
||||
|
||||
/* Setup the basic event flags group fields. */
|
||||
group_ptr -> tx_event_flags_group_name = name_ptr;
|
||||
|
||||
/* Disable interrupts to put the event flags group on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Setup the event flags ID to make it valid. */
|
||||
group_ptr -> tx_event_flags_group_id = TX_EVENT_FLAGS_ID;
|
||||
|
||||
/* Place the group on the list of created event flag groups. First,
|
||||
check for an empty list. */
|
||||
if (_tx_event_flags_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created event flags list is empty. Add event flag group to empty list. */
|
||||
_tx_event_flags_created_ptr = group_ptr;
|
||||
group_ptr -> tx_event_flags_group_created_next = group_ptr;
|
||||
group_ptr -> tx_event_flags_group_created_previous = group_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_group = _tx_event_flags_created_ptr;
|
||||
previous_group = next_group -> tx_event_flags_group_created_previous;
|
||||
|
||||
/* Place the new event flag group in the list. */
|
||||
next_group -> tx_event_flags_group_created_previous = group_ptr;
|
||||
previous_group -> tx_event_flags_group_created_next = group_ptr;
|
||||
|
||||
/* Setup this group's created links. */
|
||||
group_ptr -> tx_event_flags_group_created_previous = previous_group;
|
||||
group_ptr -> tx_event_flags_group_created_next = next_group;
|
||||
}
|
||||
|
||||
/* Increment the number of created event flag groups. */
|
||||
_tx_event_flags_created_count++;
|
||||
|
||||
/* Optional event flag group create extended processing. */
|
||||
TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr)
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_EVENT_FLAGS, group_ptr, name_ptr, 0, 0)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_CREATE, group_ptr, TX_POINTER_TO_ULONG_CONVERT(&next_group), 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS_CREATE_INSERT
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
207
common_smp/src/tx_event_flags_delete.c
Normal file
207
common_smp/src/tx_event_flags_delete.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function deletes the specified event flag group. All threads */
|
||||
/* suspended on the group are resumed with the TX_DELETED status */
|
||||
/* code. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to group control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
UINT suspended_count;
|
||||
TX_EVENT_FLAGS_GROUP *next_group;
|
||||
TX_EVENT_FLAGS_GROUP *previous_group;
|
||||
|
||||
|
||||
/* Disable interrupts to remove the group from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_DELETE, group_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Optional event flags group delete extended processing. */
|
||||
TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(group_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS_DELETE_INSERT
|
||||
|
||||
/* Clear the event flag group ID to make it invalid. */
|
||||
group_ptr -> tx_event_flags_group_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the number of created event flag groups. */
|
||||
_tx_event_flags_created_count--;
|
||||
|
||||
/* See if this group is the only one on the list. */
|
||||
if (_tx_event_flags_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created event flag group, just set the created list to NULL. */
|
||||
_tx_event_flags_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_group = group_ptr -> tx_event_flags_group_created_next;
|
||||
previous_group = group_ptr -> tx_event_flags_group_created_previous;
|
||||
next_group -> tx_event_flags_group_created_previous = previous_group;
|
||||
previous_group -> tx_event_flags_group_created_next = next_group;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_event_flags_created_ptr == group_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_event_flags_created_ptr = next_group;
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Pickup the suspension information. */
|
||||
thread_ptr = group_ptr -> tx_event_flags_group_suspension_list;
|
||||
group_ptr -> tx_event_flags_group_suspension_list = TX_NULL;
|
||||
suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
|
||||
group_ptr -> tx_event_flags_group_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the event flag suspension list to resume any and all threads
|
||||
suspended on this group. */
|
||||
while (suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Decrement the number of suspended threads. */
|
||||
suspended_count--;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_DELETED. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_DELETED;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move to next thread. */
|
||||
thread_ptr = next_thread;
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_EVENT_FLAGS_GROUP_DELETE_PORT_COMPLETION(group_ptr)
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release previous preempt disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
401
common_smp/src/tx_event_flags_get.c
Normal file
401
common_smp/src/tx_event_flags_get.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function gets the specified event flags from the group, */
|
||||
/* according to the get option. The get option also specifies whether */
|
||||
/* or not the retrieved flags are cleared. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to group control block */
|
||||
/* requested_event_flags Event flags requested */
|
||||
/* get_option Specifies and/or and clear options*/
|
||||
/* actual_flags_ptr Pointer to place the actual flags */
|
||||
/* the service retrieved */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Suspend thread service */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags,
|
||||
UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
UINT and_request;
|
||||
UINT clear_request;
|
||||
ULONG current_flags;
|
||||
ULONG flags_satisfied;
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
ULONG delayed_clear_flags;
|
||||
#endif
|
||||
UINT suspended_count;
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
UINT interrupted_set_request;
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable interrupts to examine the event flags group. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total event flags get counter. */
|
||||
_tx_event_flags_performance_get_count++;
|
||||
|
||||
/* Increment the number of event flags gets on this semaphore. */
|
||||
group_ptr -> tx_event_flags_group__performance_get_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_GET, group_ptr, requested_flags, group_ptr -> tx_event_flags_group_current, get_option, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS_GET_INSERT
|
||||
|
||||
/* Pickup current flags. */
|
||||
current_flags = group_ptr -> tx_event_flags_group_current;
|
||||
|
||||
/* Apply the event flag option mask. */
|
||||
and_request = (get_option & TX_AND);
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Check for AND condition. All flags must be present to satisfy request. */
|
||||
if (and_request == TX_AND)
|
||||
{
|
||||
|
||||
/* AND request is present. */
|
||||
|
||||
/* Calculate the flags present. */
|
||||
flags_satisfied = (current_flags & requested_flags);
|
||||
|
||||
/* Determine if they satisfy the AND request. */
|
||||
if (flags_satisfied != requested_flags)
|
||||
{
|
||||
|
||||
/* No, not all the requested flags are present. Clear the flags present variable. */
|
||||
flags_satisfied = ((ULONG) 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* OR request is present. Simply or the requested flags and the current flags. */
|
||||
flags_satisfied = (current_flags & requested_flags);
|
||||
}
|
||||
|
||||
/* Determine if the request is satisfied. */
|
||||
if (flags_satisfied != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Return the actual event flags that satisfied the request. */
|
||||
*actual_flags_ptr = current_flags;
|
||||
|
||||
/* Pickup the clear bit. */
|
||||
clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
|
||||
|
||||
/* Determine whether or not clearing needs to take place. */
|
||||
if (clear_request == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, clear the flags that satisfied this request. */
|
||||
group_ptr -> tx_event_flags_group_current =
|
||||
group_ptr -> tx_event_flags_group_current & (~requested_flags);
|
||||
}
|
||||
|
||||
/* Return success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Pickup delayed clear flags. */
|
||||
delayed_clear_flags = group_ptr -> tx_event_flags_group_delayed_clear;
|
||||
|
||||
/* Determine if there are any delayed clear operations pending. */
|
||||
if (delayed_clear_flags != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, apply them to the current flags. */
|
||||
current_flags = current_flags & (~delayed_clear_flags);
|
||||
}
|
||||
|
||||
/* Check for AND condition. All flags must be present to satisfy request. */
|
||||
if (and_request == TX_AND)
|
||||
{
|
||||
|
||||
/* AND request is present. */
|
||||
|
||||
/* Calculate the flags present. */
|
||||
flags_satisfied = (current_flags & requested_flags);
|
||||
|
||||
/* Determine if they satisfy the AND request. */
|
||||
if (flags_satisfied != requested_flags)
|
||||
{
|
||||
|
||||
/* No, not all the requested flags are present. Clear the flags present variable. */
|
||||
flags_satisfied = ((ULONG) 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* OR request is present. Simply AND together the requested flags and the current flags
|
||||
to see if any are present. */
|
||||
flags_satisfied = (current_flags & requested_flags);
|
||||
}
|
||||
|
||||
/* Determine if the request is satisfied. */
|
||||
if (flags_satisfied != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, this request can be handled immediately. */
|
||||
|
||||
/* Return the actual event flags that satisfied the request. */
|
||||
*actual_flags_ptr = current_flags;
|
||||
|
||||
/* Pickup the clear bit. */
|
||||
clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
|
||||
|
||||
/* Determine whether or not clearing needs to take place. */
|
||||
if (clear_request == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Set interrupted set request flag to false. */
|
||||
interrupted_set_request = TX_FALSE;
|
||||
|
||||
/* Determine if the suspension list is being processed by an interrupted
|
||||
set request. */
|
||||
if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL)
|
||||
{
|
||||
|
||||
/* Set the interrupted set request flag. */
|
||||
interrupted_set_request = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Was a set request interrupted? */
|
||||
if (interrupted_set_request == TX_TRUE)
|
||||
{
|
||||
|
||||
/* A previous set operation is was interrupted, we need to defer the
|
||||
event clearing until the set operation is complete. */
|
||||
|
||||
/* Remember the events to clear. */
|
||||
group_ptr -> tx_event_flags_group_delayed_clear =
|
||||
group_ptr -> tx_event_flags_group_delayed_clear | requested_flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Yes, clear the flags that satisfied this request. */
|
||||
group_ptr -> tx_event_flags_group_current =
|
||||
group_ptr -> tx_event_flags_group_current & ~requested_flags;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set status to success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if the request specifies suspension. */
|
||||
if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point, return error completion. */
|
||||
status = TX_NO_EVENTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total event flags suspensions counter. */
|
||||
_tx_event_flags_performance_suspension_count++;
|
||||
|
||||
/* Increment the number of event flags suspensions on this semaphore. */
|
||||
group_ptr -> tx_event_flags_group___performance_suspension_count++;
|
||||
#endif
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_event_flags_cleanup);
|
||||
|
||||
/* Remember which event flags we are looking for. */
|
||||
thread_ptr -> tx_thread_suspend_info = requested_flags;
|
||||
|
||||
/* Save the get option as well. */
|
||||
thread_ptr -> tx_thread_suspend_option = get_option;
|
||||
|
||||
/* Save the destination for the current events. */
|
||||
thread_ptr -> tx_thread_additional_suspend_info = (VOID *) actual_flags_ptr;
|
||||
|
||||
/* Setup cleanup information, i.e. this event flags group control
|
||||
block. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) group_ptr;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
group_ptr -> tx_event_flags_group_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = group_ptr -> tx_event_flags_group_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Increment the number of threads suspended. */
|
||||
group_ptr -> tx_event_flags_group_suspended_count++;
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_EVENT_FLAG;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Immediate return, return error completion. */
|
||||
status = TX_NO_EVENTS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
143
common_smp/src/tx_event_flags_info_get.c
Normal file
143
common_smp/src/tx_event_flags_info_get.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified event flag */
|
||||
/* group. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to event flag group */
|
||||
/* name Destination for the event flag */
|
||||
/* group name */
|
||||
/* current_flags Current event flags */
|
||||
/* first_suspended Destination for pointer of first */
|
||||
/* thread suspended on event flags */
|
||||
/* suspended_count Destination for suspended count */
|
||||
/* next_group Destination for pointer to next */
|
||||
/* event flag group on the created */
|
||||
/* list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_info_get(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR **name, ULONG *current_flags,
|
||||
TX_THREAD **first_suspended, ULONG *suspended_count,
|
||||
TX_EVENT_FLAGS_GROUP **next_group)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_INFO_GET, group_ptr, 0, 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the event flag group. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = group_ptr -> tx_event_flags_group_name;
|
||||
}
|
||||
|
||||
/* Retrieve the current event flags in the event flag group. */
|
||||
if (current_flags != TX_NULL)
|
||||
{
|
||||
|
||||
/* Pickup the current flags and apply delayed clearing. */
|
||||
*current_flags = group_ptr -> tx_event_flags_group_current &
|
||||
~group_ptr -> tx_event_flags_group_delayed_clear;
|
||||
}
|
||||
|
||||
/* Retrieve the first thread suspended on this event flag group. */
|
||||
if (first_suspended != TX_NULL)
|
||||
{
|
||||
|
||||
*first_suspended = group_ptr -> tx_event_flags_group_suspension_list;
|
||||
}
|
||||
|
||||
/* Retrieve the number of threads suspended on this event flag group. */
|
||||
if (suspended_count != TX_NULL)
|
||||
{
|
||||
|
||||
*suspended_count = (ULONG) group_ptr -> tx_event_flags_group_suspended_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to the next event flag group created. */
|
||||
if (next_group != TX_NULL)
|
||||
{
|
||||
|
||||
*next_group = group_ptr -> tx_event_flags_group_created_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
130
common_smp/src/tx_event_flags_initialize.c
Normal file
130
common_smp/src/tx_event_flags_initialize.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
#ifndef TX_INLINE_INITIALIZATION
|
||||
|
||||
/* Locate event flags component data in this file. */
|
||||
/* Define the head pointer of the created event flags list. */
|
||||
|
||||
TX_EVENT_FLAGS_GROUP * _tx_event_flags_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created event flag groups. */
|
||||
|
||||
ULONG _tx_event_flags_created_count;
|
||||
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of event flag sets. */
|
||||
|
||||
ULONG _tx_event_flags_performance_set_count;
|
||||
|
||||
|
||||
/* Define the total number of event flag gets. */
|
||||
|
||||
ULONG _tx_event_flags_performance_get_count;
|
||||
|
||||
|
||||
/* Define the total number of event flag suspensions. */
|
||||
|
||||
ULONG _tx_event_flags_performance_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of event flag timeouts. */
|
||||
|
||||
ULONG _tx_event_flags_performance_timeout_count;
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_initialize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the event flags component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_event_flags_initialize(VOID)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the head pointer of the created event flags list and the
|
||||
number of event flags created. */
|
||||
_tx_event_flags_created_ptr = TX_NULL;
|
||||
_tx_event_flags_created_count = TX_EMPTY;
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize event flags performance counters. */
|
||||
_tx_event_flags_performance_set_count = ((ULONG) 0);
|
||||
_tx_event_flags_performance_get_count = ((ULONG) 0);
|
||||
_tx_event_flags_performance_suspension_count = ((ULONG) 0);
|
||||
_tx_event_flags_performance_timeout_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
202
common_smp/src/tx_event_flags_performance_info_get.c
Normal file
202
common_smp/src/tx_event_flags_performance_info_get.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_event_flags.h"
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* event flag group. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to event flag group */
|
||||
/* sets Destination for the number of */
|
||||
/* event flag sets on this group */
|
||||
/* gets Destination for the number of */
|
||||
/* event flag gets on this group */
|
||||
/* suspensions Destination for the number of */
|
||||
/* event flag suspensions on this */
|
||||
/* group */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* on this event flag group */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_performance_info_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG *sets, ULONG *gets,
|
||||
ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (group_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Event flags group pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the event group ID is invalid. */
|
||||
else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID)
|
||||
{
|
||||
|
||||
/* Event flags group pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_PERFORMANCE_INFO_GET, group_ptr, 0, 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the number of set operations on this event flag group. */
|
||||
if (sets != TX_NULL)
|
||||
{
|
||||
|
||||
*sets = group_ptr -> tx_event_flags_group_performance_set_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of get operations on this event flag group. */
|
||||
if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
*gets = group_ptr -> tx_event_flags_group__performance_get_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of thread suspensions on this event flag group. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = group_ptr -> tx_event_flags_group___performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of thread timeouts on this event flag group. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = group_ptr -> tx_event_flags_group____performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return successful completion. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
#else
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (group_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (sets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
174
common_smp/src/tx_event_flags_performance_system_info_get.c
Normal file
174
common_smp/src/tx_event_flags_performance_system_info_get.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_event_flags.h"
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves system event flag performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* sets Destination for total number of */
|
||||
/* event flag sets */
|
||||
/* gets Destination for total number of */
|
||||
/* event flag gets */
|
||||
/* suspensions Destination for total number of */
|
||||
/* event flag suspensions */
|
||||
/* timeouts Destination for total number of */
|
||||
/* timeouts */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_performance_system_info_get(ULONG *sets, ULONG *gets, ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS__PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the total number of event flag set operations. */
|
||||
if (sets != TX_NULL)
|
||||
{
|
||||
|
||||
*sets = _tx_event_flags_performance_set_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of event flag get operations. */
|
||||
if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
*gets = _tx_event_flags_performance_get_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of event flag thread suspensions. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = _tx_event_flags_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of event flag thread timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_event_flags_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (sets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
620
common_smp/src/tx_event_flags_set.c
Normal file
620
common_smp/src/tx_event_flags_set.c
Normal file
@@ -0,0 +1,620 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_set PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function sets the specified flags in the event group based on */
|
||||
/* the set option specified. All threads suspended on the group whose */
|
||||
/* get request can now be satisfied are resumed. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to group control block */
|
||||
/* flags_to_set Event flags to set */
|
||||
/* set_option Specified either AND or OR */
|
||||
/* operation on the event flags */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Always returns success */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, UINT set_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
TX_THREAD *satisfied_list;
|
||||
TX_THREAD *last_satisfied;
|
||||
TX_THREAD *suspended_list;
|
||||
UINT suspended_count;
|
||||
ULONG current_event_flags;
|
||||
ULONG requested_flags;
|
||||
ULONG flags_satisfied;
|
||||
ULONG *suspend_info_ptr;
|
||||
UINT and_request;
|
||||
UINT get_option;
|
||||
UINT clear_request;
|
||||
UINT preempt_check;
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
UINT interrupted_set_request;
|
||||
#endif
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*events_set_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *notify_group_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable interrupts to remove the semaphore from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total event flags set counter. */
|
||||
_tx_event_flags_performance_set_count++;
|
||||
|
||||
/* Increment the number of event flags sets on this semaphore. */
|
||||
group_ptr -> tx_event_flags_group_performance_set_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_SET, group_ptr, flags_to_set, set_option, group_ptr -> tx_event_flags_group_suspended_count, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_EVENT_FLAGS_SET_INSERT
|
||||
|
||||
/* Determine how to set this group's event flags. */
|
||||
if ((set_option & TX_EVENT_FLAGS_AND_MASK) == TX_AND)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Set interrupted set request flag to false. */
|
||||
interrupted_set_request = TX_FALSE;
|
||||
|
||||
/* Determine if the suspension list is being processed by an interrupted
|
||||
set request. */
|
||||
if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL)
|
||||
{
|
||||
|
||||
/* Set the interrupted set request flag. */
|
||||
interrupted_set_request = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Was a set request interrupted? */
|
||||
if (interrupted_set_request == TX_TRUE)
|
||||
{
|
||||
|
||||
/* A previous set operation was interrupted, we need to defer the
|
||||
event clearing until the set operation is complete. */
|
||||
|
||||
/* Remember the events to clear. */
|
||||
group_ptr -> tx_event_flags_group_delayed_clear =
|
||||
group_ptr -> tx_event_flags_group_delayed_clear | ~flags_to_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Previous set operation was not interrupted, simply clear the
|
||||
specified flags by "ANDing" the flags into the current events
|
||||
of the group. */
|
||||
group_ptr -> tx_event_flags_group_current =
|
||||
group_ptr -> tx_event_flags_group_current & flags_to_set;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this event flag group. */
|
||||
events_set_notify = group_ptr -> tx_event_flags_group_set_notify;
|
||||
#endif
|
||||
|
||||
/* "OR" the flags into the current events of the group. */
|
||||
group_ptr -> tx_event_flags_group_current =
|
||||
group_ptr -> tx_event_flags_group_current | flags_to_set;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Determine if there are any delayed flags to clear. */
|
||||
if (group_ptr -> tx_event_flags_group_delayed_clear != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, we need to neutralize the delayed clearing as well. */
|
||||
group_ptr -> tx_event_flags_group_delayed_clear =
|
||||
group_ptr -> tx_event_flags_group_delayed_clear & ~flags_to_set;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clear the preempt check flag. */
|
||||
preempt_check = TX_FALSE;
|
||||
|
||||
/* Pickup the thread suspended count. */
|
||||
suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
|
||||
|
||||
/* Determine if there are any threads suspended on the event flag group. */
|
||||
if (group_ptr -> tx_event_flags_group_suspension_list != TX_NULL)
|
||||
{
|
||||
|
||||
/* Determine if there is just a single thread waiting on the event
|
||||
flag group. */
|
||||
if (suspended_count == ((UINT) 1))
|
||||
{
|
||||
|
||||
/* Single thread waiting for event flags. Bypass the multiple thread
|
||||
logic. */
|
||||
|
||||
/* Setup thread pointer. */
|
||||
thread_ptr = group_ptr -> tx_event_flags_group_suspension_list;
|
||||
|
||||
/* Pickup the current event flags. */
|
||||
current_event_flags = group_ptr -> tx_event_flags_group_current;
|
||||
|
||||
/* Pickup the suspend information. */
|
||||
requested_flags = thread_ptr -> tx_thread_suspend_info;
|
||||
|
||||
/* Pickup the suspend option. */
|
||||
get_option = thread_ptr -> tx_thread_suspend_option;
|
||||
|
||||
/* Isolate the AND selection. */
|
||||
and_request = (get_option & TX_AND);
|
||||
|
||||
/* Check for AND condition. All flags must be present to satisfy request. */
|
||||
if (and_request == TX_AND)
|
||||
{
|
||||
|
||||
/* AND request is present. */
|
||||
|
||||
/* Calculate the flags present. */
|
||||
flags_satisfied = (current_event_flags & requested_flags);
|
||||
|
||||
/* Determine if they satisfy the AND request. */
|
||||
if (flags_satisfied != requested_flags)
|
||||
{
|
||||
|
||||
/* No, not all the requested flags are present. Clear the flags present variable. */
|
||||
flags_satisfied = ((ULONG) 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* OR request is present. Simply or the requested flags and the current flags. */
|
||||
flags_satisfied = (current_event_flags & requested_flags);
|
||||
}
|
||||
|
||||
/* Determine if the request is satisfied. */
|
||||
if (flags_satisfied != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, resume the thread and apply any event flag
|
||||
clearing. */
|
||||
|
||||
/* Set the preempt check flag. */
|
||||
preempt_check = TX_TRUE;
|
||||
|
||||
/* Return the actual event flags that satisfied the request. */
|
||||
suspend_info_ptr = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
*suspend_info_ptr = current_event_flags;
|
||||
|
||||
/* Pickup the clear bit. */
|
||||
clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
|
||||
|
||||
/* Determine whether or not clearing needs to take place. */
|
||||
if (clear_request == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, clear the flags that satisfied this request. */
|
||||
group_ptr -> tx_event_flags_group_current = group_ptr -> tx_event_flags_group_current & (~requested_flags);
|
||||
}
|
||||
|
||||
/* Clear the suspension information in the event flag group. */
|
||||
group_ptr -> tx_event_flags_group_suspension_list = TX_NULL;
|
||||
group_ptr -> tx_event_flags_group_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts to remove the semaphore from the created list. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Otherwise, the event flag requests of multiple threads must be
|
||||
examined. */
|
||||
|
||||
/* Setup thread pointer, keep a local copy of the head pointer. */
|
||||
suspended_list = group_ptr -> tx_event_flags_group_suspension_list;
|
||||
thread_ptr = suspended_list;
|
||||
|
||||
/* Clear the suspended list head pointer to thwart manipulation of
|
||||
the list in ISR's while we are processing here. */
|
||||
group_ptr -> tx_event_flags_group_suspension_list = TX_NULL;
|
||||
|
||||
/* Setup the satisfied thread pointers. */
|
||||
satisfied_list = TX_NULL;
|
||||
last_satisfied = TX_NULL;
|
||||
|
||||
/* Pickup the current event flags. */
|
||||
current_event_flags = group_ptr -> tx_event_flags_group_current;
|
||||
|
||||
/* Disable preemption while we process the suspended list. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Loop to examine all of the suspended threads. */
|
||||
do
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
/* Determine if we need to reset the search. */
|
||||
if (group_ptr -> tx_event_flags_group_reset_search != TX_FALSE)
|
||||
{
|
||||
|
||||
/* Clear the reset search flag. */
|
||||
group_ptr -> tx_event_flags_group_reset_search = TX_FALSE;
|
||||
|
||||
/* Move the thread pointer to the beginning of the search list. */
|
||||
thread_ptr = suspended_list;
|
||||
|
||||
/* Reset the suspended count. */
|
||||
suspended_count = group_ptr -> tx_event_flags_group_suspended_count;
|
||||
|
||||
/* Update the current events with any new ones that might
|
||||
have been set in a nested set events call from an ISR. */
|
||||
current_event_flags = current_event_flags | group_ptr -> tx_event_flags_group_current;
|
||||
}
|
||||
|
||||
/* Save next thread pointer. */
|
||||
next_thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Pickup the suspend information. */
|
||||
requested_flags = thread_ptr -> tx_thread_suspend_info;
|
||||
|
||||
/* Pickup this thread's suspension get option. */
|
||||
get_option = thread_ptr -> tx_thread_suspend_option;
|
||||
|
||||
/* Isolate the AND selection. */
|
||||
and_request = (get_option & TX_AND);
|
||||
|
||||
/* Check for AND condition. All flags must be present to satisfy request. */
|
||||
if (and_request == TX_AND)
|
||||
{
|
||||
|
||||
/* AND request is present. */
|
||||
|
||||
/* Calculate the flags present. */
|
||||
flags_satisfied = (current_event_flags & requested_flags);
|
||||
|
||||
/* Determine if they satisfy the AND request. */
|
||||
if (flags_satisfied != requested_flags)
|
||||
{
|
||||
|
||||
/* No, not all the requested flags are present. Clear the flags present variable. */
|
||||
flags_satisfied = ((ULONG) 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* OR request is present. Simply or the requested flags and the current flags. */
|
||||
flags_satisfied = (current_event_flags & requested_flags);
|
||||
}
|
||||
|
||||
/* Check to see if the thread had a timeout or wait abort during the event search processing.
|
||||
If so, just set the flags satisfied to ensure the processing here removes the thread from
|
||||
the suspension list. */
|
||||
if (thread_ptr -> tx_thread_state != TX_EVENT_FLAG)
|
||||
{
|
||||
|
||||
/* Simply set the satisfied flags to 1 in order to remove the thread from the suspension list. */
|
||||
flags_satisfied = ((ULONG) 1);
|
||||
}
|
||||
|
||||
/* Determine if the request is satisfied. */
|
||||
if (flags_satisfied != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, this request can be handled now. */
|
||||
|
||||
/* Set the preempt check flag. */
|
||||
preempt_check = TX_TRUE;
|
||||
|
||||
/* Determine if the thread is still suspended on the event flag group. If not, a wait
|
||||
abort must have been done from an ISR. */
|
||||
if (thread_ptr -> tx_thread_state == TX_EVENT_FLAG)
|
||||
{
|
||||
|
||||
/* Return the actual event flags that satisfied the request. */
|
||||
suspend_info_ptr = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
*suspend_info_ptr = current_event_flags;
|
||||
|
||||
/* Pickup the clear bit. */
|
||||
clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK);
|
||||
|
||||
/* Determine whether or not clearing needs to take place. */
|
||||
if (clear_request == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, clear the flags that satisfied this request. */
|
||||
group_ptr -> tx_event_flags_group_current = group_ptr -> tx_event_flags_group_current & ~requested_flags;
|
||||
}
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
/* We need to remove the thread from the suspension list and place it in the
|
||||
expired list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (thread_ptr == thread_ptr -> tx_thread_suspended_next)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
suspended_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Update the list head pointer, if removing the head of the
|
||||
list. */
|
||||
if (suspended_list == thread_ptr)
|
||||
{
|
||||
|
||||
/* Yes, head pointer needs to be updated. */
|
||||
suspended_list = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
group_ptr -> tx_event_flags_group_suspended_count--;
|
||||
|
||||
/* Place this thread on the expired list. */
|
||||
if (satisfied_list == TX_NULL)
|
||||
{
|
||||
|
||||
/* First thread on the satisfied list. */
|
||||
satisfied_list = thread_ptr;
|
||||
last_satisfied = thread_ptr;
|
||||
|
||||
/* Setup initial next pointer. */
|
||||
thread_ptr -> tx_thread_suspended_next = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not the first thread on the satisfied list. */
|
||||
|
||||
/* Link it up at the end. */
|
||||
last_satisfied -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = TX_NULL;
|
||||
last_satisfied = thread_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy next thread pointer to working thread ptr. */
|
||||
thread_ptr = next_thread_ptr;
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
} while (suspended_count != TX_NO_SUSPENSIONS);
|
||||
|
||||
/* Setup the group's suspension list head again. */
|
||||
group_ptr -> tx_event_flags_group_suspension_list = suspended_list;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Determine if there is any delayed event clearing to perform. */
|
||||
if (group_ptr -> tx_event_flags_group_delayed_clear != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Perform the delayed event clearing. */
|
||||
group_ptr -> tx_event_flags_group_current =
|
||||
group_ptr -> tx_event_flags_group_current & ~(group_ptr -> tx_event_flags_group_delayed_clear);
|
||||
|
||||
/* Clear the delayed event flag clear value. */
|
||||
group_ptr -> tx_event_flags_group_delayed_clear = ((ULONG) 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the satisfied list, setup initial thread pointer. */
|
||||
thread_ptr = satisfied_list;
|
||||
while(thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Get next pointer first. */
|
||||
next_thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupt posture. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move next thread to current. */
|
||||
thread_ptr = next_thread_ptr;
|
||||
}
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release thread preemption disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if we need to set the reset search field. */
|
||||
if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* We interrupted a search of an event flag group suspension
|
||||
list. Make sure we reset the search. */
|
||||
group_ptr -> tx_event_flags_group_reset_search = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (events_set_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application event flags set notification. */
|
||||
(events_set_notify)(group_ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if a check for preemption is necessary. */
|
||||
if (preempt_check == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, one or more threads were resumed, check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
107
common_smp/src/tx_event_flags_set_notify.c
Normal file
107
common_smp/src/tx_event_flags_set_notify.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Event Flags */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_event_flags.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_event_flags_set_notify PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function registers an application callback function that is */
|
||||
/* called whenever an event flag is set in this group. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* group_ptr Pointer to group control block*/
|
||||
/* group_put_notify Application callback function */
|
||||
/* (TX_NULL disables notify) */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_event_flags_set_notify(TX_EVENT_FLAGS_GROUP *group_ptr, VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr))
|
||||
{
|
||||
|
||||
#ifdef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
TX_EVENT_FLAGS_GROUP_NOT_USED(group_ptr);
|
||||
TX_EVENT_FLAGS_SET_NOTIFY_NOT_USED(events_set_notify);
|
||||
|
||||
/* Feature is not enabled, return error. */
|
||||
return(TX_FEATURE_NOT_ENABLED);
|
||||
#else
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_SET_NOTIFY, group_ptr, 0, 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS)
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_EL_EVENT_FLAGS_SET_NOTIFY_INSERT
|
||||
|
||||
/* Setup event flag group set notification callback function. */
|
||||
group_ptr -> tx_event_flags_group_set_notify = events_set_notify;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success to caller. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
150
common_smp/src/tx_initialize_high_level.c
Normal file
150
common_smp/src/tx_initialize_high_level.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Initialize */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
|
||||
/* Determine if in-line initialization is required. */
|
||||
#ifdef TX_INLINE_INITIALIZATION
|
||||
#define TX_INVOKE_INLINE_INITIALIZATION
|
||||
#endif
|
||||
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_semaphore.h"
|
||||
#include "tx_queue.h"
|
||||
#include "tx_event_flags.h"
|
||||
#include "tx_mutex.h"
|
||||
#include "tx_block_pool.h"
|
||||
#include "tx_byte_pool.h"
|
||||
|
||||
|
||||
/* Define the unused memory pointer. The value of the first available
|
||||
memory address is placed in this variable in the low-level
|
||||
initialization function. The content of this variable is passed
|
||||
to the application's system definition function. */
|
||||
|
||||
VOID *_tx_initialize_unused_memory;
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_initialize_high_level PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is responsible for initializing all of the other */
|
||||
/* components in the ThreadX real-time kernel. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_initialize Initialize the thread control */
|
||||
/* component */
|
||||
/* _tx_timer_initialize Initialize the timer control */
|
||||
/* component */
|
||||
/* _tx_semaphore_initialize Initialize the semaphore control */
|
||||
/* component */
|
||||
/* _tx_queue_initialize Initialize the queue control */
|
||||
/* component */
|
||||
/* _tx_event_flags_initialize Initialize the event flags control*/
|
||||
/* component */
|
||||
/* _tx_block_pool_initialize Initialize the block pool control */
|
||||
/* component */
|
||||
/* _tx_byte_pool_initialize Initialize the byte pool control */
|
||||
/* component */
|
||||
/* _tx_mutex_initialize Initialize the mutex control */
|
||||
/* component */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_kernel_enter Kernel entry function */
|
||||
/* _tx_initialize_kernel_setup Early kernel setup function that */
|
||||
/* is optionally called by */
|
||||
/* compiler's startup code. */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_initialize_high_level(VOID)
|
||||
{
|
||||
|
||||
/* Initialize event tracing, if enabled. */
|
||||
TX_TRACE_INITIALIZE
|
||||
|
||||
/* Initialize the event log, if enabled. */
|
||||
TX_EL_INITIALIZE
|
||||
|
||||
/* Call the thread control initialization function. */
|
||||
_tx_thread_initialize();
|
||||
|
||||
#ifndef TX_NO_TIMER
|
||||
|
||||
/* Call the timer control initialization function. */
|
||||
_tx_timer_initialize();
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Call the semaphore initialization function. */
|
||||
_tx_semaphore_initialize();
|
||||
|
||||
/* Call the queue initialization function. */
|
||||
_tx_queue_initialize();
|
||||
|
||||
/* Call the event flag initialization function. */
|
||||
_tx_event_flags_initialize();
|
||||
|
||||
/* Call the block pool initialization function. */
|
||||
_tx_block_pool_initialize();
|
||||
|
||||
/* Call the byte pool initialization function. */
|
||||
_tx_byte_pool_initialize();
|
||||
|
||||
/* Call the mutex initialization function. */
|
||||
_tx_mutex_initialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
188
common_smp/src/tx_initialize_kernel_enter.c
Normal file
188
common_smp/src/tx_initialize_kernel_enter.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Initialize */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_timer.h"
|
||||
|
||||
|
||||
/* Define any port-specific scheduling data structures. */
|
||||
|
||||
TX_PORT_SPECIFIC_DATA
|
||||
|
||||
|
||||
#ifdef TX_SAFETY_CRITICAL
|
||||
TX_SAFETY_CRITICAL_EXCEPTION_HANDLER
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_initialize_kernel_enter PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is the first ThreadX function called during */
|
||||
/* initialization. It is called from the application's "main()" */
|
||||
/* function. It is important to note that this routine never */
|
||||
/* returns. The processing of this function is relatively simple: */
|
||||
/* it calls several ThreadX initialization functions (if needed), */
|
||||
/* calls the application define function, and then invokes the */
|
||||
/* scheduler. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_high_level_initialize SMP initialization */
|
||||
/* _tx_thread_smp_current_state_set Set system state for all cores */
|
||||
/* _tx_initialize_low_level Low-level initialization */
|
||||
/* _tx_initialize_high_level High-level initialization */
|
||||
/* tx_application_define Application define function */
|
||||
/* _tx_thread_scheduler ThreadX scheduling loop */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* main Application main program */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_initialize_kernel_enter(VOID)
|
||||
{
|
||||
|
||||
ULONG other_core_status, i;
|
||||
|
||||
|
||||
/* Determine if the compiler has pre-initialized ThreadX. */
|
||||
if (_tx_thread_system_state[0] != TX_INITIALIZE_ALMOST_DONE)
|
||||
{
|
||||
|
||||
/* No, the initialization still needs to take place. */
|
||||
|
||||
/* Ensure that the system state variable is set to indicate
|
||||
initialization is in progress. Note that this variable is
|
||||
later used to represent interrupt nesting. */
|
||||
_tx_thread_smp_current_state_set(TX_INITIALIZE_IN_PROGRESS);
|
||||
|
||||
/* Call any port specific preprocessing. */
|
||||
TX_PORT_SPECIFIC_PRE_INITIALIZATION
|
||||
|
||||
/* Invoke the low-level initialization to handle all processor specific
|
||||
initialization issues. */
|
||||
_tx_initialize_low_level();
|
||||
|
||||
/* Call the high-level SMP Initialization. */
|
||||
_tx_thread_smp_high_level_initialize();
|
||||
|
||||
/* Invoke the high-level initialization to exercise all of the
|
||||
ThreadX components and the application's initialization
|
||||
function. */
|
||||
_tx_initialize_high_level();
|
||||
|
||||
/* Call any port specific post-processing. */
|
||||
TX_PORT_SPECIFIC_POST_INITIALIZATION
|
||||
}
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_INITIALIZE_KERNEL_ENTER_EXTENSION
|
||||
|
||||
/* Ensure that the system state variable is set to indicate
|
||||
initialization is in progress. Note that this variable is
|
||||
later used to represent interrupt nesting. */
|
||||
_tx_thread_system_state[0] = TX_INITIALIZE_IN_PROGRESS;
|
||||
|
||||
/* Call the application provided initialization function. Pass the
|
||||
first available memory address to it. */
|
||||
tx_application_define(_tx_initialize_unused_memory);
|
||||
|
||||
/* Call any port specific pre-scheduler processing. */
|
||||
TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION
|
||||
|
||||
/* Now wait for all cores to become ready for scheduling. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Release the other cores from initialization. */
|
||||
_tx_thread_smp_release_cores_flag = TX_TRUE;
|
||||
|
||||
/* Add all the status together... Other cores must clear their system
|
||||
state before they they are released. */
|
||||
other_core_status = ((ULONG) 0);
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
for (i = ((ULONG) 1); i < ((ULONG) TX_THREAD_SMP_MAX_CORES); i++)
|
||||
#else
|
||||
for (i = ((ULONG) 1); i < _tx_thread_smp_max_cores; i++)
|
||||
#endif
|
||||
{
|
||||
|
||||
|
||||
/* Call port-specific memory synchronization primitive. */
|
||||
TX_PORT_SPECIFIC_MEMORY_SYNCHRONIZATION
|
||||
|
||||
/* Add the states of each subsequent core. */
|
||||
other_core_status = other_core_status + _tx_thread_system_state[i];
|
||||
}
|
||||
|
||||
} while (other_core_status != ((ULONG) 0));
|
||||
|
||||
/* Set the system state in preparation for entering the thread
|
||||
scheduler. */
|
||||
_tx_thread_system_state[0] = TX_INITIALIZE_IS_FINISHED;
|
||||
|
||||
/* Call port-specific memory synchronization primitive. */
|
||||
TX_PORT_SPECIFIC_MEMORY_SYNCHRONIZATION
|
||||
|
||||
/* Enter the scheduling loop to start executing threads! */
|
||||
_tx_thread_schedule();
|
||||
|
||||
#ifdef TX_SAFETY_CRITICAL
|
||||
|
||||
/* If we ever get here, raise safety critical exception. */
|
||||
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
106
common_smp/src/tx_initialize_kernel_setup.c
Normal file
106
common_smp/src/tx_initialize_kernel_setup.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Initialize */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_initialize_kernel_setup PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is called by the compiler's startup code to make */
|
||||
/* ThreadX objects accessible to the compiler's library. If this */
|
||||
/* function is not called by the compiler, all ThreadX initialization */
|
||||
/* takes place from the kernel enter function defined previously. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_high_level_initialize SMP initialization */
|
||||
/* _tx_thread_smp_current_state_set Set system state for all cores */
|
||||
/* _tx_initialize_low_level Low-level initialization */
|
||||
/* _tx_initialize_high_level High-level initialization */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* startup code Compiler startup code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_initialize_kernel_setup(VOID)
|
||||
{
|
||||
|
||||
/* Ensure that the system state variable is set to indicate
|
||||
initialization is in progress. Note that this variable is
|
||||
later used to represent interrupt nesting. */
|
||||
_tx_thread_smp_current_state_set(TX_INITIALIZE_IN_PROGRESS);
|
||||
|
||||
/* Call any port specific preprocessing. */
|
||||
TX_PORT_SPECIFIC_PRE_INITIALIZATION
|
||||
|
||||
/* Invoke the low-level initialization to handle all processor specific
|
||||
initialization issues. */
|
||||
_tx_initialize_low_level();
|
||||
|
||||
/* Call the high-level SMP Initialization. */
|
||||
_tx_thread_smp_high_level_initialize();
|
||||
|
||||
/* Invoke the high-level initialization to exercise all of the
|
||||
ThreadX components and the application's initialization
|
||||
function. */
|
||||
_tx_initialize_high_level();
|
||||
|
||||
/* Call any port specific post-processing. */
|
||||
TX_PORT_SPECIFIC_POST_INITIALIZATION
|
||||
|
||||
/* Set the system state to indicate initialization is almost done. */
|
||||
_tx_thread_system_state[0] = TX_INITIALIZE_ALMOST_DONE;
|
||||
}
|
||||
|
||||
833
common_smp/src/tx_misra.c
Normal file
833
common_smp/src/tx_misra.c
Normal file
@@ -0,0 +1,833 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** ThreadX MISRA Compliance */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** _tx_version_id */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
#define TX_THREAD_INIT
|
||||
//CHAR _tx_version_id[100] = "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX 6.0.1 MISRA C Compliant *";
|
||||
#endif
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_trace.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size)
|
||||
{
|
||||
memset(ptr, value, size);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount)
|
||||
{
|
||||
ptr = ptr + amount;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount)
|
||||
{
|
||||
ptr = ptr - amount;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2)
|
||||
{
|
||||
|
||||
ULONG value;
|
||||
|
||||
value = ptr1 - ptr2;
|
||||
return(value);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr)
|
||||
{
|
||||
return((ULONG) ptr);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount)
|
||||
{
|
||||
ptr = ptr + amount;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount)
|
||||
{
|
||||
|
||||
ptr = ptr - amount;
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2)
|
||||
{
|
||||
ULONG value;
|
||||
|
||||
value = ptr1 - ptr2;
|
||||
return(value);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID *_tx_misra_ulong_to_pointer_convert(ULONG input)
|
||||
{
|
||||
|
||||
return((VOID *) input);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */
|
||||
/** UINT size); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, UINT size)
|
||||
{
|
||||
|
||||
ULONG *s, *d;
|
||||
UINT z;
|
||||
|
||||
s = *source;
|
||||
d = *destination;
|
||||
z = size;
|
||||
|
||||
*(d) = *(s);
|
||||
(d)++;
|
||||
(s)++;
|
||||
if ((z) > ((UINT) 1))
|
||||
{
|
||||
(z)--;
|
||||
while ((z))
|
||||
{
|
||||
*(d) = *(s);
|
||||
(d)++;
|
||||
(s)++;
|
||||
(z)--;
|
||||
}
|
||||
}
|
||||
|
||||
*source = s;
|
||||
*destination = d;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */
|
||||
/** TX_TIMER_INTERNAL **ptr2); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, TX_TIMER_INTERNAL **ptr2)
|
||||
{
|
||||
|
||||
ULONG value;
|
||||
|
||||
value = ptr1 - ptr2;
|
||||
return(value);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */
|
||||
/** **ptr1, ULONG size); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL **ptr1, ULONG amount)
|
||||
{
|
||||
ptr1 = ptr1 + amount;
|
||||
return(ptr1);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */
|
||||
/** *internal_timer, TX_TIMER **user_timer); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL *internal_timer, TX_TIMER **user_timer)
|
||||
{
|
||||
|
||||
UCHAR *working_ptr;
|
||||
TX_TIMER *temp_timer;
|
||||
|
||||
|
||||
working_ptr = (UCHAR *) internal_timer;
|
||||
|
||||
temp_timer = (TX_TIMER *) working_ptr;
|
||||
working_ptr = working_ptr - (((UCHAR *) &temp_timer -> tx_timer_internal) - ((UCHAR *) &temp_timer -> tx_timer_id));
|
||||
*user_timer = (TX_TIMER *) working_ptr;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */
|
||||
/** VOID **highest_stack); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, VOID **highest_stack)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_DISABLE
|
||||
if (((thread_ptr)) && ((thread_ptr) -> tx_thread_id == TX_THREAD_ID))
|
||||
{
|
||||
if (((ULONG *) (thread_ptr) -> tx_thread_stack_ptr) < ((ULONG *) *highest_stack))
|
||||
{
|
||||
*highest_stack = (thread_ptr) -> tx_thread_stack_ptr;
|
||||
}
|
||||
if ((*((ULONG *) (thread_ptr) -> tx_thread_stack_start) != TX_STACK_FILL) ||
|
||||
(*((ULONG *) (((UCHAR *) (thread_ptr) -> tx_thread_stack_end) + 1)) != TX_STACK_FILL) ||
|
||||
(((ULONG *) *highest_stack) < ((ULONG *) (thread_ptr) -> tx_thread_stack_start)))
|
||||
{
|
||||
TX_RESTORE
|
||||
_tx_thread_stack_error_handler((thread_ptr));
|
||||
TX_DISABLE
|
||||
}
|
||||
if (*(((ULONG *) *highest_stack) - 1) != TX_STACK_FILL)
|
||||
{
|
||||
TX_RESTORE
|
||||
_tx_thread_stack_analyze((thread_ptr));
|
||||
TX_DISABLE
|
||||
}
|
||||
}
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID _tx_misra_trace_event_insert(ULONG event_id, */
|
||||
/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */
|
||||
/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID _tx_misra_trace_event_insert(ULONG event_id, VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4, ULONG filter, ULONG time_stamp)
|
||||
{
|
||||
|
||||
TX_TRACE_BUFFER_ENTRY *trace_event_ptr;
|
||||
ULONG trace_system_state;
|
||||
ULONG trace_priority;
|
||||
TX_THREAD *trace_thread_ptr;
|
||||
|
||||
|
||||
trace_event_ptr = _tx_trace_buffer_current_ptr;
|
||||
if ((trace_event_ptr) && (_tx_trace_event_enable_bits & ((ULONG) (filter))))
|
||||
{
|
||||
TX_TRACE_PORT_EXTENSION
|
||||
trace_system_state = (ULONG) _tx_thread_system_state;
|
||||
trace_thread_ptr = _tx_thread_current_ptr;
|
||||
|
||||
if (trace_system_state == 0)
|
||||
{
|
||||
trace_priority = trace_thread_ptr -> tx_thread_priority;
|
||||
trace_priority = trace_priority | 0x80000000UL | (trace_thread_ptr -> tx_thread_preempt_threshold << 16);
|
||||
}
|
||||
else if (trace_system_state < 0xF0F0F0F0UL)
|
||||
{
|
||||
trace_priority = (ULONG) trace_thread_ptr;
|
||||
trace_thread_ptr = (TX_THREAD *) 0xFFFFFFFFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_thread_ptr = (TX_THREAD *) 0xF0F0F0F0UL;
|
||||
trace_priority = 0;
|
||||
}
|
||||
trace_event_ptr -> tx_trace_buffer_entry_thread_pointer = (ULONG) trace_thread_ptr;
|
||||
trace_event_ptr -> tx_trace_buffer_entry_thread_priority = (ULONG) trace_priority;
|
||||
trace_event_ptr -> tx_trace_buffer_entry_event_id = (ULONG) (event_id);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_time_stamp = (ULONG) (time_stamp);
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
trace_event_ptr -> tx_trace_buffer_entry_info_1 = (ULONG) (info_field_1);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_info_2 = (ULONG) (info_field_2);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_info_3 = (ULONG) (info_field_3);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_info_4 = (ULONG) (info_field_4);
|
||||
#else
|
||||
trace_event_ptr -> tx_trace_buffer_entry_information_field_1 = (ULONG) (info_field_1);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_information_field_2 = (ULONG) (info_field_2);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_information_field_3 = (ULONG) (info_field_3);
|
||||
trace_event_ptr -> tx_trace_buffer_entry_information_field_4 = (ULONG) (info_field_4);
|
||||
#endif
|
||||
trace_event_ptr++;
|
||||
if (trace_event_ptr >= _tx_trace_buffer_end_ptr)
|
||||
{
|
||||
trace_event_ptr = _tx_trace_buffer_start_ptr;
|
||||
_tx_trace_buffer_current_ptr = trace_event_ptr;
|
||||
_tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr;
|
||||
if (_tx_trace_full_notify_function)
|
||||
(_tx_trace_full_notify_function)((VOID *) _tx_trace_header_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
_tx_trace_buffer_current_ptr = trace_event_ptr;
|
||||
_tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ULONG _tx_misra_time_stamp_get(VOID); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
ULONG _tx_misra_time_stamp_get(VOID)
|
||||
{
|
||||
|
||||
/* Return time stamp. */
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** UINT _tx_misra_always_true(void); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
UINT _tx_misra_always_true(void)
|
||||
{
|
||||
return(TX_TRUE);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************/
|
||||
/******************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */
|
||||
/** */
|
||||
/******************************************************************************************/
|
||||
/******************************************************************************************/
|
||||
UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr)
|
||||
{
|
||||
|
||||
/* Return an indirect UCHAR pointer. */
|
||||
return((UCHAR **) ((VOID *) return_ptr));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
/***************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/***************************************************************************************/
|
||||
/***************************************************************************************/
|
||||
UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return an indirect UCHAR pointer. */
|
||||
return((UCHAR **) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************/
|
||||
/***********************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */
|
||||
/** */
|
||||
/***********************************************************************************/
|
||||
/***********************************************************************************/
|
||||
UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR *) ((VOID *) pool));
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************/
|
||||
/******************************************************************************************/
|
||||
/** */
|
||||
/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/******************************************************************************************/
|
||||
/******************************************************************************************/
|
||||
TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return a block pool pointer. */
|
||||
return((TX_BLOCK_POOL *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
/** */
|
||||
/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/************************************************************************************/
|
||||
/************************************************************************************/
|
||||
TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((TX_BLOCK_POOL *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************/
|
||||
/**************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/**************************************************************************************/
|
||||
/**************************************************************************************/
|
||||
UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR **) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************/
|
||||
/*****************************************************************************************/
|
||||
/** */
|
||||
/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/*****************************************************************************************/
|
||||
/*****************************************************************************************/
|
||||
TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return a byte pool pointer. */
|
||||
return((TX_BYTE_POOL *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
/***************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */
|
||||
/** */
|
||||
/***************************************************************************************/
|
||||
/***************************************************************************************/
|
||||
UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR *) ((VOID *) pool));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************/
|
||||
/*****************************************************************************************/
|
||||
/** */
|
||||
/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/*****************************************************************************************/
|
||||
/*****************************************************************************************/
|
||||
ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return an align time pointer. */
|
||||
return((ALIGN_TYPE *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************************/
|
||||
/****************************************************************************************************/
|
||||
/** */
|
||||
/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/****************************************************************************************************/
|
||||
/****************************************************************************************************/
|
||||
TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return a byte pool pointer. */
|
||||
return((TX_BYTE_POOL **) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/**************************************************************************************************/
|
||||
/** */
|
||||
/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/**************************************************************************************************/
|
||||
/**************************************************************************************************/
|
||||
TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return event flags pointer. */
|
||||
return((TX_EVENT_FLAGS_GROUP *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/** */
|
||||
/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return a ULONG pointer. */
|
||||
return((ULONG *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/** */
|
||||
/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return a mutex pointer. */
|
||||
return((TX_MUTEX *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** UINT _tx_misra_status_get(UINT status); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
UINT _tx_misra_status_get(UINT status)
|
||||
{
|
||||
|
||||
/* Return a successful status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/** */
|
||||
/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return queue pointer. */
|
||||
return((TX_QUEUE *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************************/
|
||||
/****************************************************************************************/
|
||||
/** */
|
||||
/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */
|
||||
/** */
|
||||
/****************************************************************************************/
|
||||
/****************************************************************************************/
|
||||
TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer)
|
||||
{
|
||||
|
||||
/* Return semaphore pointer. */
|
||||
return((TX_SEMAPHORE *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return a VOID pointer. */
|
||||
return((VOID *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************/
|
||||
/*********************************************************************************/
|
||||
/** */
|
||||
/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */
|
||||
/** */
|
||||
/*********************************************************************************/
|
||||
/*********************************************************************************/
|
||||
TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value)
|
||||
{
|
||||
|
||||
/* Return a thread pointer. */
|
||||
return((TX_THREAD *) ((VOID *) value));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************************/
|
||||
/***************************************************************************************************/
|
||||
/** */
|
||||
/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */
|
||||
/** */
|
||||
/***************************************************************************************************/
|
||||
/***************************************************************************************************/
|
||||
VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer)
|
||||
{
|
||||
|
||||
/* Return a void pointer. */
|
||||
return((VOID *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
/***************************************************************************************/
|
||||
/** */
|
||||
/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */
|
||||
/** */
|
||||
/***************************************************************************************/
|
||||
/***************************************************************************************/
|
||||
CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer)
|
||||
{
|
||||
|
||||
/* Return a CHAR pointer. */
|
||||
return((CHAR *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************************/
|
||||
/**********************************************************************************/
|
||||
/** */
|
||||
/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */
|
||||
/** */
|
||||
/**********************************************************************************/
|
||||
/**********************************************************************************/
|
||||
TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer)
|
||||
{
|
||||
|
||||
/* Return thread pointer. */
|
||||
return((TX_THREAD *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */
|
||||
/** */
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
/** */
|
||||
/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/************************************************************************************************/
|
||||
/************************************************************************************************/
|
||||
TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return an object entry pointer. */
|
||||
return((TX_TRACE_OBJECT_ENTRY *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************************/
|
||||
/******************************************************************************************/
|
||||
/** */
|
||||
/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/******************************************************************************************/
|
||||
/******************************************************************************************/
|
||||
TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return a trace header pointer. */
|
||||
return((TX_TRACE_HEADER *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************/
|
||||
/***********************************************************************************************/
|
||||
/** */
|
||||
/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */
|
||||
/** */
|
||||
/***********************************************************************************************/
|
||||
/***********************************************************************************************/
|
||||
TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return a trace buffer entry pointer. */
|
||||
return((TX_TRACE_BUFFER_ENTRY *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************/
|
||||
/***********************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */
|
||||
/** */
|
||||
/***********************************************************************************************/
|
||||
/***********************************************************************************************/
|
||||
UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************************************/
|
||||
/***********************************************************************************************/
|
||||
/** */
|
||||
/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */
|
||||
/** */
|
||||
/***********************************************************************************************/
|
||||
/***********************************************************************************************/
|
||||
UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer)
|
||||
{
|
||||
|
||||
/* Return a UCHAR pointer. */
|
||||
return((UCHAR *) ((VOID *) pointer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
313
common_smp/src/tx_mutex_cleanup.c
Normal file
313
common_smp/src/tx_mutex_cleanup.c
Normal file
@@ -0,0 +1,313 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_cleanup PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes mutex timeout and thread terminate */
|
||||
/* actions that require the mutex data structures to be cleaned */
|
||||
/* up. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to suspended thread's */
|
||||
/* control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_timeout Thread timeout processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* _tx_thread_wait_abort Thread wait abort processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_mutex_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_MUTEX *mutex_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts to remove the suspended thread from the mutex. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the cleanup is still required. */
|
||||
if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_mutex_cleanup))
|
||||
{
|
||||
|
||||
/* Check for valid suspension sequence. */
|
||||
if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
|
||||
{
|
||||
|
||||
/* Setup pointer to mutex control block. */
|
||||
mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
|
||||
/* Check for NULL mutex pointer. */
|
||||
if (mutex_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Determine if the mutex ID is valid. */
|
||||
if (mutex_ptr -> tx_mutex_id == TX_MUTEX_ID)
|
||||
{
|
||||
|
||||
/* Determine if there are any thread suspensions. */
|
||||
if (mutex_ptr -> tx_mutex_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
#else
|
||||
|
||||
/* Setup pointer to mutex control block. */
|
||||
mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
#endif
|
||||
|
||||
/* Yes, we still have thread suspension! */
|
||||
|
||||
/* Clear the suspension cleanup flag. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
mutex_ptr -> tx_mutex_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = mutex_ptr -> tx_mutex_suspended_count;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
mutex_ptr -> tx_mutex_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same suspension list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Determine if we need to update the head pointer. */
|
||||
if (mutex_ptr -> tx_mutex_suspension_list == thread_ptr)
|
||||
{
|
||||
|
||||
/* Update the list head pointer. */
|
||||
mutex_ptr -> tx_mutex_suspension_list = next_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we need to determine if this cleanup is from a terminate, timeout,
|
||||
or from a wait abort. */
|
||||
if (thread_ptr -> tx_thread_state == TX_MUTEX_SUSP)
|
||||
{
|
||||
|
||||
/* Timeout condition and the thread still suspended on the mutex.
|
||||
Setup return error status and resume the thread. */
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total timeouts counter. */
|
||||
_tx_mutex_performance_timeout_count++;
|
||||
|
||||
/* Increment the number of timeouts on this semaphore. */
|
||||
mutex_ptr -> tx_mutex_performance_timeout_count++;
|
||||
#endif
|
||||
|
||||
/* Setup return status. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_NOT_AVAILABLE;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_thread_release PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function releases all mutexes owned by the thread. This */
|
||||
/* function is called when the thread completes or is terminated. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread's control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_mutex_put Release the mutex */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_shell_entry Thread completion processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_mutex_thread_release(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_MUTEX *mutex_ptr;
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
UINT status;
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Loop to look at all the mutexes. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Pickup the mutex head pointer. */
|
||||
mutex_ptr = thread_ptr -> tx_thread_owned_mutex_list;
|
||||
|
||||
/* Determine if there is a mutex. */
|
||||
if (mutex_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, set the ownership count to 1. */
|
||||
mutex_ptr -> tx_mutex_ownership_count = ((UINT) 1);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
/* Release the mutex. */
|
||||
do
|
||||
{
|
||||
status = _tx_mutex_put(mutex_ptr);
|
||||
} while (status != TX_SUCCESS);
|
||||
#else
|
||||
_tx_mutex_put(mutex_ptr);
|
||||
#endif
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Move to the next mutex. */
|
||||
mutex_ptr = thread_ptr -> tx_thread_owned_mutex_list;
|
||||
}
|
||||
} while (mutex_ptr != TX_NULL);
|
||||
|
||||
/* Restore preemption. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
146
common_smp/src/tx_mutex_create.c
Normal file
146
common_smp/src/tx_mutex_create.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_create PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a mutex with optional priority inheritance as */
|
||||
/* specified in this call. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block*/
|
||||
/* name_ptr Pointer to mutex name */
|
||||
/* inherit Priority inheritance option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_MUTEX *next_mutex;
|
||||
TX_MUTEX *previous_mutex;
|
||||
|
||||
|
||||
/* Initialize mutex control block to all zeros. */
|
||||
TX_MEMSET(mutex_ptr, 0, (sizeof(TX_MUTEX)));
|
||||
|
||||
/* Setup the basic mutex fields. */
|
||||
mutex_ptr -> tx_mutex_name = name_ptr;
|
||||
mutex_ptr -> tx_mutex_inherit = inherit;
|
||||
|
||||
/* Disable interrupts to place the mutex on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Setup the mutex ID to make it valid. */
|
||||
mutex_ptr -> tx_mutex_id = TX_MUTEX_ID;
|
||||
|
||||
/* Setup the thread mutex release function pointer. */
|
||||
_tx_thread_mutex_release = &(_tx_mutex_thread_release);
|
||||
|
||||
/* Place the mutex on the list of created mutexes. First,
|
||||
check for an empty list. */
|
||||
if (_tx_mutex_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created mutex list is empty. Add mutex to empty list. */
|
||||
_tx_mutex_created_ptr = mutex_ptr;
|
||||
mutex_ptr -> tx_mutex_created_next = mutex_ptr;
|
||||
mutex_ptr -> tx_mutex_created_previous = mutex_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_mutex = _tx_mutex_created_ptr;
|
||||
previous_mutex = next_mutex -> tx_mutex_created_previous;
|
||||
|
||||
/* Place the new mutex in the list. */
|
||||
next_mutex -> tx_mutex_created_previous = mutex_ptr;
|
||||
previous_mutex -> tx_mutex_created_next = mutex_ptr;
|
||||
|
||||
/* Setup this mutex's next and previous created links. */
|
||||
mutex_ptr -> tx_mutex_created_previous = previous_mutex;
|
||||
mutex_ptr -> tx_mutex_created_next = next_mutex;
|
||||
}
|
||||
|
||||
/* Increment the ownership count. */
|
||||
_tx_mutex_created_count++;
|
||||
|
||||
/* Optional mutex create extended processing. */
|
||||
TX_MUTEX_CREATE_EXTENSION(mutex_ptr)
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_MUTEX, mutex_ptr, name_ptr, inherit, 0)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_CREATE, mutex_ptr, inherit, TX_POINTER_TO_ULONG_CONVERT(&next_mutex), 0, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_CREATE_INSERT
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
243
common_smp/src/tx_mutex_delete.c
Normal file
243
common_smp/src/tx_mutex_delete.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function deletes the specified mutex. All threads */
|
||||
/* suspended on the mutex are resumed with the TX_DELETED status */
|
||||
/* code. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_mutex_put Release an owned mutex */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_delete(TX_MUTEX *mutex_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *owner_thread;
|
||||
UINT suspended_count;
|
||||
TX_MUTEX *next_mutex;
|
||||
TX_MUTEX *previous_mutex;
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
UINT status;
|
||||
#endif
|
||||
|
||||
/* Disable interrupts to remove the mutex from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_DELETE, mutex_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Optional mutex delete extended processing. */
|
||||
TX_MUTEX_DELETE_EXTENSION(mutex_ptr)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(mutex_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_DELETE_INSERT
|
||||
|
||||
/* Clear the mutex ID to make it invalid. */
|
||||
mutex_ptr -> tx_mutex_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the created count. */
|
||||
_tx_mutex_created_count--;
|
||||
|
||||
/* See if the mutex is the only one on the list. */
|
||||
if (_tx_mutex_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created mutex, just set the created list to NULL. */
|
||||
_tx_mutex_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_mutex = mutex_ptr -> tx_mutex_created_next;
|
||||
previous_mutex = mutex_ptr -> tx_mutex_created_previous;
|
||||
next_mutex -> tx_mutex_created_previous = previous_mutex;
|
||||
previous_mutex -> tx_mutex_created_next = next_mutex;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_mutex_created_ptr == mutex_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_mutex_created_ptr = next_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Pickup the suspension information. */
|
||||
thread_ptr = mutex_ptr -> tx_mutex_suspension_list;
|
||||
mutex_ptr -> tx_mutex_suspension_list = TX_NULL;
|
||||
suspended_count = mutex_ptr -> tx_mutex_suspended_count;
|
||||
mutex_ptr -> tx_mutex_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
|
||||
/* Determine if the mutex is currently on a thread's ownership list. */
|
||||
|
||||
/* Setup pointer to owner of mutex. */
|
||||
owner_thread = mutex_ptr -> tx_mutex_owner;
|
||||
|
||||
/* Determine if there is a valid thread pointer. */
|
||||
if (owner_thread != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, remove this mutex from the owned list. */
|
||||
|
||||
/* Set the ownership count to 1. */
|
||||
mutex_ptr -> tx_mutex_ownership_count = ((UINT) 1);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
/* Release the mutex. */
|
||||
do
|
||||
{
|
||||
status = _tx_mutex_put(mutex_ptr);
|
||||
} while (status != TX_SUCCESS);
|
||||
#else
|
||||
_tx_mutex_put(mutex_ptr);
|
||||
#endif
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the mutex list to resume any and all threads suspended
|
||||
on this mutex. */
|
||||
while (suspended_count != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_DELETED. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_DELETED;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move to next thread. */
|
||||
thread_ptr = next_thread;
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_MUTEX_DELETE_PORT_COMPLETION(mutex_ptr)
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release previous preempt disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
409
common_smp/src/tx_mutex_get.c
Normal file
409
common_smp/src/tx_mutex_get.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function gets the specified mutex. If the calling thread */
|
||||
/* already owns the mutex, an ownership count is simply increased. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Suspend thread service */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* _tx_mutex_priority_change Inherit thread priority */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_MUTEX *next_mutex;
|
||||
TX_MUTEX *previous_mutex;
|
||||
TX_THREAD *mutex_owner;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Disable interrupts to get an instance from the mutex. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total mutex get counter. */
|
||||
_tx_mutex_performance_get_count++;
|
||||
|
||||
/* Increment the number of attempts to get this mutex. */
|
||||
mutex_ptr -> tx_mutex_performance_get_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_GET, mutex_ptr, wait_option, TX_POINTER_TO_ULONG_CONVERT(mutex_ptr -> tx_mutex_owner), mutex_ptr -> tx_mutex_ownership_count, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_GET_INSERT
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Determine if this mutex is available. */
|
||||
if (mutex_ptr -> tx_mutex_ownership_count == ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Set the ownership count to 1. */
|
||||
mutex_ptr -> tx_mutex_ownership_count = ((UINT) 1);
|
||||
|
||||
/* Remember that the calling thread owns the mutex. */
|
||||
mutex_ptr -> tx_mutex_owner = thread_ptr;
|
||||
|
||||
/* Determine if the thread pointer is valid. */
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Determine if priority inheritance is required. */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Remember the current priority of thread. */
|
||||
mutex_ptr -> tx_mutex_original_priority = thread_ptr -> tx_thread_priority;
|
||||
|
||||
/* Setup the highest priority waiting thread. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = ((UINT) TX_MAX_PRIORITIES);
|
||||
}
|
||||
|
||||
/* Pickup next mutex pointer, which is the head of the list. */
|
||||
next_mutex = thread_ptr -> tx_thread_owned_mutex_list;
|
||||
|
||||
/* Determine if this thread owns any other mutexes that have priority inheritance. */
|
||||
if (next_mutex != TX_NULL)
|
||||
{
|
||||
|
||||
/* Non-empty list. Link up the mutex. */
|
||||
|
||||
/* Pickup the next and previous mutex pointer. */
|
||||
previous_mutex = next_mutex -> tx_mutex_owned_previous;
|
||||
|
||||
/* Place the owned mutex in the list. */
|
||||
next_mutex -> tx_mutex_owned_previous = mutex_ptr;
|
||||
previous_mutex -> tx_mutex_owned_next = mutex_ptr;
|
||||
|
||||
/* Setup this mutex's next and previous created links. */
|
||||
mutex_ptr -> tx_mutex_owned_previous = previous_mutex;
|
||||
mutex_ptr -> tx_mutex_owned_next = next_mutex;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* The owned mutex list is empty. Add mutex to empty list. */
|
||||
thread_ptr -> tx_thread_owned_mutex_list = mutex_ptr;
|
||||
mutex_ptr -> tx_mutex_owned_next = mutex_ptr;
|
||||
mutex_ptr -> tx_mutex_owned_previous = mutex_ptr;
|
||||
}
|
||||
|
||||
/* Increment the number of mutexes owned counter. */
|
||||
thread_ptr -> tx_thread_owned_mutex_count++;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Otherwise, see if the owning thread is trying to obtain the same mutex. */
|
||||
else if (mutex_ptr -> tx_mutex_owner == thread_ptr)
|
||||
{
|
||||
|
||||
/* The owning thread is requesting the mutex again, just
|
||||
increment the ownership count. */
|
||||
mutex_ptr -> tx_mutex_ownership_count++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if the request specifies suspension. */
|
||||
if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_NOT_AVAILABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
/* Pickup the mutex owner. */
|
||||
mutex_owner = mutex_ptr -> tx_mutex_owner;
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total mutex suspension counter. */
|
||||
_tx_mutex_performance_suspension_count++;
|
||||
|
||||
/* Increment the number of suspensions on this mutex. */
|
||||
mutex_ptr -> tx_mutex_performance_suspension_count++;
|
||||
|
||||
/* Determine if a priority inversion is present. */
|
||||
if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, priority inversion is present! */
|
||||
|
||||
/* Increment the total mutex priority inversions counter. */
|
||||
_tx_mutex_performance_priority_inversion_count++;
|
||||
|
||||
/* Increment the number of priority inversions on this mutex. */
|
||||
mutex_ptr -> tx_mutex_performance_priority_inversion_count++;
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the number of total thread priority inversions. */
|
||||
_tx_thread_performance_priority_inversion_count++;
|
||||
|
||||
/* Increment the number of priority inversions for this thread. */
|
||||
thread_ptr -> tx_thread_performance_priority_inversion_count++;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_mutex_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this mutex control
|
||||
block. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) mutex_ptr;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (mutex_ptr -> tx_mutex_suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
mutex_ptr -> tx_mutex_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = mutex_ptr -> tx_mutex_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Increment the suspension count. */
|
||||
mutex_ptr -> tx_mutex_suspended_count++;
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_MUTEX_SUSP;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Determine if we need to raise the priority of the thread
|
||||
owning the mutex. */
|
||||
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 > thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Remember this priority. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = thread_ptr -> tx_thread_priority;
|
||||
}
|
||||
|
||||
/* Determine if we have to update inherit priority level of the mutex owner. */
|
||||
if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_inherit_priority)
|
||||
{
|
||||
|
||||
/* Remember the new priority inheritance priority. */
|
||||
mutex_owner -> tx_thread_inherit_priority = thread_ptr -> tx_thread_priority;
|
||||
}
|
||||
|
||||
/* Priority inheritance is requested, check to see if the thread that owns the mutex is lower priority. */
|
||||
if (mutex_owner -> tx_thread_priority > thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, raise the suspended, owning thread's priority to that
|
||||
of the current thread. */
|
||||
_tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total mutex priority inheritance counter. */
|
||||
_tx_mutex_performance__priority_inheritance_count++;
|
||||
|
||||
/* Increment the number of priority inheritance situations on this mutex. */
|
||||
mutex_ptr -> tx_mutex_performance__priority_inheritance_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Determine if we need to raise the priority of the thread
|
||||
owning the mutex. */
|
||||
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 > thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Remember this priority. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = thread_ptr -> tx_thread_priority;
|
||||
}
|
||||
|
||||
/* Determine if we have to update inherit priority level of the mutex owner. */
|
||||
if (thread_ptr -> tx_thread_priority < mutex_owner -> tx_thread_inherit_priority)
|
||||
{
|
||||
|
||||
/* Remember the new priority inheritance priority. */
|
||||
mutex_owner -> tx_thread_inherit_priority = thread_ptr -> tx_thread_priority;
|
||||
}
|
||||
|
||||
/* Priority inheritance is requested, check to see if the thread that owns the mutex is lower priority. */
|
||||
if (mutex_owner -> tx_thread_priority > thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, raise the suspended, owning thread's priority to that
|
||||
of the current thread. */
|
||||
_tx_mutex_priority_change(mutex_owner, thread_ptr -> tx_thread_priority);
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total mutex priority inheritance counter. */
|
||||
_tx_mutex_performance__priority_inheritance_count++;
|
||||
|
||||
/* Increment the number of priority inheritance situations on this mutex. */
|
||||
mutex_ptr -> tx_mutex_performance__priority_inheritance_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Immediate return, return error completion. */
|
||||
status = TX_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
147
common_smp/src/tx_mutex_info_get.c
Normal file
147
common_smp/src/tx_mutex_info_get.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified mutex. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block */
|
||||
/* name Destination for the mutex name */
|
||||
/* count Destination for the owner count */
|
||||
/* owner Destination for the owner's */
|
||||
/* thread control block pointer */
|
||||
/* first_suspended Destination for pointer of first */
|
||||
/* thread suspended on the mutex */
|
||||
/* suspended_count Destination for suspended count */
|
||||
/* next_mutex Destination for pointer to next */
|
||||
/* mutex on the created list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_info_get(TX_MUTEX *mutex_ptr, CHAR **name, ULONG *count, TX_THREAD **owner,
|
||||
TX_THREAD **first_suspended, ULONG *suspended_count,
|
||||
TX_MUTEX **next_mutex)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_INFO_GET, mutex_ptr, 0, 0, 0, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the mutex. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = mutex_ptr -> tx_mutex_name;
|
||||
}
|
||||
|
||||
/* Retrieve the current ownership count of the mutex. */
|
||||
if (count != TX_NULL)
|
||||
{
|
||||
|
||||
*count = ((ULONG) mutex_ptr -> tx_mutex_ownership_count);
|
||||
}
|
||||
|
||||
/* Retrieve the current owner of the mutex. */
|
||||
if (owner != TX_NULL)
|
||||
{
|
||||
|
||||
*owner = mutex_ptr -> tx_mutex_owner;
|
||||
}
|
||||
|
||||
/* Retrieve the first thread suspended on this mutex. */
|
||||
if (first_suspended != TX_NULL)
|
||||
{
|
||||
|
||||
*first_suspended = mutex_ptr -> tx_mutex_suspension_list;
|
||||
}
|
||||
|
||||
/* Retrieve the number of threads suspended on this mutex. */
|
||||
if (suspended_count != TX_NULL)
|
||||
{
|
||||
|
||||
*suspended_count = (ULONG) mutex_ptr -> tx_mutex_suspended_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to the next mutex created. */
|
||||
if (next_mutex != TX_NULL)
|
||||
{
|
||||
|
||||
*next_mutex = mutex_ptr -> tx_mutex_created_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
141
common_smp/src/tx_mutex_initialize.c
Normal file
141
common_smp/src/tx_mutex_initialize.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
#ifndef TX_INLINE_INITIALIZATION
|
||||
|
||||
/* Locate mutex component data in this file. */
|
||||
|
||||
/* Define the head pointer of the created mutex list. */
|
||||
|
||||
TX_MUTEX * _tx_mutex_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created mutexes. */
|
||||
|
||||
ULONG _tx_mutex_created_count;
|
||||
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of mutex puts. */
|
||||
|
||||
ULONG _tx_mutex_performance_put_count;
|
||||
|
||||
|
||||
/* Define the total number of mutex gets. */
|
||||
|
||||
ULONG _tx_mutex_performance_get_count;
|
||||
|
||||
|
||||
/* Define the total number of mutex suspensions. */
|
||||
|
||||
ULONG _tx_mutex_performance_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of mutex timeouts. */
|
||||
|
||||
ULONG _tx_mutex_performance_timeout_count;
|
||||
|
||||
|
||||
/* Define the total number of priority inversions. */
|
||||
|
||||
ULONG _tx_mutex_performance_priority_inversion_count;
|
||||
|
||||
|
||||
/* Define the total number of priority inheritance conditions. */
|
||||
|
||||
ULONG _tx_mutex_performance__priority_inheritance_count;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_initialize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the mutex component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_mutex_initialize(VOID)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the head pointer of the created mutexes list and the
|
||||
number of mutexes created. */
|
||||
_tx_mutex_created_ptr = TX_NULL;
|
||||
_tx_mutex_created_count = TX_EMPTY;
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize the mutex performance counters. */
|
||||
_tx_mutex_performance_put_count = ((ULONG) 0);
|
||||
_tx_mutex_performance_get_count = ((ULONG) 0);
|
||||
_tx_mutex_performance_suspension_count = ((ULONG) 0);
|
||||
_tx_mutex_performance_timeout_count = ((ULONG) 0);
|
||||
_tx_mutex_performance_priority_inversion_count = ((ULONG) 0);
|
||||
_tx_mutex_performance__priority_inheritance_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
230
common_smp/src/tx_mutex_performance_info_get.c
Normal file
230
common_smp/src/tx_mutex_performance_info_get.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_mutex.h"
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* mutex. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block */
|
||||
/* puts Destination for the number of */
|
||||
/* puts on to this mutex */
|
||||
/* gets Destination for the number of */
|
||||
/* gets on this mutex */
|
||||
/* suspensions Destination for the number of */
|
||||
/* suspensions on this mutex */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* on this mutex */
|
||||
/* inversions Destination for number of priority*/
|
||||
/* inversions on this mutex */
|
||||
/* inheritances Destination for number of priority*/
|
||||
/* inheritances on this mutex */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_performance_info_get(TX_MUTEX *mutex_ptr, ULONG *puts, ULONG *gets,
|
||||
ULONG *suspensions, ULONG *timeouts, ULONG *inversions, ULONG *inheritances)
|
||||
{
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (mutex_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Mutex pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the mutex ID is invalid. */
|
||||
else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID)
|
||||
{
|
||||
|
||||
/* Mutex pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PERFORMANCE_INFO_GET, mutex_ptr, 0, 0, 0, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the number of puts on this mutex. */
|
||||
if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
*puts = mutex_ptr -> tx_mutex_performance_put_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of gets on this mutex. */
|
||||
if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
*gets = mutex_ptr -> tx_mutex_performance_get_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of suspensions on this mutex. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = mutex_ptr -> tx_mutex_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of timeouts on this mutex. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = mutex_ptr -> tx_mutex_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of priority inversions on this mutex. */
|
||||
if (inversions != TX_NULL)
|
||||
{
|
||||
|
||||
*inversions = mutex_ptr -> tx_mutex_performance_priority_inversion_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of priority inheritances on this mutex. */
|
||||
if (inheritances != TX_NULL)
|
||||
{
|
||||
|
||||
*inheritances = mutex_ptr -> tx_mutex_performance__priority_inheritance_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
#else
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (mutex_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (inversions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (inheritances != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
205
common_smp/src/tx_mutex_performance_system_info_get.c
Normal file
205
common_smp/src/tx_mutex_performance_system_info_get.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_mutex.h"
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves system mutex performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* puts Destination for total number of */
|
||||
/* mutex puts */
|
||||
/* gets Destination for total number of */
|
||||
/* mutex gets */
|
||||
/* suspensions Destination for total number of */
|
||||
/* mutex suspensions */
|
||||
/* timeouts Destination for total number of */
|
||||
/* mutex timeouts */
|
||||
/* inversions Destination for total number of */
|
||||
/* mutex priority inversions */
|
||||
/* inheritances Destination for total number of */
|
||||
/* mutex priority inheritances */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_performance_system_info_get(ULONG *puts, ULONG *gets, ULONG *suspensions,
|
||||
ULONG *timeouts, ULONG *inversions, ULONG *inheritances)
|
||||
{
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the total number of mutex puts. */
|
||||
if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
*puts = _tx_mutex_performance_put_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of mutex gets. */
|
||||
if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
*gets = _tx_mutex_performance_get_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of mutex suspensions. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = _tx_mutex_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of mutex timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_mutex_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of mutex priority inversions. */
|
||||
if (inversions != TX_NULL)
|
||||
{
|
||||
|
||||
*inversions = _tx_mutex_performance_priority_inversion_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of mutex priority inheritances. */
|
||||
if (inheritances != TX_NULL)
|
||||
{
|
||||
|
||||
*inheritances = _tx_mutex_performance__priority_inheritance_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (inversions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (inheritances != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
265
common_smp/src/tx_mutex_prioritize.c
Normal file
265
common_smp/src/tx_mutex_prioritize.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_prioritize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places the highest priority suspended thread at the */
|
||||
/* front of the suspension list. All other threads remain in the same */
|
||||
/* FIFO suspension order. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_prioritize(TX_MUTEX *mutex_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *priority_thread_ptr;
|
||||
TX_THREAD *head_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT list_changed;
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
UINT status;
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PRIORITIZE, mutex_ptr, mutex_ptr -> tx_mutex_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_PRIORITIZE_INSERT
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = mutex_ptr -> tx_mutex_suspended_count;
|
||||
|
||||
/* Determine if there are fewer than 2 suspended threads. */
|
||||
if (suspended_count < ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Determine if there how many threads are suspended on this mutex. */
|
||||
else if (suspended_count == ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Pickup the head pointer and the next pointer. */
|
||||
head_ptr = mutex_ptr -> tx_mutex_suspension_list;
|
||||
next_thread = head_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Determine if the next suspended thread has a higher priority. */
|
||||
if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
|
||||
{
|
||||
|
||||
/* Yes, move the list head to the next thread. */
|
||||
mutex_ptr -> tx_mutex_suspension_list = next_thread;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = mutex_ptr -> tx_mutex_suspension_list;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the list changed flag to false. */
|
||||
list_changed = TX_FALSE;
|
||||
|
||||
/* Search through the list to find the highest priority thread. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Is the current thread higher priority? */
|
||||
if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, remember that this thread is the highest priority. */
|
||||
priority_thread_ptr = thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if any changes to the list have occurred while
|
||||
interrupts were enabled. */
|
||||
|
||||
/* Is the list head the same? */
|
||||
if (head_ptr != mutex_ptr -> tx_mutex_suspension_list)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is the suspended count the same? */
|
||||
if (suspended_count != mutex_ptr -> tx_mutex_suspended_count)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the list has changed. */
|
||||
if (list_changed == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Move the thread pointer to the next thread. */
|
||||
thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = mutex_ptr -> tx_mutex_suspension_list;
|
||||
suspended_count = mutex_ptr -> tx_mutex_suspended_count;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Reset the list changed flag. */
|
||||
list_changed = TX_FALSE;
|
||||
}
|
||||
|
||||
} while (thread_ptr != head_ptr);
|
||||
|
||||
/* Release preemption. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Now determine if the highest priority thread is at the front
|
||||
of the list. */
|
||||
if (priority_thread_ptr != head_ptr)
|
||||
{
|
||||
|
||||
/* No, we need to move the highest priority suspended thread to the
|
||||
front of the list. */
|
||||
|
||||
/* First, remove the highest priority thread by updating the
|
||||
adjacent suspended threads. */
|
||||
next_thread = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = priority_thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Now, link the highest priority thread at the front of the list. */
|
||||
previous_thread = head_ptr -> tx_thread_suspended_previous;
|
||||
priority_thread_ptr -> tx_thread_suspended_next = head_ptr;
|
||||
priority_thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = priority_thread_ptr;
|
||||
head_ptr -> tx_thread_suspended_previous = priority_thread_ptr;
|
||||
|
||||
/* Move the list head pointer to the highest priority suspended thread. */
|
||||
mutex_ptr -> tx_mutex_suspension_list = priority_thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
|
||||
/* Initialize status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Define extended processing option. */
|
||||
status = TX_MUTEX_PRIORITIZE_MISRA_EXTENSION(status);
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#else
|
||||
|
||||
/* Return successful completion. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
487
common_smp/src/tx_mutex_priority_change.c
Normal file
487
common_smp/src/tx_mutex_priority_change.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_priority_change PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function changes the priority of the specified thread for the */
|
||||
/* priority inheritance option of the mutex service. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to suspend */
|
||||
/* new_priority New thread priority */
|
||||
/* new_threshold New preemption-threshold */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list */
|
||||
/* Rebalance the execution list */
|
||||
/* _tx_thread_smp_simple_priority_change */
|
||||
/* Change priority */
|
||||
/* _tx_thread_system_resume Resume thread */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* _tx_thread_system_suspend Suspend thread */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_mutex_get Inherit priority */
|
||||
/* _tx_mutex_put Restore previous priority */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_THREAD *execute_ptr;
|
||||
UINT core_index;
|
||||
UINT original_priority;
|
||||
UINT lowest_priority;
|
||||
TX_THREAD *original_pt_thread;
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
TX_THREAD *new_pt_thread;
|
||||
UINT priority;
|
||||
ULONG priority_bit;
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
UINT map_index;
|
||||
#endif
|
||||
#endif
|
||||
UINT finished;
|
||||
|
||||
|
||||
/* Default finished to false. */
|
||||
finished = TX_FALSE;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Lockout interrupts while the thread is being suspended. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
/* Determine if there is anything to do. */
|
||||
if (thread_ptr -> tx_thread_priority == new_priority)
|
||||
{
|
||||
|
||||
if (thread_ptr -> tx_thread_preempt_threshold == new_priority)
|
||||
{
|
||||
|
||||
/* Set the finished flag to true. */
|
||||
finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if there is still more to do. */
|
||||
if (finished == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Default the execute pointer to NULL. */
|
||||
execute_ptr = TX_NULL;
|
||||
|
||||
/* Determine if this thread is currently ready. */
|
||||
if (thread_ptr -> tx_thread_state != TX_READY)
|
||||
{
|
||||
|
||||
/* Change thread priority to the new mutex priority-inheritance priority. */
|
||||
thread_ptr -> tx_thread_priority = new_priority;
|
||||
|
||||
/* Determine how to setup the thread's preemption-threshold. */
|
||||
if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
|
||||
{
|
||||
|
||||
/* Change thread preemption-threshold to the user's preemption-threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change the thread preemption-threshold to the new threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_priority;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Pickup the core index. */
|
||||
core_index = thread_ptr -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Save the original priority. */
|
||||
original_priority = thread_ptr -> tx_thread_priority;
|
||||
|
||||
/* Determine if this thread is the currently executing thread. */
|
||||
if (thread_ptr == _tx_thread_execute_ptr[core_index])
|
||||
{
|
||||
|
||||
/* Yes, this thread is scheduled. */
|
||||
|
||||
/* Remember this thread as the currently executing thread. */
|
||||
execute_ptr = thread_ptr;
|
||||
|
||||
/* Determine if the thread is being set to a higher-priority and it does't have
|
||||
preemption-threshold set. */
|
||||
if (new_priority < thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Check for preemption-threshold. */
|
||||
if (thread_ptr -> tx_thread_user_priority == thread_ptr -> tx_thread_user_preempt_threshold)
|
||||
{
|
||||
|
||||
/* Simple case, remove the thread from the current priority list and place in
|
||||
the higher priority list. */
|
||||
_tx_thread_smp_simple_priority_change(thread_ptr, new_priority);
|
||||
|
||||
/* Set the finished flag to true. */
|
||||
finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Thread is not currently executing, so it can just be moved to the lower priority in the list. */
|
||||
|
||||
/* Determine if the thread is being set to a lower-priority and it does't have
|
||||
preemption-threshold set. */
|
||||
if (new_priority > thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Check for preemption-threshold. */
|
||||
if (thread_ptr -> tx_thread_user_priority == thread_ptr -> tx_thread_user_preempt_threshold)
|
||||
{
|
||||
|
||||
/* Simple case, remove the thread from the current priority list and place in
|
||||
the lower priority list. */
|
||||
if (new_priority < thread_ptr -> tx_thread_user_priority)
|
||||
{
|
||||
|
||||
/* Use the new priority. */
|
||||
_tx_thread_smp_simple_priority_change(thread_ptr, new_priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Use the user priority. */
|
||||
_tx_thread_smp_simple_priority_change(thread_ptr, thread_ptr -> tx_thread_user_priority);
|
||||
}
|
||||
|
||||
/* Set the finished flag to true. */
|
||||
finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now determine if we are finished. */
|
||||
if (finished == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Save the original preemption-threshold thread. */
|
||||
original_pt_thread = _tx_thread_preemption__threshold_scheduled;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
|
||||
|
||||
/* At this point, the preempt disable flag is still set, so we still have
|
||||
protection against all preemption. */
|
||||
|
||||
/* Determine how to setup the thread's priority. */
|
||||
if (thread_ptr -> tx_thread_user_priority < new_priority)
|
||||
{
|
||||
|
||||
/* Change thread priority to the user's priority. */
|
||||
thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_user_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change thread priority to the new mutex priority-inheritance priority. */
|
||||
thread_ptr -> tx_thread_priority = new_priority;
|
||||
}
|
||||
|
||||
/* Determine how to setup the thread's preemption-threshold. */
|
||||
if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
|
||||
{
|
||||
|
||||
/* Change thread preemption-threshold to the user's preemption-threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change the thread preemption-threshold to the new threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_priority;
|
||||
}
|
||||
|
||||
/* Resume the thread with the new priority. */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Decrement the preempt disable flag. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#else
|
||||
|
||||
/* Increment the preempt disable flag. */
|
||||
_tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 2);
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((UINT) 0);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* The thread is ready and must first be removed from the list. Call the
|
||||
system suspend function to accomplish this. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
|
||||
/* Lockout interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* At this point, the preempt disable flag is still set, so we still have
|
||||
protection against all preemption. */
|
||||
|
||||
/* Determine how to setup the thread's priority. */
|
||||
if (thread_ptr -> tx_thread_user_priority < new_priority)
|
||||
{
|
||||
|
||||
/* Change thread priority to the user's priority. */
|
||||
thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_user_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change thread priority to the new mutex priority-inheritance priority. */
|
||||
thread_ptr -> tx_thread_priority = new_priority;
|
||||
}
|
||||
|
||||
/* Determine how to setup the thread's preemption-threshold. */
|
||||
if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority)
|
||||
{
|
||||
|
||||
/* Change thread preemption-threshold to the user's preemption-threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change the thread preemption-threshold to the new threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_priority;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread with the new priority. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_MUTEX_PRIORITY_CHANGE_EXTENSION
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
/* Determine if the thread was previously executing. */
|
||||
if (thread_ptr == execute_ptr)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
/* Determine if preemption-threshold is in force at the new priority level. */
|
||||
if (_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] == TX_NULL)
|
||||
{
|
||||
|
||||
/* Ensure that this thread is placed at the front of the priority list. */
|
||||
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Ensure that this thread is placed at the front of the priority list. */
|
||||
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pickup the core index. */
|
||||
core_index = thread_ptr -> tx_thread_smp_core_mapped;
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
/* Pickup the next thread to execute. */
|
||||
if (core_index < ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
#else
|
||||
|
||||
/* Pickup the next thread to execute. */
|
||||
if (core_index < _tx_thread_smp_max_cores)
|
||||
#endif
|
||||
{
|
||||
|
||||
/* Determine if this thread is not the next thread to execute. */
|
||||
if (thread_ptr != _tx_thread_execute_ptr[core_index])
|
||||
{
|
||||
|
||||
/* Now determine if this thread was previously executing thread. */
|
||||
if (thread_ptr == execute_ptr)
|
||||
{
|
||||
|
||||
/* Determine if we moved to a lower priority. If so, move the thread to the front of the priority list. */
|
||||
if (original_priority < new_priority)
|
||||
{
|
||||
|
||||
/* Make sure the thread is still ready. */
|
||||
if (thread_ptr -> tx_thread_state == TX_READY)
|
||||
{
|
||||
|
||||
/* Determine the lowest priority scheduled thread. */
|
||||
lowest_priority = _tx_thread_smp_lowest_priority_get();
|
||||
|
||||
/* Determine if this thread has a higher or same priority as the lowest priority
|
||||
in the list. */
|
||||
if (thread_ptr -> tx_thread_priority <= lowest_priority)
|
||||
{
|
||||
|
||||
/* Yes, we need to rebalance to make it possible for this thread to execute. */
|
||||
|
||||
/* Determine if the thread with preemption-threshold thread has changed... and is
|
||||
not the scheduled thread. */
|
||||
if ((original_pt_thread != _tx_thread_preemption__threshold_scheduled) &&
|
||||
(original_pt_thread != thread_ptr))
|
||||
{
|
||||
|
||||
/* Yes, preemption-threshold has changed. Determine if it can or should
|
||||
be reversed. */
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Pickup the preemption-threshold thread. */
|
||||
new_pt_thread = _tx_thread_preemption__threshold_scheduled;
|
||||
#endif
|
||||
|
||||
/* Restore the original preemption-threshold thread. */
|
||||
_tx_thread_preemption__threshold_scheduled = original_pt_thread;
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Determine if there is a new preemption-threshold thread to reverse. */
|
||||
if (new_pt_thread != TX_NULL)
|
||||
{
|
||||
|
||||
/* Clear the information associated with the new preemption-threshold thread. */
|
||||
|
||||
/* Pickup the priority. */
|
||||
priority = new_pt_thread -> tx_thread_priority;
|
||||
|
||||
/* Clear the preempted list entry. */
|
||||
_tx_thread_preemption_threshold_list[priority] = TX_NULL;
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
/* Calculate the bit map array index. */
|
||||
map_index = new_priority/((UINT) 32);
|
||||
#endif
|
||||
/* Ensure that this thread's priority is clear in the preempt map. */
|
||||
TX_MOD32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Determine if there are any other bits set in this preempt map. */
|
||||
if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No, clear the active bit to signify this preempted map has nothing set. */
|
||||
TX_DIV32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
654
common_smp/src/tx_mutex_put.c
Normal file
654
common_smp/src/tx_mutex_put.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Mutex */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_mutex.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_mutex_put PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function puts back an instance of the specified mutex. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* mutex_ptr Pointer to mutex control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Success completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* _tx_mutex_priority_change Restore previous thread priority */
|
||||
/* _tx_mutex_prioritize Prioritize the mutex suspension */
|
||||
/* _tx_mutex_thread_release Release all thread's mutexes */
|
||||
/* _tx_mutex_delete Release ownership upon mutex */
|
||||
/* deletion */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_mutex_put(TX_MUTEX *mutex_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *old_owner;
|
||||
UINT old_priority;
|
||||
UINT status;
|
||||
TX_MUTEX *next_mutex;
|
||||
TX_MUTEX *previous_mutex;
|
||||
UINT owned_count;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *current_thread;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
TX_THREAD *suspended_thread;
|
||||
UINT inheritance_priority;
|
||||
|
||||
|
||||
/* Setup status to indicate the processing is not complete. */
|
||||
status = TX_NOT_DONE;
|
||||
|
||||
/* Disable interrupts to put an instance back to the mutex. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total mutex put counter. */
|
||||
_tx_mutex_performance_put_count++;
|
||||
|
||||
/* Increment the number of attempts to put this mutex. */
|
||||
mutex_ptr -> tx_mutex_performance_put_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PUT, mutex_ptr, TX_POINTER_TO_ULONG_CONVERT(mutex_ptr -> tx_mutex_owner), mutex_ptr -> tx_mutex_ownership_count, TX_POINTER_TO_ULONG_CONVERT(&old_priority), TX_TRACE_MUTEX_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_MUTEX_PUT_INSERT
|
||||
|
||||
/* Determine if this mutex is owned. */
|
||||
if (mutex_ptr -> tx_mutex_ownership_count != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Pickup the owning thread pointer. */
|
||||
thread_ptr = mutex_ptr -> tx_mutex_owner;
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(current_thread)
|
||||
|
||||
/* Check to see if the mutex is owned by the calling thread. */
|
||||
if (mutex_ptr -> tx_mutex_owner != current_thread)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is set, indicating that
|
||||
the caller is not the application but from ThreadX. In such
|
||||
cases, the thread mutex owner does not need to match. */
|
||||
if (_tx_thread_preempt_disable == ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Invalid mutex release. */
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Caller does not own the mutex. */
|
||||
status = TX_NOT_OWNED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if we should continue. */
|
||||
if (status == TX_NOT_DONE)
|
||||
{
|
||||
|
||||
/* Decrement the mutex ownership count. */
|
||||
mutex_ptr -> tx_mutex_ownership_count--;
|
||||
|
||||
/* Determine if the mutex is still owned by the current thread. */
|
||||
if (mutex_ptr -> tx_mutex_ownership_count != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Mutex is still owned, just return successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Check for a NULL thread pointer, which can only happen during initialization. */
|
||||
if (thread_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Mutex is now available, return successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* The mutex is now available. */
|
||||
|
||||
/* Remove this mutex from the owned mutex list. */
|
||||
|
||||
/* Decrement the ownership count. */
|
||||
thread_ptr -> tx_thread_owned_mutex_count--;
|
||||
|
||||
/* Determine if this mutex was the only one on the list. */
|
||||
if (thread_ptr -> tx_thread_owned_mutex_count == ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Yes, the list is empty. Simply set the head pointer to NULL. */
|
||||
thread_ptr -> tx_thread_owned_mutex_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, there are more mutexes on the list. */
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_mutex = mutex_ptr -> tx_mutex_owned_next;
|
||||
previous_mutex = mutex_ptr -> tx_mutex_owned_previous;
|
||||
next_mutex -> tx_mutex_owned_previous = previous_mutex;
|
||||
previous_mutex -> tx_mutex_owned_next = next_mutex;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (thread_ptr -> tx_thread_owned_mutex_list == mutex_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
thread_ptr -> tx_thread_owned_mutex_list = next_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the simple, non-suspension, non-priority inheritance case is present. */
|
||||
if (mutex_ptr -> tx_mutex_suspension_list == TX_NULL)
|
||||
{
|
||||
|
||||
/* Is this a priority inheritance mutex? */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Yes, we are done - set the mutex owner to NULL. */
|
||||
mutex_ptr -> tx_mutex_owner = TX_NULL;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Mutex is now available, return successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the processing is complete. */
|
||||
if (status == TX_NOT_DONE)
|
||||
{
|
||||
|
||||
/* Initialize original owner and thread priority. */
|
||||
old_owner = TX_NULL;
|
||||
old_priority = thread_ptr -> tx_thread_user_priority;
|
||||
|
||||
/* Does this mutex support priority inheritance? */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Default the inheritance priority to disabled. */
|
||||
inheritance_priority = ((UINT) TX_MAX_PRIORITIES);
|
||||
|
||||
/* Search the owned mutexes for this thread to determine the highest priority for this
|
||||
former mutex owner to return to. */
|
||||
next_mutex = thread_ptr -> tx_thread_owned_mutex_list;
|
||||
while (next_mutex != TX_NULL)
|
||||
{
|
||||
|
||||
/* Does this mutex support priority inheritance? */
|
||||
if (next_mutex -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Determine if highest priority field of the mutex is higher than the priority to
|
||||
restore. */
|
||||
if (next_mutex -> tx_mutex_highest_priority_waiting < inheritance_priority)
|
||||
{
|
||||
|
||||
/* Use this priority to return releasing thread to. */
|
||||
inheritance_priority = next_mutex -> tx_mutex_highest_priority_waiting;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move mutex pointer to the next mutex in the list. */
|
||||
next_mutex = next_mutex -> tx_mutex_owned_next;
|
||||
|
||||
/* Are we at the end of the list? */
|
||||
if (next_mutex == thread_ptr -> tx_thread_owned_mutex_list)
|
||||
{
|
||||
|
||||
/* Yes, set the next mutex to NULL. */
|
||||
next_mutex = TX_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Undo the temporarily preemption disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#endif
|
||||
|
||||
/* Set the inherit priority to that of the highest priority thread waiting on the mutex. */
|
||||
thread_ptr -> tx_thread_inherit_priority = inheritance_priority;
|
||||
|
||||
/* Determine if the inheritance priority is less than the default old priority. */
|
||||
if (inheritance_priority < old_priority)
|
||||
{
|
||||
|
||||
/* Yes, update the old priority. */
|
||||
old_priority = inheritance_priority;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if priority inheritance is in effect and there are one or more
|
||||
threads suspended on the mutex. */
|
||||
if (mutex_ptr -> tx_mutex_suspended_count > ((UINT) 1))
|
||||
{
|
||||
|
||||
/* Is priority inheritance in effect? */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, this code is simply to ensure the highest priority thread is positioned
|
||||
at the front of the suspension list. */
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Call the mutex prioritize processing to ensure the
|
||||
highest priority thread is resumed. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
do
|
||||
{
|
||||
status = _tx_mutex_prioritize(mutex_ptr);
|
||||
} while (status != TX_SUCCESS);
|
||||
#else
|
||||
_tx_mutex_prioritize(mutex_ptr);
|
||||
#endif
|
||||
|
||||
/* At this point, the highest priority thread is at the
|
||||
front of the suspension list. */
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_MUTEX_PUT_EXTENSION_1
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Back off the preemption disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Now determine if there are any threads still waiting on the mutex. */
|
||||
if (mutex_ptr -> tx_mutex_suspension_list == TX_NULL)
|
||||
{
|
||||
|
||||
/* No, there are no longer any threads waiting on the mutex. */
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Mutex is not owned, but it is possible that a thread that
|
||||
caused a priority inheritance to occur is no longer waiting
|
||||
on the mutex. */
|
||||
|
||||
/* Setup the highest priority waiting thread. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = (UINT) TX_MAX_PRIORITIES;
|
||||
|
||||
/* Determine if we need to restore priority. */
|
||||
if ((mutex_ptr -> tx_mutex_owner) -> tx_thread_priority != old_priority)
|
||||
{
|
||||
|
||||
/* Yes, restore the priority of thread. */
|
||||
_tx_mutex_priority_change(mutex_ptr -> tx_mutex_owner, old_priority);
|
||||
}
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Back off the preemption disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#endif
|
||||
|
||||
/* Set the mutex owner to NULL. */
|
||||
mutex_ptr -> tx_mutex_owner = TX_NULL;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Set status to success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Pickup the thread at the front of the suspension list. */
|
||||
thread_ptr = mutex_ptr -> tx_mutex_suspension_list;
|
||||
|
||||
/* Save the previous ownership information, if inheritance is
|
||||
in effect. */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Remember the old mutex owner. */
|
||||
old_owner = mutex_ptr -> tx_mutex_owner;
|
||||
|
||||
/* Setup owner thread priority information. */
|
||||
mutex_ptr -> tx_mutex_original_priority = thread_ptr -> tx_thread_priority;
|
||||
|
||||
/* Setup the highest priority waiting thread. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = (UINT) TX_MAX_PRIORITIES;
|
||||
}
|
||||
|
||||
/* Determine how many mutexes are owned by this thread. */
|
||||
owned_count = thread_ptr -> tx_thread_owned_mutex_count;
|
||||
|
||||
/* Determine if this thread owns any other mutexes that have priority inheritance. */
|
||||
if (owned_count == ((UINT) 0))
|
||||
{
|
||||
|
||||
/* The owned mutex list is empty. Add mutex to empty list. */
|
||||
thread_ptr -> tx_thread_owned_mutex_list = mutex_ptr;
|
||||
mutex_ptr -> tx_mutex_owned_next = mutex_ptr;
|
||||
mutex_ptr -> tx_mutex_owned_previous = mutex_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Non-empty list. Link up the mutex. */
|
||||
|
||||
/* Pickup tail pointer. */
|
||||
next_mutex = thread_ptr -> tx_thread_owned_mutex_list;
|
||||
previous_mutex = next_mutex -> tx_mutex_owned_previous;
|
||||
|
||||
/* Place the owned mutex in the list. */
|
||||
next_mutex -> tx_mutex_owned_previous = mutex_ptr;
|
||||
previous_mutex -> tx_mutex_owned_next = mutex_ptr;
|
||||
|
||||
/* Setup this mutex's next and previous created links. */
|
||||
mutex_ptr -> tx_mutex_owned_previous = previous_mutex;
|
||||
mutex_ptr -> tx_mutex_owned_next = next_mutex;
|
||||
}
|
||||
|
||||
/* Increment the number of mutexes owned counter. */
|
||||
thread_ptr -> tx_thread_owned_mutex_count = owned_count + ((UINT) 1);
|
||||
|
||||
/* Mark the Mutex as owned and fill in the corresponding information. */
|
||||
mutex_ptr -> tx_mutex_ownership_count = (UINT) 1;
|
||||
mutex_ptr -> tx_mutex_owner = thread_ptr;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
mutex_ptr -> tx_mutex_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = mutex_ptr -> tx_mutex_suspended_count;
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
mutex_ptr -> tx_mutex_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
mutex_ptr -> tx_mutex_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Determine if priority inheritance is enabled for this mutex. */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, priority inheritance is requested. */
|
||||
|
||||
/* Determine if there are any more threads still suspended on the mutex. */
|
||||
if (mutex_ptr -> tx_mutex_suspended_count != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Determine if there are more than one thread suspended on the mutex. */
|
||||
if (mutex_ptr -> tx_mutex_suspended_count > ((ULONG) 1))
|
||||
{
|
||||
|
||||
/* If so, prioritize the list so the highest priority thread is placed at the
|
||||
front of the suspension list. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
do
|
||||
{
|
||||
status = _tx_mutex_prioritize(mutex_ptr);
|
||||
} while (status != TX_SUCCESS);
|
||||
#else
|
||||
_tx_mutex_prioritize(mutex_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Now, pickup the list head and set the priority. */
|
||||
|
||||
/* Determine if there still are threads suspended for this mutex. */
|
||||
suspended_thread = mutex_ptr -> tx_mutex_suspension_list;
|
||||
if (suspended_thread != TX_NULL)
|
||||
{
|
||||
|
||||
/* Setup the highest priority thread waiting on this mutex. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = suspended_thread -> tx_thread_priority;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore previous priority needs to be restored after priority
|
||||
inheritance. */
|
||||
|
||||
/* Determine if we need to restore priority. */
|
||||
if (old_owner -> tx_thread_priority != old_priority)
|
||||
{
|
||||
|
||||
/* Restore priority of thread. */
|
||||
_tx_mutex_priority_change(old_owner, old_priority);
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Determine if priority inheritance is enabled for this mutex. */
|
||||
if (mutex_ptr -> tx_mutex_inherit == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, priority inheritance is requested. */
|
||||
|
||||
/* Determine if there are any more threads still suspended on the mutex. */
|
||||
if (mutex_ptr -> tx_mutex_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Prioritize the list so the highest priority thread is placed at the
|
||||
front of the suspension list. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
do
|
||||
{
|
||||
status = _tx_mutex_prioritize(mutex_ptr);
|
||||
} while (status != TX_SUCCESS);
|
||||
#else
|
||||
_tx_mutex_prioritize(mutex_ptr);
|
||||
#endif
|
||||
|
||||
/* Now, pickup the list head and set the priority. */
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_MUTEX_PUT_EXTENSION_2
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if there still are threads suspended for this mutex. */
|
||||
suspended_thread = mutex_ptr -> tx_mutex_suspension_list;
|
||||
if (suspended_thread != TX_NULL)
|
||||
{
|
||||
|
||||
/* Setup the highest priority thread waiting on this mutex. */
|
||||
mutex_ptr -> tx_mutex_highest_priority_waiting = suspended_thread -> tx_thread_priority;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Restore previous priority needs to be restored after priority
|
||||
inheritance. */
|
||||
|
||||
/* Is the priority different? */
|
||||
if (old_owner -> tx_thread_priority != old_priority)
|
||||
{
|
||||
|
||||
/* Restore the priority of thread. */
|
||||
_tx_mutex_priority_change(old_owner, old_priority);
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Return a successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Caller does not own the mutex. */
|
||||
status = TX_NOT_OWNED;
|
||||
}
|
||||
|
||||
/* Return the completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
225
common_smp/src/tx_queue_cleanup.c
Normal file
225
common_smp/src/tx_queue_cleanup.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_cleanup PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes queue timeout and thread terminate */
|
||||
/* actions that require the queue data structures to be cleaned */
|
||||
/* up. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to suspended thread's */
|
||||
/* control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_timeout Thread timeout processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* _tx_thread_wait_abort Thread wait abort processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_queue_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_QUEUE *queue_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts to remove the suspended thread from the queue. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the cleanup is still required. */
|
||||
if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_queue_cleanup))
|
||||
{
|
||||
|
||||
/* Check for valid suspension sequence. */
|
||||
if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
|
||||
{
|
||||
|
||||
/* Setup pointer to queue control block. */
|
||||
queue_ptr = TX_VOID_TO_QUEUE_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
|
||||
/* Check for NULL queue pointer. */
|
||||
if (queue_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Is the queue ID valid? */
|
||||
if (queue_ptr -> tx_queue_id == TX_QUEUE_ID)
|
||||
{
|
||||
|
||||
/* Determine if there are any thread suspensions. */
|
||||
if (queue_ptr -> tx_queue_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
#else
|
||||
|
||||
/* Setup pointer to queue control block. */
|
||||
queue_ptr = TX_VOID_TO_QUEUE_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
#endif
|
||||
|
||||
/* Yes, we still have thread suspension! */
|
||||
|
||||
/* Clear the suspension cleanup flag. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Decrement the suspended count. */
|
||||
queue_ptr -> tx_queue_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same suspension list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Determine if we need to update the head pointer. */
|
||||
if (queue_ptr -> tx_queue_suspension_list == thread_ptr)
|
||||
{
|
||||
|
||||
/* Update the list head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = next_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we need to determine if this cleanup is from a terminate, timeout,
|
||||
or from a wait abort. */
|
||||
if (thread_ptr -> tx_thread_state == TX_QUEUE_SUSP)
|
||||
{
|
||||
|
||||
/* Timeout condition and the thread still suspended on the queue.
|
||||
Setup return error status and resume the thread. */
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total timeouts counter. */
|
||||
_tx_queue_performance_timeout_count++;
|
||||
|
||||
/* Increment the number of timeouts on this queue. */
|
||||
queue_ptr -> tx_queue_performance_timeout_count++;
|
||||
#endif
|
||||
|
||||
/* Setup return status. */
|
||||
if (queue_ptr -> tx_queue_enqueued != TX_NO_MESSAGES)
|
||||
{
|
||||
|
||||
/* Queue full timeout! */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_QUEUE_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Queue empty timeout! */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_QUEUE_EMPTY;
|
||||
}
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
170
common_smp/src/tx_queue_create.c
Normal file
170
common_smp/src/tx_queue_create.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_create PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a message queue. The message size and depth */
|
||||
/* of the queue is specified by the caller. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* name_ptr Pointer to queue name */
|
||||
/* message_size Size of each queue message */
|
||||
/* queue_start Starting address of the queue area*/
|
||||
/* queue_size Number of bytes in the queue */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size,
|
||||
VOID *queue_start, ULONG queue_size)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT capacity;
|
||||
UINT used_words;
|
||||
TX_QUEUE *next_queue;
|
||||
TX_QUEUE *previous_queue;
|
||||
|
||||
|
||||
/* Initialize queue control block to all zeros. */
|
||||
TX_MEMSET(queue_ptr, 0, (sizeof(TX_QUEUE)));
|
||||
|
||||
/* Setup the basic queue fields. */
|
||||
queue_ptr -> tx_queue_name = name_ptr;
|
||||
|
||||
/* Save the message size in the control block. */
|
||||
queue_ptr -> tx_queue_message_size = message_size;
|
||||
|
||||
/* Determine how many messages will fit in the queue area and the number
|
||||
of ULONGs used. */
|
||||
capacity = (UINT) (queue_size / ((ULONG) (((ULONG) message_size) * (sizeof(ULONG)))));
|
||||
used_words = capacity * message_size;
|
||||
|
||||
/* Save the starting address and calculate the ending address of
|
||||
the queue. Note that the ending address is really one past the
|
||||
end! */
|
||||
queue_ptr -> tx_queue_start = TX_VOID_TO_ULONG_POINTER_CONVERT(queue_start);
|
||||
queue_ptr -> tx_queue_end = TX_ULONG_POINTER_ADD(queue_ptr -> tx_queue_start, used_words);
|
||||
|
||||
/* Set the read and write pointers to the beginning of the queue
|
||||
area. */
|
||||
queue_ptr -> tx_queue_read = TX_VOID_TO_ULONG_POINTER_CONVERT(queue_start);
|
||||
queue_ptr -> tx_queue_write = TX_VOID_TO_ULONG_POINTER_CONVERT(queue_start);
|
||||
|
||||
/* Setup the number of enqueued messages and the number of message
|
||||
slots available in the queue. */
|
||||
queue_ptr -> tx_queue_available_storage = (UINT) capacity;
|
||||
queue_ptr -> tx_queue_capacity = (UINT) capacity;
|
||||
|
||||
/* Disable interrupts to put the queue on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Setup the queue ID to make it valid. */
|
||||
queue_ptr -> tx_queue_id = TX_QUEUE_ID;
|
||||
|
||||
/* Place the queue on the list of created queues. First,
|
||||
check for an empty list. */
|
||||
if (_tx_queue_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created queue list is empty. Add queue to empty list. */
|
||||
_tx_queue_created_ptr = queue_ptr;
|
||||
queue_ptr -> tx_queue_created_next = queue_ptr;
|
||||
queue_ptr -> tx_queue_created_previous = queue_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_queue = _tx_queue_created_ptr;
|
||||
previous_queue = next_queue -> tx_queue_created_previous;
|
||||
|
||||
/* Place the new queue in the list. */
|
||||
next_queue -> tx_queue_created_previous = queue_ptr;
|
||||
previous_queue -> tx_queue_created_next = queue_ptr;
|
||||
|
||||
/* Setup this queues's created links. */
|
||||
queue_ptr -> tx_queue_created_previous = previous_queue;
|
||||
queue_ptr -> tx_queue_created_next = next_queue;
|
||||
}
|
||||
|
||||
/* Increment the created queue count. */
|
||||
_tx_queue_created_count++;
|
||||
|
||||
/* Optional queue create extended processing. */
|
||||
TX_QUEUE_CREATE_EXTENSION(queue_ptr)
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_QUEUE, queue_ptr, name_ptr, queue_size, message_size)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_CREATE, queue_ptr, message_size, TX_POINTER_TO_ULONG_CONVERT(queue_start), queue_size, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_CREATE_INSERT
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
206
common_smp/src/tx_queue_delete.c
Normal file
206
common_smp/src/tx_queue_delete.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function deletes the specified queue. All threads suspended */
|
||||
/* on the queue are resumed with the TX_DELETED status code. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_delete(TX_QUEUE *queue_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
UINT suspended_count;
|
||||
TX_QUEUE *next_queue;
|
||||
TX_QUEUE *previous_queue;
|
||||
|
||||
|
||||
/* Disable interrupts to remove the queue from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_DELETE, queue_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Optional queue delete extended processing. */
|
||||
TX_QUEUE_DELETE_EXTENSION(queue_ptr)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(queue_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_DELETE_INSERT
|
||||
|
||||
/* Clear the queue ID to make it invalid. */
|
||||
queue_ptr -> tx_queue_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the number of created queues. */
|
||||
_tx_queue_created_count--;
|
||||
|
||||
/* See if the queue is the only one on the list. */
|
||||
if (_tx_queue_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created queue, just set the created list to NULL. */
|
||||
_tx_queue_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_queue = queue_ptr -> tx_queue_created_next;
|
||||
previous_queue = queue_ptr -> tx_queue_created_previous;
|
||||
next_queue -> tx_queue_created_previous = previous_queue;
|
||||
previous_queue -> tx_queue_created_next = next_queue;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_queue_created_ptr == queue_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_queue_created_ptr = next_queue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Pickup the suspension information. */
|
||||
thread_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
queue_ptr -> tx_queue_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the queue list to resume any and all threads suspended
|
||||
on this queue. */
|
||||
while (suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_DELETED. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_DELETED;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move to next thread. */
|
||||
thread_ptr = next_thread;
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_QUEUE_DELETE_PORT_COMPLETION(queue_ptr)
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release previous preempt disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
205
common_smp/src/tx_queue_flush.c
Normal file
205
common_smp/src/tx_queue_flush.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_flush PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function resets the specified queue, if there are any messages */
|
||||
/* in it. Messages waiting to be placed on the queue are also thrown */
|
||||
/* out. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_flush(TX_QUEUE *queue_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *suspension_list;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *thread_ptr;
|
||||
|
||||
|
||||
/* Initialize the suspended count and list. */
|
||||
suspended_count = TX_NO_SUSPENSIONS;
|
||||
suspension_list = TX_NULL;
|
||||
|
||||
/* Disable interrupts to reset various queue parameters. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_FLUSH, queue_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_FLUSH_INSERT
|
||||
|
||||
/* Determine if there is something on the queue. */
|
||||
if (queue_ptr -> tx_queue_enqueued != TX_NO_MESSAGES)
|
||||
{
|
||||
|
||||
/* Yes, there is something in the queue. */
|
||||
|
||||
/* Reset the queue parameters to erase all of the queued messages. */
|
||||
queue_ptr -> tx_queue_enqueued = TX_NO_MESSAGES;
|
||||
queue_ptr -> tx_queue_available_storage = queue_ptr -> tx_queue_capacity;
|
||||
queue_ptr -> tx_queue_read = queue_ptr -> tx_queue_start;
|
||||
queue_ptr -> tx_queue_write = queue_ptr -> tx_queue_start;
|
||||
|
||||
/* Now determine if there are any threads suspended on a full queue. */
|
||||
if (queue_ptr -> tx_queue_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, there are threads suspended on this queue, they must be
|
||||
resumed! */
|
||||
|
||||
/* Copy the information into temporary variables. */
|
||||
suspension_list = queue_ptr -> tx_queue_suspension_list;
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Clear the queue variables. */
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
queue_ptr -> tx_queue_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the queue list to resume any and all threads suspended
|
||||
on this queue. */
|
||||
if (suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Pickup the thread to resume. */
|
||||
thread_ptr = suspension_list;
|
||||
while (suspended_count != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Check for a NULL thread pointer. */
|
||||
if (thread_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Get out of the loop. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Resume the next suspended thread. */
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_SUCCESS. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr -> tx_thread_suspended_previous);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr -> tx_thread_suspended_previous);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Restore previous preempt posture. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
421
common_smp/src/tx_queue_front_send.c
Normal file
421
common_smp/src/tx_queue_front_send.c
Normal file
@@ -0,0 +1,421 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_front_send PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places a message at the front of the specified queue. */
|
||||
/* If there is no room in the queue, this function returns the */
|
||||
/* queue full status. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* source_ptr Pointer to message source */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread routine */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* _tx_thread_system_suspend Suspend thread routine */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_front_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
ULONG *source;
|
||||
ULONG *destination;
|
||||
UINT size;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*queue_send_notify)(struct TX_QUEUE_STRUCT *notify_queue_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
/* Default the status to TX_SUCCESS. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Disable interrupts to place message in the queue. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total messages sent counter. */
|
||||
_tx_queue_performance_messages_sent_count++;
|
||||
|
||||
/* Increment the number of messages sent to this queue. */
|
||||
queue_ptr -> tx_queue_performance_messages_sent_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_FRONT_SEND, queue_ptr, TX_POINTER_TO_ULONG_CONVERT(source_ptr), wait_option, queue_ptr -> tx_queue_enqueued, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_FRONT_SEND_INSERT
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Now check for room in the queue for placing the new message in front. */
|
||||
if (queue_ptr -> tx_queue_available_storage != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Yes there is room in the queue. Now determine if there is a thread waiting
|
||||
for a message. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No thread suspended while waiting for a message from
|
||||
this queue. */
|
||||
|
||||
/* Adjust the read pointer since we are adding to the front of the
|
||||
queue. */
|
||||
|
||||
/* See if the read pointer is at the beginning of the queue area. */
|
||||
if (queue_ptr -> tx_queue_read == queue_ptr -> tx_queue_start)
|
||||
{
|
||||
|
||||
/* Adjust the read pointer to the last message at the end of the
|
||||
queue. */
|
||||
queue_ptr -> tx_queue_read = TX_ULONG_POINTER_SUB(queue_ptr -> tx_queue_end, queue_ptr -> tx_queue_message_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not at the beginning of the queue, just move back one message. */
|
||||
queue_ptr -> tx_queue_read = TX_ULONG_POINTER_SUB(queue_ptr -> tx_queue_read, queue_ptr -> tx_queue_message_size);
|
||||
}
|
||||
|
||||
/* Simply place the message in the queue. */
|
||||
|
||||
/* Reduce the amount of available storage. */
|
||||
queue_ptr -> tx_queue_available_storage--;
|
||||
|
||||
/* Increase the enqueued count. */
|
||||
queue_ptr -> tx_queue_enqueued++;
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = TX_VOID_TO_ULONG_POINTER_CONVERT(source_ptr);
|
||||
destination = queue_ptr -> tx_queue_read;
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this queue. */
|
||||
queue_send_notify = queue_ptr -> tx_queue_send_notify;
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (queue_send_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application queue send notification. */
|
||||
(queue_send_notify)(queue_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Thread suspended waiting for a message. Remove it and copy this message
|
||||
into its storage area. */
|
||||
thread_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
suspended_count--;
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
queue_ptr -> tx_queue_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count;
|
||||
|
||||
/* Prepare for resumption of the thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this queue. */
|
||||
queue_send_notify = queue_ptr -> tx_queue_send_notify;
|
||||
#endif
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = TX_VOID_TO_ULONG_POINTER_CONVERT(source_ptr);
|
||||
destination = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (queue_send_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application queue send notification. */
|
||||
(queue_send_notify)(queue_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the caller has requested suspension. */
|
||||
else if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_QUEUE_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Yes, suspension is requested. */
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_queue_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this queue control
|
||||
block and the source pointer. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) queue_ptr;
|
||||
thread_ptr -> tx_thread_additional_suspend_info = (VOID *) source_ptr;
|
||||
|
||||
/* Set the flag to true to indicate a queue front send suspension. */
|
||||
thread_ptr -> tx_thread_suspend_option = TX_TRUE;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Place this thread at the front of the suspension list, since it is a
|
||||
queue front send suspension. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
queue_ptr -> tx_queue_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = queue_ptr -> tx_queue_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
|
||||
/* Update the suspension list to put this thread in front, which will put
|
||||
the message that was removed in the proper relative order when room is
|
||||
made in the queue. */
|
||||
queue_ptr -> tx_queue_suspension_list = thread_ptr;
|
||||
}
|
||||
|
||||
/* Increment the suspended thread count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count + ((UINT) 1);
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_QUEUE_SUSP;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this queue. */
|
||||
queue_send_notify = queue_ptr -> tx_queue_send_notify;
|
||||
#endif
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (thread_ptr -> tx_thread_suspend_status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Check for a notify callback. */
|
||||
if (queue_send_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application queue send notification. */
|
||||
(queue_send_notify)(queue_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* No room in queue and no suspension requested, return error completion. */
|
||||
status = TX_QUEUE_FULL;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
145
common_smp/src/tx_queue_info_get.c
Normal file
145
common_smp/src/tx_queue_info_get.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified queue. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* name Destination for the queue name */
|
||||
/* enqueued Destination for enqueued count */
|
||||
/* available_storage Destination for available storage */
|
||||
/* first_suspended Destination for pointer of first */
|
||||
/* thread suspended on this queue */
|
||||
/* suspended_count Destination for suspended count */
|
||||
/* next_queue Destination for pointer to next */
|
||||
/* queue on the created list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_info_get(TX_QUEUE *queue_ptr, CHAR **name, ULONG *enqueued, ULONG *available_storage,
|
||||
TX_THREAD **first_suspended, ULONG *suspended_count, TX_QUEUE **next_queue)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_INFO_GET, queue_ptr, 0, 0, 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the queue. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = queue_ptr -> tx_queue_name;
|
||||
}
|
||||
|
||||
/* Retrieve the number of messages currently in the queue. */
|
||||
if (enqueued != TX_NULL)
|
||||
{
|
||||
|
||||
*enqueued = (ULONG) queue_ptr -> tx_queue_enqueued;
|
||||
}
|
||||
|
||||
/* Retrieve the number of messages that will still fit in the queue. */
|
||||
if (available_storage != TX_NULL)
|
||||
{
|
||||
|
||||
*available_storage = (ULONG) queue_ptr -> tx_queue_available_storage;
|
||||
}
|
||||
|
||||
/* Retrieve the first thread suspended on this queue. */
|
||||
if (first_suspended != TX_NULL)
|
||||
{
|
||||
|
||||
*first_suspended = queue_ptr -> tx_queue_suspension_list;
|
||||
}
|
||||
|
||||
/* Retrieve the number of threads suspended on this queue. */
|
||||
if (suspended_count != TX_NULL)
|
||||
{
|
||||
|
||||
*suspended_count = (ULONG) queue_ptr -> tx_queue_suspended_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to the next queue created. */
|
||||
if (next_queue != TX_NULL)
|
||||
{
|
||||
|
||||
*next_queue = queue_ptr -> tx_queue_created_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
138
common_smp/src/tx_queue_initialize.c
Normal file
138
common_smp/src/tx_queue_initialize.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
#ifndef TX_INLINE_INITIALIZATION
|
||||
|
||||
/* Define the head pointer of the created queue list. */
|
||||
|
||||
TX_QUEUE * _tx_queue_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created queues. */
|
||||
|
||||
ULONG _tx_queue_created_count;
|
||||
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of messages sent. */
|
||||
|
||||
ULONG _tx_queue_performance_messages_sent_count;
|
||||
|
||||
|
||||
/* Define the total number of messages received. */
|
||||
|
||||
ULONG _tx_queue_performance__messages_received_count;
|
||||
|
||||
|
||||
/* Define the total number of queue empty suspensions. */
|
||||
|
||||
ULONG _tx_queue_performance_empty_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of queue full suspensions. */
|
||||
|
||||
ULONG _tx_queue_performance_full_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of queue full errors. */
|
||||
|
||||
ULONG _tx_queue_performance_full_error_count;
|
||||
|
||||
|
||||
/* Define the total number of queue timeouts. */
|
||||
|
||||
ULONG _tx_queue_performance_timeout_count;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_initialize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the queue component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_queue_initialize(VOID)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the head pointer of the created queue list and the
|
||||
number of queues created. */
|
||||
_tx_queue_created_ptr = TX_NULL;
|
||||
_tx_queue_created_count = TX_EMPTY;
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize the queue performance counters. */
|
||||
_tx_queue_performance_messages_sent_count = ((ULONG) 0);
|
||||
_tx_queue_performance__messages_received_count = ((ULONG) 0);
|
||||
_tx_queue_performance_empty_suspension_count = ((ULONG) 0);
|
||||
_tx_queue_performance_full_suspension_count = ((ULONG) 0);
|
||||
_tx_queue_performance_timeout_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
229
common_smp/src/tx_queue_performance_info_get.c
Normal file
229
common_smp/src/tx_queue_performance_info_get.c
Normal file
@@ -0,0 +1,229 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_queue.h"
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* queue. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* messages_sent Destination for messages sent */
|
||||
/* messages_received Destination for messages received */
|
||||
/* empty_suspensions Destination for number of empty */
|
||||
/* queue suspensions */
|
||||
/* full_suspensions Destination for number of full */
|
||||
/* queue suspensions */
|
||||
/* full_errors Destination for queue full errors */
|
||||
/* returned - no suspension */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* on this queue */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_performance_info_get(TX_QUEUE *queue_ptr, ULONG *messages_sent, ULONG *messages_received,
|
||||
ULONG *empty_suspensions, ULONG *full_suspensions, ULONG *full_errors, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (queue_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Queue pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the queue ID is invalid. */
|
||||
else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID)
|
||||
{
|
||||
|
||||
/* Queue pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_PERFORMANCE_INFO_GET, queue_ptr, 0, 0, 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the number of messages sent to this queue. */
|
||||
if (messages_sent != TX_NULL)
|
||||
{
|
||||
|
||||
*messages_sent = queue_ptr -> tx_queue_performance_messages_sent_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of messages received from this queue. */
|
||||
if (messages_received != TX_NULL)
|
||||
{
|
||||
|
||||
*messages_received = queue_ptr -> tx_queue_performance_messages_received_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of empty queue suspensions on this queue. */
|
||||
if (empty_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*empty_suspensions = queue_ptr -> tx_queue_performance_empty_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of full queue suspensions on this queue. */
|
||||
if (full_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*full_suspensions = queue_ptr -> tx_queue_performance_full_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of full errors (no suspension!) on this queue. */
|
||||
if (full_errors != TX_NULL)
|
||||
{
|
||||
|
||||
*full_errors = queue_ptr -> tx_queue_performance_full_error_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of timeouts on this queue. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = queue_ptr -> tx_queue_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
#else
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (queue_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (messages_sent != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (messages_received != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (empty_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (full_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (full_errors != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
205
common_smp/src/tx_queue_performance_system_info_get.c
Normal file
205
common_smp/src/tx_queue_performance_system_info_get.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_queue.h"
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves queue system performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* messages_sent Destination for total messages */
|
||||
/* sent */
|
||||
/* messages_received Destination for total messages */
|
||||
/* received */
|
||||
/* empty_suspensions Destination for total empty */
|
||||
/* queue suspensions */
|
||||
/* full_suspensions Destination for total full */
|
||||
/* queue suspensions */
|
||||
/* full_errors Destination for total queue full */
|
||||
/* errors returned - no suspension */
|
||||
/* timeouts Destination for total number of */
|
||||
/* timeouts */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_performance_system_info_get(ULONG *messages_sent, ULONG *messages_received,
|
||||
ULONG *empty_suspensions, ULONG *full_suspensions, ULONG *full_errors, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the total number of queue messages sent. */
|
||||
if (messages_sent != TX_NULL)
|
||||
{
|
||||
|
||||
*messages_sent = _tx_queue_performance_messages_sent_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of queue messages received. */
|
||||
if (messages_received != TX_NULL)
|
||||
{
|
||||
|
||||
*messages_received = _tx_queue_performance__messages_received_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of empty queue suspensions. */
|
||||
if (empty_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*empty_suspensions = _tx_queue_performance_empty_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of full queue suspensions. */
|
||||
if (full_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*full_suspensions = _tx_queue_performance_full_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of full errors. */
|
||||
if (full_errors != TX_NULL)
|
||||
{
|
||||
|
||||
*full_errors = _tx_queue_performance_full_error_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of queue timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_queue_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (messages_sent != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (messages_received != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (empty_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (full_suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (full_errors != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
249
common_smp/src/tx_queue_prioritize.c
Normal file
249
common_smp/src/tx_queue_prioritize.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_prioritize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places the highest priority suspended thread at the */
|
||||
/* front of the suspension list. All other threads remain in the same */
|
||||
/* FIFO suspension order. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_prioritize(TX_QUEUE *queue_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *priority_thread_ptr;
|
||||
TX_THREAD *head_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT list_changed;
|
||||
|
||||
|
||||
/* Disable interrupts to place message in the queue. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_PRIORITIZE, queue_ptr, queue_ptr -> tx_queue_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_PRIORITIZE_INSERT
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Determine if there are fewer than 2 suspended threads. */
|
||||
if (suspended_count < ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Determine if there how many threads are suspended on this queue. */
|
||||
else if (suspended_count == ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Pickup the head pointer and the next pointer. */
|
||||
head_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
next_thread = head_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Determine if the next suspended thread has a higher priority. */
|
||||
if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
|
||||
{
|
||||
|
||||
/* Yes, move the list head to the next thread. */
|
||||
queue_ptr -> tx_queue_suspension_list = next_thread;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the list changed flag to false. */
|
||||
list_changed = TX_FALSE;
|
||||
|
||||
/* Search through the list to find the highest priority thread. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Is the current thread higher priority? */
|
||||
if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, remember that this thread is the highest priority. */
|
||||
priority_thread_ptr = thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if any changes to the list have occurred while
|
||||
interrupts were enabled. */
|
||||
|
||||
/* Is the list head the same? */
|
||||
if (head_ptr != queue_ptr -> tx_queue_suspension_list)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is the suspended count the same? */
|
||||
if (suspended_count != queue_ptr -> tx_queue_suspended_count)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the list has changed. */
|
||||
if (list_changed == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Move the thread pointer to the next thread. */
|
||||
thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Save the suspension count and head pointer. */
|
||||
head_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Reset the list changed flag. */
|
||||
list_changed = TX_FALSE;
|
||||
}
|
||||
|
||||
} while (thread_ptr != head_ptr);
|
||||
|
||||
/* Release preemption. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Now determine if the highest priority thread is at the front
|
||||
of the list. */
|
||||
if (priority_thread_ptr != head_ptr)
|
||||
{
|
||||
|
||||
/* No, we need to move the highest priority suspended thread to the
|
||||
front of the list. */
|
||||
|
||||
/* First, remove the highest priority thread by updating the
|
||||
adjacent suspended threads. */
|
||||
next_thread = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = priority_thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Now, link the highest priority thread at the front of the list. */
|
||||
previous_thread = head_ptr -> tx_thread_suspended_previous;
|
||||
priority_thread_ptr -> tx_thread_suspended_next = head_ptr;
|
||||
priority_thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = priority_thread_ptr;
|
||||
head_ptr -> tx_thread_suspended_previous = priority_thread_ptr;
|
||||
|
||||
/* Move the list head pointer to the highest priority suspended thread. */
|
||||
queue_ptr -> tx_queue_suspension_list = priority_thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
|
||||
/* Return successful status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
486
common_smp/src/tx_queue_receive.c
Normal file
486
common_smp/src/tx_queue_receive.c
Normal file
@@ -0,0 +1,486 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_receive PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function receives a message from the specified queue. If there */
|
||||
/* are no messages in the queue, this function waits according to the */
|
||||
/* option specified. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* destination_ptr Pointer to message destination */
|
||||
/* **** MUST BE LARGE ENOUGH TO */
|
||||
/* HOLD MESSAGE **** */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread routine */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* _tx_thread_system_suspend Suspend thread routine */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
ULONG *source;
|
||||
ULONG *destination;
|
||||
UINT size;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default the status to TX_SUCCESS. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Disable interrupts to receive message from queue. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total messages received counter. */
|
||||
_tx_queue_performance__messages_received_count++;
|
||||
|
||||
/* Increment the number of messages received from this queue. */
|
||||
queue_ptr -> tx_queue_performance_messages_received_count++;
|
||||
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_RECEIVE, queue_ptr, TX_POINTER_TO_ULONG_CONVERT(destination_ptr), wait_option, queue_ptr -> tx_queue_enqueued, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_RECEIVE_INSERT
|
||||
|
||||
/* Pickup the thread suspension count. */
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Determine if there is anything in the queue. */
|
||||
if (queue_ptr -> tx_queue_enqueued != TX_NO_MESSAGES)
|
||||
{
|
||||
|
||||
/* Determine if there are any suspensions. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* There is a message waiting in the queue and there are no suspensi. */
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = queue_ptr -> tx_queue_read;
|
||||
destination = TX_VOID_TO_ULONG_POINTER_CONVERT(destination_ptr);
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Determine if we are at the end. */
|
||||
if (source == queue_ptr -> tx_queue_end)
|
||||
{
|
||||
|
||||
/* Yes, wrap around to the beginning. */
|
||||
source = queue_ptr -> tx_queue_start;
|
||||
}
|
||||
|
||||
/* Setup the queue read pointer. */
|
||||
queue_ptr -> tx_queue_read = source;
|
||||
|
||||
/* Increase the amount of available storage. */
|
||||
queue_ptr -> tx_queue_available_storage++;
|
||||
|
||||
/* Decrease the enqueued count. */
|
||||
queue_ptr -> tx_queue_enqueued--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At this point we know the queue is full. */
|
||||
|
||||
/* Pickup thread suspension list head pointer. */
|
||||
thread_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
|
||||
/* Now determine if there is a queue front suspension active. */
|
||||
|
||||
/* Is the front suspension flag set? */
|
||||
if (thread_ptr -> tx_thread_suspend_option == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, a queue front suspension is present. */
|
||||
|
||||
/* Return the message associated with this suspension. */
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
destination = TX_VOID_TO_ULONG_POINTER_CONVERT(destination_ptr);
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Message is now in the caller's destination. See if this is the only suspended thread
|
||||
on the list. */
|
||||
suspended_count--;
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
queue_ptr -> tx_queue_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count;
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At this point, we know that the queue is full and there
|
||||
are one or more threads suspended trying to send another
|
||||
message to this queue. */
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = queue_ptr -> tx_queue_read;
|
||||
destination = TX_VOID_TO_ULONG_POINTER_CONVERT(destination_ptr);
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Determine if we are at the end. */
|
||||
if (source == queue_ptr -> tx_queue_end)
|
||||
{
|
||||
|
||||
/* Yes, wrap around to the beginning. */
|
||||
source = queue_ptr -> tx_queue_start;
|
||||
}
|
||||
|
||||
/* Setup the queue read pointer. */
|
||||
queue_ptr -> tx_queue_read = source;
|
||||
|
||||
/* Disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Interrupts are enabled briefly here to keep the interrupt
|
||||
lockout time deterministic. */
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
/* Decrement the preemption disable variable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
destination = queue_ptr -> tx_queue_write;
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Determine if we are at the end. */
|
||||
if (destination == queue_ptr -> tx_queue_end)
|
||||
{
|
||||
|
||||
/* Yes, wrap around to the beginning. */
|
||||
destination = queue_ptr -> tx_queue_start;
|
||||
}
|
||||
|
||||
/* Adjust the write pointer. */
|
||||
queue_ptr -> tx_queue_write = destination;
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
thread_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
|
||||
/* Message is now in the queue. See if this is the only suspended thread
|
||||
on the list. */
|
||||
suspended_count--;
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
queue_ptr -> tx_queue_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count;
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the request specifies suspension. */
|
||||
else if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_QUEUE_EMPTY;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total queue empty suspensions counter. */
|
||||
_tx_queue_performance_empty_suspension_count++;
|
||||
|
||||
/* Increment the number of empty suspensions on this queue. */
|
||||
queue_ptr -> tx_queue_performance_empty_suspension_count++;
|
||||
#endif
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_queue_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this queue control
|
||||
block and the source pointer. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) queue_ptr;
|
||||
thread_ptr -> tx_thread_additional_suspend_info = (VOID *) destination_ptr;
|
||||
thread_ptr -> tx_thread_suspend_option = TX_FALSE;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
queue_ptr -> tx_queue_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = queue_ptr -> tx_queue_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Increment the suspended thread count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count + ((UINT) 1);
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_QUEUE_SUSP;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Immediate return, return error completion. */
|
||||
status = TX_QUEUE_EMPTY;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
426
common_smp/src/tx_queue_send.c
Normal file
426
common_smp/src/tx_queue_send.c
Normal file
@@ -0,0 +1,426 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_send PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places a message into the specified queue. If there */
|
||||
/* is no room in the queue, this function waits according to the */
|
||||
/* option specified. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block */
|
||||
/* source_ptr Pointer to message source */
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread routine */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* _tx_thread_system_suspend Suspend thread routine */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
ULONG *source;
|
||||
ULONG *destination;
|
||||
UINT size;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*queue_send_notify)(struct TX_QUEUE_STRUCT *notify_queue_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
/* Default the status to TX_SUCCESS. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Disable interrupts to place message in the queue. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total messages sent counter. */
|
||||
_tx_queue_performance_messages_sent_count++;
|
||||
|
||||
/* Increment the number of messages sent to this queue. */
|
||||
queue_ptr -> tx_queue_performance_messages_sent_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_SEND, queue_ptr, TX_POINTER_TO_ULONG_CONVERT(source_ptr), wait_option, queue_ptr -> tx_queue_enqueued, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_QUEUE_SEND_INSERT
|
||||
|
||||
/* Pickup the thread suspension count. */
|
||||
suspended_count = queue_ptr -> tx_queue_suspended_count;
|
||||
|
||||
/* Determine if there is room in the queue. */
|
||||
if (queue_ptr -> tx_queue_available_storage != TX_NO_MESSAGES)
|
||||
{
|
||||
|
||||
/* There is room for the message in the queue. */
|
||||
|
||||
/* Determine if there are suspended on this queue. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No suspended threads, simply place the message in the queue. */
|
||||
|
||||
/* Reduce the amount of available storage. */
|
||||
queue_ptr -> tx_queue_available_storage--;
|
||||
|
||||
/* Increase the enqueued count. */
|
||||
queue_ptr -> tx_queue_enqueued++;
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = TX_VOID_TO_ULONG_POINTER_CONVERT(source_ptr);
|
||||
destination = queue_ptr -> tx_queue_write;
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Determine if we are at the end. */
|
||||
if (destination == queue_ptr -> tx_queue_end)
|
||||
{
|
||||
|
||||
/* Yes, wrap around to the beginning. */
|
||||
destination = queue_ptr -> tx_queue_start;
|
||||
}
|
||||
|
||||
/* Adjust the write pointer. */
|
||||
queue_ptr -> tx_queue_write = destination;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this queue. */
|
||||
queue_send_notify = queue_ptr -> tx_queue_send_notify;
|
||||
#endif
|
||||
|
||||
/* No thread suspended, just return to caller. */
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (queue_send_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application queue send notification. */
|
||||
(queue_send_notify)(queue_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* There is a thread suspended on an empty queue. Simply
|
||||
copy the message to the suspended thread's destination
|
||||
pointer. */
|
||||
|
||||
/* Pickup the head of the suspension list. */
|
||||
thread_ptr = queue_ptr -> tx_queue_suspension_list;
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
suspended_count--;
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
queue_ptr -> tx_queue_suspension_list = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
queue_ptr -> tx_queue_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count;
|
||||
|
||||
/* Prepare for resumption of the thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Setup source and destination pointers. */
|
||||
source = TX_VOID_TO_ULONG_POINTER_CONVERT(source_ptr);
|
||||
destination = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info);
|
||||
size = queue_ptr -> tx_queue_message_size;
|
||||
|
||||
/* Copy message. Note that the source and destination pointers are
|
||||
incremented by the macro. */
|
||||
TX_QUEUE_MESSAGE_COPY(source, destination, size)
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this queue. */
|
||||
queue_send_notify = queue_ptr -> tx_queue_send_notify;
|
||||
#endif
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (queue_send_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application queue send notification. */
|
||||
(queue_send_notify)(queue_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, the queue is full. Determine if suspension is requested. */
|
||||
else if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_QUEUE_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Yes, prepare for suspension of this thread. */
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total number of queue full suspensions. */
|
||||
_tx_queue_performance_full_suspension_count++;
|
||||
|
||||
/* Increment the number of full suspensions on this queue. */
|
||||
queue_ptr -> tx_queue_performance_full_suspension_count++;
|
||||
#endif
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_queue_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this queue control
|
||||
block and the source pointer. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) queue_ptr;
|
||||
thread_ptr -> tx_thread_additional_suspend_info = (VOID *) source_ptr;
|
||||
thread_ptr -> tx_thread_suspend_option = TX_FALSE;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
queue_ptr -> tx_queue_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = queue_ptr -> tx_queue_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Increment the suspended thread count. */
|
||||
queue_ptr -> tx_queue_suspended_count = suspended_count + ((UINT) 1);
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_QUEUE_SUSP;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the notify callback routine for this queue. */
|
||||
queue_send_notify = queue_ptr -> tx_queue_send_notify;
|
||||
#endif
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if a notify callback is required. */
|
||||
if (thread_ptr -> tx_thread_suspend_status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Determine if there is a notify callback. */
|
||||
if (queue_send_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Call application queue send notification. */
|
||||
(queue_send_notify)(queue_ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Otherwise, just return a queue full error message to the caller. */
|
||||
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the number of full non-suspensions on this queue. */
|
||||
queue_ptr -> tx_queue_performance_full_error_count++;
|
||||
|
||||
/* Increment the total number of full non-suspensions. */
|
||||
_tx_queue_performance_full_error_count++;
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return error completion. */
|
||||
status = TX_QUEUE_FULL;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
107
common_smp/src/tx_queue_send_notify.c
Normal file
107
common_smp/src/tx_queue_send_notify.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Queue */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_queue.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_queue_send_notify PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function registers an application callback function that is */
|
||||
/* called whenever a messages is sent to this queue. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* queue_ptr Pointer to queue control block*/
|
||||
/* queue_send_notify Application callback function */
|
||||
/* (TX_NULL disables notify) */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_queue_send_notify(TX_QUEUE *queue_ptr, VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr))
|
||||
{
|
||||
|
||||
#ifdef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
TX_QUEUE_NOT_USED(queue_ptr);
|
||||
TX_QUEUE_SEND_NOTIFY_NOT_USED(queue_send_notify);
|
||||
|
||||
/* Feature is not enabled, return error. */
|
||||
return(TX_FEATURE_NOT_ENABLED);
|
||||
#else
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_SEND_NOTIFY, queue_ptr, 0, 0, 0, TX_TRACE_QUEUE_EVENTS)
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_EL_QUEUE_SEND_NOTIFY_INSERT
|
||||
|
||||
/* Setup queue send notification callback function. */
|
||||
queue_ptr -> tx_queue_send_notify = queue_send_notify;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success to caller. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
243
common_smp/src/tx_semaphore_ceiling_put.c
Normal file
243
common_smp/src/tx_semaphore_ceiling_put.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_ceiling_put PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function puts an instance into the specified counting */
|
||||
/* semaphore up to the specified semaphore ceiling. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore */
|
||||
/* ceiling Maximum value of semaphore */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume */
|
||||
/* thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_ceiling_put(TX_SEMAPHORE *semaphore_ptr, ULONG ceiling)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*semaphore_put_notify)(struct TX_SEMAPHORE_STRUCT *notify_semaphore_ptr);
|
||||
#endif
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default the status to TX_SUCCESS. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Disable interrupts to put an instance back to the semaphore. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total semaphore put counter. */
|
||||
_tx_semaphore_performance_put_count++;
|
||||
|
||||
/* Increment the number of puts on this semaphore. */
|
||||
semaphore_ptr -> tx_semaphore_performance_put_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_CEILING_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count, semaphore_ptr -> tx_semaphore_suspended_count, ceiling, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_CEILING_PUT_INSERT
|
||||
|
||||
/* Pickup the number of suspended threads. */
|
||||
suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
|
||||
/* Determine if there are any threads suspended on the semaphore. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Determine if the ceiling has been exceeded. */
|
||||
if (semaphore_ptr -> tx_semaphore_count >= ceiling)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return an error. */
|
||||
status = TX_CEILING_EXCEEDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Increment the semaphore count. */
|
||||
semaphore_ptr -> tx_semaphore_count++;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the application notify function. */
|
||||
semaphore_put_notify = semaphore_ptr -> tx_semaphore_put_notify;
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if notification is required. */
|
||||
if (semaphore_put_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, call the appropriate notify callback function. */
|
||||
(semaphore_put_notify)(semaphore_ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return successful completion status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* Pickup the pointer to the first suspended thread. */
|
||||
thread_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
suspended_count--;
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
semaphore_ptr -> tx_semaphore_suspended_count = suspended_count;
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the application notify function. */
|
||||
semaphore_put_notify = semaphore_ptr -> tx_semaphore_put_notify;
|
||||
#endif
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if notification is required. */
|
||||
if (semaphore_put_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, call the appropriate notify callback function. */
|
||||
(semaphore_put_notify)(semaphore_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return successful completion. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
215
common_smp/src/tx_semaphore_cleanup.c
Normal file
215
common_smp/src/tx_semaphore_cleanup.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_cleanup PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes semaphore timeout and thread terminate */
|
||||
/* actions that require the semaphore data structures to be cleaned */
|
||||
/* up. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to suspended thread's */
|
||||
/* control block */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_timeout Thread timeout processing */
|
||||
/* _tx_thread_terminate Thread terminate processing */
|
||||
/* _tx_thread_wait_abort Thread wait abort processing */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_semaphore_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
#endif
|
||||
|
||||
TX_SEMAPHORE *semaphore_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts to remove the suspended thread from the semaphore. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the cleanup is still required. */
|
||||
if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_semaphore_cleanup))
|
||||
{
|
||||
|
||||
/* Check for valid suspension sequence. */
|
||||
if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence)
|
||||
{
|
||||
|
||||
/* Setup pointer to semaphore control block. */
|
||||
semaphore_ptr = TX_VOID_TO_SEMAPHORE_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
|
||||
/* Check for a NULL semaphore pointer. */
|
||||
if (semaphore_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Check for a valid semaphore ID. */
|
||||
if (semaphore_ptr -> tx_semaphore_id == TX_SEMAPHORE_ID)
|
||||
{
|
||||
|
||||
/* Determine if there are any thread suspensions. */
|
||||
if (semaphore_ptr -> tx_semaphore_suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
#else
|
||||
|
||||
/* Setup pointer to semaphore control block. */
|
||||
semaphore_ptr = TX_VOID_TO_SEMAPHORE_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block);
|
||||
#endif
|
||||
|
||||
/* Yes, we still have thread suspension! */
|
||||
|
||||
/* Clear the suspension cleanup flag. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Decrement the suspended count. */
|
||||
semaphore_ptr -> tx_semaphore_suspended_count--;
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same suspension list. */
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Determine if we need to update the head pointer. */
|
||||
if (semaphore_ptr -> tx_semaphore_suspension_list == thread_ptr)
|
||||
{
|
||||
|
||||
/* Update the list head pointer. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = next_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we need to determine if this cleanup is from a terminate, timeout,
|
||||
or from a wait abort. */
|
||||
if (thread_ptr -> tx_thread_state == TX_SEMAPHORE_SUSP)
|
||||
{
|
||||
|
||||
/* Timeout condition and the thread is still suspended on the semaphore.
|
||||
Setup return error status and resume the thread. */
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total timeouts counter. */
|
||||
_tx_semaphore_performance_timeout_count++;
|
||||
|
||||
/* Increment the number of timeouts on this semaphore. */
|
||||
semaphore_ptr -> tx_semaphore_performance_timeout_count++;
|
||||
#endif
|
||||
|
||||
/* Setup return status. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_NO_INSTANCE;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
}
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
|
||||
142
common_smp/src/tx_semaphore_create.c
Normal file
142
common_smp/src/tx_semaphore_create.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_create PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a counting semaphore with the initial count */
|
||||
/* specified in this call. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* name_ptr Pointer to semaphore name */
|
||||
/* initial_count Initial semaphore count */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_create(TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_SEMAPHORE *next_semaphore;
|
||||
TX_SEMAPHORE *previous_semaphore;
|
||||
|
||||
|
||||
/* Initialize semaphore control block to all zeros. */
|
||||
TX_MEMSET(semaphore_ptr, 0, (sizeof(TX_SEMAPHORE)));
|
||||
|
||||
/* Setup the basic semaphore fields. */
|
||||
semaphore_ptr -> tx_semaphore_name = name_ptr;
|
||||
semaphore_ptr -> tx_semaphore_count = initial_count;
|
||||
|
||||
/* Disable interrupts to place the semaphore on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Setup the semaphore ID to make it valid. */
|
||||
semaphore_ptr -> tx_semaphore_id = TX_SEMAPHORE_ID;
|
||||
|
||||
/* Place the semaphore on the list of created semaphores. First,
|
||||
check for an empty list. */
|
||||
if (_tx_semaphore_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created semaphore list is empty. Add semaphore to empty list. */
|
||||
_tx_semaphore_created_ptr = semaphore_ptr;
|
||||
semaphore_ptr -> tx_semaphore_created_next = semaphore_ptr;
|
||||
semaphore_ptr -> tx_semaphore_created_previous = semaphore_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_semaphore = _tx_semaphore_created_ptr;
|
||||
previous_semaphore = next_semaphore -> tx_semaphore_created_previous;
|
||||
|
||||
/* Place the new semaphore in the list. */
|
||||
next_semaphore -> tx_semaphore_created_previous = semaphore_ptr;
|
||||
previous_semaphore -> tx_semaphore_created_next = semaphore_ptr;
|
||||
|
||||
/* Setup this semaphore's next and previous created links. */
|
||||
semaphore_ptr -> tx_semaphore_created_previous = previous_semaphore;
|
||||
semaphore_ptr -> tx_semaphore_created_next = next_semaphore;
|
||||
}
|
||||
|
||||
/* Increment the created count. */
|
||||
_tx_semaphore_created_count++;
|
||||
|
||||
/* Optional semaphore create extended processing. */
|
||||
TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr)
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_SEMAPHORE, semaphore_ptr, name_ptr, initial_count, 0)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_CREATE, semaphore_ptr, initial_count, TX_POINTER_TO_ULONG_CONVERT(&next_semaphore), 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_CREATE_INSERT
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
207
common_smp/src/tx_semaphore_delete.c
Normal file
207
common_smp/src/tx_semaphore_delete.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function deletes the specified semaphore. All threads */
|
||||
/* suspended on the semaphore are resumed with the TX_DELETED status */
|
||||
/* code. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Successful completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_delete(TX_SEMAPHORE *semaphore_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
UINT suspended_count;
|
||||
TX_SEMAPHORE *next_semaphore;
|
||||
TX_SEMAPHORE *previous_semaphore;
|
||||
|
||||
|
||||
/* Disable interrupts to remove the semaphore from the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_DELETE, semaphore_ptr, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), 0, 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Optional semaphore delete extended processing. */
|
||||
TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(semaphore_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_DELETE_INSERT
|
||||
|
||||
/* Clear the semaphore ID to make it invalid. */
|
||||
semaphore_ptr -> tx_semaphore_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the number of semaphores. */
|
||||
_tx_semaphore_created_count--;
|
||||
|
||||
/* See if the semaphore is the only one on the list. */
|
||||
if (_tx_semaphore_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created semaphore, just set the created list to NULL. */
|
||||
_tx_semaphore_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Link-up the neighbors. */
|
||||
next_semaphore = semaphore_ptr -> tx_semaphore_created_next;
|
||||
previous_semaphore = semaphore_ptr -> tx_semaphore_created_previous;
|
||||
next_semaphore -> tx_semaphore_created_previous = previous_semaphore;
|
||||
previous_semaphore -> tx_semaphore_created_next = next_semaphore;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_semaphore_created_ptr == semaphore_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_semaphore_created_ptr = next_semaphore;
|
||||
}
|
||||
}
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Pickup the suspension information. */
|
||||
thread_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = TX_NULL;
|
||||
suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
semaphore_ptr -> tx_semaphore_suspended_count = TX_NO_SUSPENSIONS;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Walk through the semaphore list to resume any and all threads suspended
|
||||
on this semaphore. */
|
||||
while (suspended_count != TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
suspended_count--;
|
||||
|
||||
/* Lockout interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Clear the cleanup pointer, this prevents the timeout from doing
|
||||
anything. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
/* Set the return status in the thread to TX_DELETED. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_DELETED;
|
||||
|
||||
/* Move the thread pointer ahead. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption again. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Move to next thread. */
|
||||
thread_ptr = next_thread;
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_SEMAPHORE_DELETE_PORT_COMPLETION(semaphore_ptr)
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Release previous preempt disable. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
|
||||
/* Return TX_SUCCESS. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
232
common_smp/src/tx_semaphore_get.c
Normal file
232
common_smp/src/tx_semaphore_get.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function gets an instance from the specified counting */
|
||||
/* semaphore. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* wait_option Suspension option */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Suspend thread service */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default the status to TX_SUCCESS. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Disable interrupts to get an instance from the semaphore. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total semaphore get counter. */
|
||||
_tx_semaphore_performance_get_count++;
|
||||
|
||||
/* Increment the number of attempts to get this semaphore. */
|
||||
semaphore_ptr -> tx_semaphore_performance_get_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_GET, semaphore_ptr, wait_option, semaphore_ptr -> tx_semaphore_count, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_GET_INSERT
|
||||
|
||||
/* Determine if there is an instance of the semaphore. */
|
||||
if (semaphore_ptr -> tx_semaphore_count != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Decrement the semaphore count. */
|
||||
semaphore_ptr -> tx_semaphore_count--;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Determine if the request specifies suspension. */
|
||||
else if (wait_option != TX_NO_WAIT)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_NO_INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Prepare for suspension of this thread. */
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total semaphore suspensions counter. */
|
||||
_tx_semaphore_performance_suspension_count++;
|
||||
|
||||
/* Increment the number of suspensions on this semaphore. */
|
||||
semaphore_ptr -> tx_semaphore_performance_suspension_count++;
|
||||
#endif
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Setup cleanup routine pointer. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = &(_tx_semaphore_cleanup);
|
||||
|
||||
/* Setup cleanup information, i.e. this semaphore control
|
||||
block. */
|
||||
thread_ptr -> tx_thread_suspend_control_block = (VOID *) semaphore_ptr;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the suspension sequence number, which is used to identify
|
||||
this suspension event. */
|
||||
thread_ptr -> tx_thread_suspension_sequence++;
|
||||
#endif
|
||||
|
||||
/* Setup suspension list. */
|
||||
if (semaphore_ptr -> tx_semaphore_suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* No other threads are suspended. Setup the head pointer and
|
||||
just setup this threads pointers to itself. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add current thread to the end. */
|
||||
next_thread = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
thread_ptr -> tx_thread_suspended_next = next_thread;
|
||||
previous_thread = next_thread -> tx_thread_suspended_previous;
|
||||
thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = thread_ptr;
|
||||
next_thread -> tx_thread_suspended_previous = thread_ptr;
|
||||
}
|
||||
|
||||
/* Increment the number of suspensions. */
|
||||
semaphore_ptr -> tx_semaphore_suspended_count++;
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SEMAPHORE_SUSP;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, wait_option);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Return the completion status. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Immediate return, return error completion. */
|
||||
status = TX_NO_INSTANCE;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
139
common_smp/src/tx_semaphore_info_get.c
Normal file
139
common_smp/src/tx_semaphore_info_get.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified semaphore. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* name Destination for the semaphore name*/
|
||||
/* current_value Destination for current value of */
|
||||
/* the semaphore */
|
||||
/* first_suspended Destination for pointer of first */
|
||||
/* thread suspended on semaphore */
|
||||
/* suspended_count Destination for suspended count */
|
||||
/* next_semaphore Destination for pointer to next */
|
||||
/* semaphore on the created list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_info_get(TX_SEMAPHORE *semaphore_ptr, CHAR **name, ULONG *current_value,
|
||||
TX_THREAD **first_suspended, ULONG *suspended_count,
|
||||
TX_SEMAPHORE **next_semaphore)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_INFO_GET, semaphore_ptr, 0, 0, 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the semaphore. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = semaphore_ptr -> tx_semaphore_name;
|
||||
}
|
||||
|
||||
/* Retrieve the current value of the semaphore. */
|
||||
if (current_value != TX_NULL)
|
||||
{
|
||||
|
||||
*current_value = semaphore_ptr -> tx_semaphore_count;
|
||||
}
|
||||
|
||||
/* Retrieve the first thread suspended on this semaphore. */
|
||||
if (first_suspended != TX_NULL)
|
||||
{
|
||||
|
||||
*first_suspended = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
}
|
||||
|
||||
/* Retrieve the number of threads suspended on this semaphore. */
|
||||
if (suspended_count != TX_NULL)
|
||||
{
|
||||
|
||||
*suspended_count = (ULONG) semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer to the next semaphore created. */
|
||||
if (next_semaphore != TX_NULL)
|
||||
{
|
||||
|
||||
*next_semaphore = semaphore_ptr -> tx_semaphore_created_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
129
common_smp/src/tx_semaphore_initialize.c
Normal file
129
common_smp/src/tx_semaphore_initialize.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
#ifndef TX_INLINE_INITIALIZATION
|
||||
|
||||
/* Locate semaphore component data in this file. */
|
||||
|
||||
/* Define the head pointer of the created semaphore list. */
|
||||
|
||||
TX_SEMAPHORE * _tx_semaphore_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created semaphores. */
|
||||
|
||||
ULONG _tx_semaphore_created_count;
|
||||
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of semaphore puts. */
|
||||
|
||||
ULONG _tx_semaphore_performance_put_count;
|
||||
|
||||
|
||||
/* Define the total number of semaphore gets. */
|
||||
|
||||
ULONG _tx_semaphore_performance_get_count;
|
||||
|
||||
|
||||
/* Define the total number of semaphore suspensions. */
|
||||
|
||||
ULONG _tx_semaphore_performance_suspension_count;
|
||||
|
||||
|
||||
/* Define the total number of semaphore timeouts. */
|
||||
|
||||
ULONG _tx_semaphore_performance_timeout_count;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_initialize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the semaphore component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_semaphore_initialize(VOID)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the head pointer of the created semaphores list and the
|
||||
number of semaphores created. */
|
||||
_tx_semaphore_created_ptr = TX_NULL;
|
||||
_tx_semaphore_created_count = TX_EMPTY;
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize semaphore performance counters. */
|
||||
_tx_semaphore_performance_put_count = ((ULONG) 0);
|
||||
_tx_semaphore_performance_get_count = ((ULONG) 0);
|
||||
_tx_semaphore_performance_suspension_count = ((ULONG) 0);
|
||||
_tx_semaphore_performance_timeout_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
201
common_smp/src/tx_semaphore_performance_info_get.c
Normal file
201
common_smp/src/tx_semaphore_performance_info_get.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_semaphore.h"
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* semaphore. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* puts Destination for the number of */
|
||||
/* puts on to this semaphore */
|
||||
/* gets Destination for the number of */
|
||||
/* gets on this semaphore */
|
||||
/* suspensions Destination for the number of */
|
||||
/* suspensions on this semaphore */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* on this semaphore */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_performance_info_get(TX_SEMAPHORE *semaphore_ptr, ULONG *puts, ULONG *gets,
|
||||
ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (semaphore_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Semaphore pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the semaphore ID is invalid. */
|
||||
else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID)
|
||||
{
|
||||
|
||||
/* Semaphore pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_PERFORMANCE_INFO_GET, semaphore_ptr, 0, 0, 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the number of puts on this semaphore. */
|
||||
if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
*puts = semaphore_ptr -> tx_semaphore_performance_put_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of gets on this semaphore. */
|
||||
if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
*gets = semaphore_ptr -> tx_semaphore_performance_get_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of suspensions on this semaphore. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = semaphore_ptr -> tx_semaphore_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the number of timeouts on this semaphore. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = semaphore_ptr -> tx_semaphore_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return successful completion. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
#else
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (semaphore_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
174
common_smp/src/tx_semaphore_performance_system_info_get.c
Normal file
174
common_smp/src/tx_semaphore_performance_system_info_get.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_semaphore.h"
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves system semaphore performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* puts Destination for total number of */
|
||||
/* semaphore puts */
|
||||
/* gets Destination for total number of */
|
||||
/* semaphore gets */
|
||||
/* suspensions Destination for total number of */
|
||||
/* semaphore suspensions */
|
||||
/* timeouts Destination for total number of */
|
||||
/* timeouts */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_performance_system_info_get(ULONG *puts, ULONG *gets, ULONG *suspensions, ULONG *timeouts)
|
||||
{
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the total number of semaphore puts. */
|
||||
if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
*puts = _tx_semaphore_performance_put_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of semaphore gets. */
|
||||
if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
*gets = _tx_semaphore_performance_get_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of semaphore suspensions. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = _tx_semaphore_performance_suspension_count;
|
||||
}
|
||||
|
||||
/* Retrieve the total number of semaphore timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_semaphore_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (puts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (gets != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
251
common_smp/src/tx_semaphore_prioritize.c
Normal file
251
common_smp/src/tx_semaphore_prioritize.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_prioritize PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places the highest priority suspended thread at the */
|
||||
/* front of the suspension list. All other threads remain in the same */
|
||||
/* FIFO suspension order. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_prioritize(TX_SEMAPHORE *semaphore_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *priority_thread_ptr;
|
||||
TX_THREAD *head_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT list_changed;
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_PRIORITIZE, semaphore_ptr, semaphore_ptr -> tx_semaphore_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&suspended_count), 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_PRIORITIZE_INSERT
|
||||
|
||||
/* Pickup the suspended count. */
|
||||
suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
|
||||
/* Determine if there are fewer than 2 suspended threads. */
|
||||
if (suspended_count < ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Determine if there how many threads are suspended on this semaphore. */
|
||||
else if (suspended_count == ((UINT) 2))
|
||||
{
|
||||
|
||||
/* Pickup the head pointer and the next pointer. */
|
||||
head_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
next_thread = head_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Determine if the next suspended thread has a higher priority. */
|
||||
if ((next_thread -> tx_thread_priority) < (head_ptr -> tx_thread_priority))
|
||||
{
|
||||
|
||||
/* Yes, move the list head to the next thread. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = next_thread;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the suspension count and head pointer. */
|
||||
head_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the list changed flag to false. */
|
||||
list_changed = TX_FALSE;
|
||||
|
||||
/* Search through the list to find the highest priority thread. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Is the current thread higher priority? */
|
||||
if (thread_ptr -> tx_thread_priority < priority_thread_ptr -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, remember that this thread is the highest priority. */
|
||||
priority_thread_ptr = thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts temporarily. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if any changes to the list have occurred while
|
||||
interrupts were enabled. */
|
||||
|
||||
/* Is the list head the same? */
|
||||
if (head_ptr != semaphore_ptr -> tx_semaphore_suspension_list)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is the suspended count the same? */
|
||||
if (suspended_count != semaphore_ptr -> tx_semaphore_suspended_count)
|
||||
{
|
||||
|
||||
/* The list head has changed, set the list changed flag. */
|
||||
list_changed = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the list has changed. */
|
||||
if (list_changed == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Yes, everything is the same... move the thread pointer to the next thread. */
|
||||
thread_ptr = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, the list is been modified so we need to start the search over. */
|
||||
|
||||
/* Save the suspension count and head pointer. */
|
||||
head_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
|
||||
/* Default the highest priority thread to the thread at the front of the list. */
|
||||
priority_thread_ptr = head_ptr;
|
||||
|
||||
/* Setup search pointer. */
|
||||
thread_ptr = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
|
||||
/* Reset the list changed flag. */
|
||||
list_changed = TX_FALSE;
|
||||
}
|
||||
|
||||
} while (thread_ptr != head_ptr);
|
||||
|
||||
/* Release preemption. */
|
||||
_tx_thread_preempt_disable--;
|
||||
|
||||
/* Now determine if the highest priority thread is at the front
|
||||
of the list. */
|
||||
if (priority_thread_ptr != head_ptr)
|
||||
{
|
||||
|
||||
/* No, we need to move the highest priority suspended thread to the
|
||||
front of the list. */
|
||||
|
||||
/* First, remove the highest priority thread by updating the
|
||||
adjacent suspended threads. */
|
||||
next_thread = priority_thread_ptr -> tx_thread_suspended_next;
|
||||
previous_thread = priority_thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
|
||||
/* Now, link the highest priority thread at the front of the list. */
|
||||
previous_thread = head_ptr -> tx_thread_suspended_previous;
|
||||
priority_thread_ptr -> tx_thread_suspended_next = head_ptr;
|
||||
priority_thread_ptr -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = priority_thread_ptr;
|
||||
head_ptr -> tx_thread_suspended_previous = priority_thread_ptr;
|
||||
|
||||
/* Move the list head pointer to the highest priority suspended thread. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = priority_thread_ptr;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
222
common_smp/src/tx_semaphore_put.c
Normal file
222
common_smp/src/tx_semaphore_put.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_put PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function puts an instance into the specified counting */
|
||||
/* semaphore. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore control block*/
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_SUCCESS Success completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_resume Resume thread service */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_put(TX_SEMAPHORE *semaphore_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*semaphore_put_notify)(struct TX_SEMAPHORE_STRUCT *notify_semaphore_ptr);
|
||||
#endif
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
UINT suspended_count;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
|
||||
|
||||
/* Disable interrupts to put an instance back to the semaphore. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total semaphore put counter. */
|
||||
_tx_semaphore_performance_put_count++;
|
||||
|
||||
/* Increment the number of puts on this semaphore. */
|
||||
semaphore_ptr -> tx_semaphore_performance_put_count++;
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count, semaphore_ptr -> tx_semaphore_suspended_count, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_SEMAPHORE_PUT_INSERT
|
||||
|
||||
/* Pickup the number of suspended threads. */
|
||||
suspended_count = semaphore_ptr -> tx_semaphore_suspended_count;
|
||||
|
||||
/* Determine if there are any threads suspended on the semaphore. */
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Increment the semaphore count. */
|
||||
semaphore_ptr -> tx_semaphore_count++;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the application notify function. */
|
||||
semaphore_put_notify = semaphore_ptr -> tx_semaphore_put_notify;
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if notification is required. */
|
||||
if (semaphore_put_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, call the appropriate notify callback function. */
|
||||
(semaphore_put_notify)(semaphore_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* A thread is suspended on this semaphore. */
|
||||
|
||||
/* Pickup the pointer to the first suspended thread. */
|
||||
thread_ptr = semaphore_ptr -> tx_semaphore_suspension_list;
|
||||
|
||||
/* Remove the suspended thread from the list. */
|
||||
|
||||
/* See if this is the only suspended thread on the list. */
|
||||
suspended_count--;
|
||||
if (suspended_count == TX_NO_SUSPENSIONS)
|
||||
{
|
||||
|
||||
/* Yes, the only suspended thread. */
|
||||
|
||||
/* Update the head pointer. */
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more thread is on the same expiration list. */
|
||||
|
||||
/* Update the list head pointer. */
|
||||
next_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
semaphore_ptr -> tx_semaphore_suspension_list = next_thread;
|
||||
|
||||
/* Update the links of the adjacent threads. */
|
||||
previous_thread = thread_ptr -> tx_thread_suspended_previous;
|
||||
next_thread -> tx_thread_suspended_previous = previous_thread;
|
||||
previous_thread -> tx_thread_suspended_next = next_thread;
|
||||
}
|
||||
|
||||
/* Decrement the suspension count. */
|
||||
semaphore_ptr -> tx_semaphore_suspended_count = suspended_count;
|
||||
|
||||
/* Prepare for resumption of the first thread. */
|
||||
|
||||
/* Clear cleanup routine to avoid timeout. */
|
||||
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the application notify function. */
|
||||
semaphore_put_notify = semaphore_ptr -> tx_semaphore_put_notify;
|
||||
#endif
|
||||
|
||||
/* Put return status into the thread control block. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if notification is required. */
|
||||
if (semaphore_put_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, call the appropriate notify callback function. */
|
||||
(semaphore_put_notify)(semaphore_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return successful completion. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
107
common_smp/src/tx_semaphore_put_notify.c
Normal file
107
common_smp/src/tx_semaphore_put_notify.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Semaphore */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_semaphore.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_semaphore_put_notify PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function registers an application callback function that is */
|
||||
/* called whenever the this semaphore is put. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* semaphore_ptr Pointer to semaphore */
|
||||
/* semaphore_put_notify Application callback function */
|
||||
/* (TX_NULL disables notify) */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_semaphore_put_notify(TX_SEMAPHORE *semaphore_ptr, VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr))
|
||||
{
|
||||
|
||||
#ifdef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
TX_SEMAPHORE_NOT_USED(semaphore_ptr);
|
||||
TX_SEMAPHORE_PUT_NOTIFY_NOT_USED(semaphore_put_notify);
|
||||
|
||||
/* Feature is not enabled, return error. */
|
||||
return(TX_FEATURE_NOT_ENABLED);
|
||||
#else
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_PUT_NOTIFY, semaphore_ptr, 0, 0, 0, TX_TRACE_SEMAPHORE_EVENTS)
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_EL_SEMAPHORE_PUT_NOTIFY_INSERT
|
||||
|
||||
/* Setup semaphore put notification callback function. */
|
||||
semaphore_ptr -> tx_semaphore_put_notify = semaphore_put_notify;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success to caller. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
346
common_smp/src/tx_thread_create.c
Normal file
346
common_smp/src/tx_thread_create.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_initialize.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_create PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function creates a thread and places it on the list of created */
|
||||
/* threads. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Thread control block pointer */
|
||||
/* name_ptr Pointer to thread name string */
|
||||
/* entry_function Entry function of the thread */
|
||||
/* entry_input 32-bit input value to thread */
|
||||
/* stack_start Pointer to start of stack */
|
||||
/* stack_size Stack size in bytes */
|
||||
/* priority Priority of thread (0-31) */
|
||||
/* preempt_threshold Preemption threshold */
|
||||
/* time_slice Thread time-slice value */
|
||||
/* auto_start Automatic start selection */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* return status Thread create return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list Rebalance execution list */
|
||||
/* _tx_thread_stack_build Build initial thread stack */
|
||||
/* _tx_thread_system_resume Resume automatic start thread */
|
||||
/* _tx_thread_system_ni_resume Noninterruptable resume thread*/
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* _tx_timer_initialize Create system timer thread */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input,
|
||||
VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold,
|
||||
ULONG time_slice, UINT auto_start)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT core_index;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UCHAR *temp_ptr;
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
ULONG new_stack_start;
|
||||
ULONG updated_stack_start;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_STACK_FILLING
|
||||
|
||||
/* Set the thread stack to a pattern prior to creating the initial
|
||||
stack frame. This pattern is used by the stack checking routines
|
||||
to see how much has been used. */
|
||||
TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size);
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Ensure that there are two ULONG of 0xEF patterns at the top and
|
||||
bottom of the thread's stack. This will be used to check for stack
|
||||
overflow conditions during run-time. */
|
||||
stack_size = ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG));
|
||||
|
||||
/* Ensure the starting stack address is evenly aligned. */
|
||||
new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start);
|
||||
updated_stack_start = ((((ULONG) new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1))));
|
||||
|
||||
/* Determine if the starting stack address is different. */
|
||||
if (new_stack_start != updated_stack_start)
|
||||
{
|
||||
|
||||
/* Yes, subtract another ULONG from the size to avoid going past the stack area. */
|
||||
stack_size = stack_size - (sizeof(ULONG));
|
||||
}
|
||||
|
||||
/* Update the starting stack pointer. */
|
||||
stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start);
|
||||
#endif
|
||||
|
||||
/* Prepare the thread control block prior to placing it on the created
|
||||
list. */
|
||||
|
||||
/* Initialize thread control block to all zeros. */
|
||||
TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD)));
|
||||
|
||||
/* Place the supplied parameters into the thread's control block. */
|
||||
thread_ptr -> tx_thread_name = name_ptr;
|
||||
thread_ptr -> tx_thread_entry = entry_function;
|
||||
thread_ptr -> tx_thread_entry_parameter = entry_input;
|
||||
thread_ptr -> tx_thread_stack_start = stack_start;
|
||||
thread_ptr -> tx_thread_stack_size = stack_size;
|
||||
thread_ptr -> tx_thread_priority = priority;
|
||||
thread_ptr -> tx_thread_user_priority = priority;
|
||||
thread_ptr -> tx_thread_time_slice = time_slice;
|
||||
thread_ptr -> tx_thread_new_time_slice = time_slice;
|
||||
thread_ptr -> tx_thread_inherit_priority = ((UINT) TX_MAX_PRIORITIES);
|
||||
thread_ptr -> tx_thread_smp_core_executing = ((UINT) TX_THREAD_SMP_MAX_CORES);
|
||||
thread_ptr -> tx_thread_smp_cores_excluded = ((ULONG) 0);
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
thread_ptr -> tx_thread_smp_cores_allowed = ((ULONG) TX_THREAD_SMP_CORE_MASK);
|
||||
#else
|
||||
thread_ptr -> tx_thread_smp_cores_allowed = (((ULONG) 1) << _tx_thread_smp_max_cores) - 1;
|
||||
#endif
|
||||
|
||||
#ifdef TX_THREAD_SMP_ONLY_CORE_0_DEFAULT
|
||||
|
||||
/* Default thread creation such that core0 is the only allowed core for execution, i.e., bit 1 is set to exclude core1. */
|
||||
thread_ptr -> tx_thread_smp_cores_excluded = (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
|
||||
thread_ptr -> tx_thread_smp_cores_allowed = 1;
|
||||
|
||||
/* Default the timers to run on core 0 as well. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_smp_cores_excluded = (TX_THREAD_SMP_CORE_MASK & 0xFFFFFFFE);
|
||||
|
||||
/* Default the mapped to 0 too. */
|
||||
thread_ptr -> tx_thread_smp_core_mapped = 0;
|
||||
#endif
|
||||
|
||||
/* Calculate the end of the thread's stack area. */
|
||||
temp_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start);
|
||||
temp_ptr = (TX_UCHAR_POINTER_ADD(temp_ptr, (stack_size - ((ULONG) 1))));
|
||||
thread_ptr -> tx_thread_stack_end = TX_UCHAR_TO_VOID_POINTER_CONVERT(temp_ptr);
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Preemption-threshold is enabled, setup accordingly. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = preempt_threshold;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = preempt_threshold;
|
||||
#else
|
||||
|
||||
/* Preemption-threshold is disabled, determine if preemption-threshold was required. */
|
||||
if (priority != preempt_threshold)
|
||||
{
|
||||
|
||||
/* Preemption-threshold specified. Since specific preemption-threshold is not supported,
|
||||
disable all preemption. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = ((UINT) 0);
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = ((UINT) 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Preemption-threshold is not specified, just setup with the priority. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = priority;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now fill in the values that are required for thread initialization. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
/* Setup the necessary fields in the thread timer block. */
|
||||
TX_THREAD_CREATE_TIMEOUT_SETUP(thread_ptr)
|
||||
|
||||
/* Perform any additional thread setup activities for tool or user purpose. */
|
||||
TX_THREAD_CREATE_INTERNAL_EXTENSION(thread_ptr)
|
||||
|
||||
/* Call the target specific stack frame building routine to build the
|
||||
thread's initial stack and to setup the actual stack pointer in the
|
||||
control block. */
|
||||
_tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Setup the highest usage stack pointer. */
|
||||
thread_ptr -> tx_thread_stack_highest_ptr = thread_ptr -> tx_thread_stack_ptr;
|
||||
#endif
|
||||
|
||||
/* Prepare to make this thread a member of the created thread list. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Load the thread ID field in the thread control block. */
|
||||
thread_ptr -> tx_thread_id = TX_THREAD_ID;
|
||||
|
||||
/* Place the thread on the list of created threads. First,
|
||||
check for an empty list. */
|
||||
if (_tx_thread_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* The created thread list is empty. Add thread to empty list. */
|
||||
_tx_thread_created_ptr = thread_ptr;
|
||||
thread_ptr -> tx_thread_created_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_created_previous = thread_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This list is not NULL, add to the end of the list. */
|
||||
next_thread = _tx_thread_created_ptr;
|
||||
previous_thread = next_thread -> tx_thread_created_previous;
|
||||
|
||||
/* Place the new thread in the list. */
|
||||
next_thread -> tx_thread_created_previous = thread_ptr;
|
||||
previous_thread -> tx_thread_created_next = thread_ptr;
|
||||
|
||||
/* Setup this thread's created links. */
|
||||
thread_ptr -> tx_thread_created_previous = previous_thread;
|
||||
thread_ptr -> tx_thread_created_next = next_thread;
|
||||
}
|
||||
|
||||
/* Increment the thread created count. */
|
||||
_tx_thread_created_count++;
|
||||
|
||||
/* If trace is enabled, register this object. */
|
||||
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, name_ptr, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_CREATE, thread_ptr, priority, TX_POINTER_TO_ULONG_CONVERT(stack_start), stack_size, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Register thread in the thread array structure. */
|
||||
TX_EL_THREAD_REGISTER(thread_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_CREATE_INSERT
|
||||
|
||||
/* Determine if an automatic start was requested. If so, call the resume
|
||||
thread function and then check for a preemption condition. */
|
||||
if (auto_start == TX_AUTO_START)
|
||||
{
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Perform any additional activities for tool or user purpose. */
|
||||
TX_THREAD_CREATE_EXTENSION(thread_ptr)
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore previous interrupt posture. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Perform any additional activities for tool or user purpose. */
|
||||
TX_THREAD_CREATE_EXTENSION(thread_ptr)
|
||||
|
||||
/* Call the resume thread function to make this thread ready. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
|
||||
/* Disable interrupts again. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
/* Determine if the execution list needs to be re-evaluated. */
|
||||
if (_tx_thread_smp_current_state_get() >= TX_INITIALIZE_IN_PROGRESS)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Clear the preemption bit maps, since nothing has yet run during initialization. */
|
||||
TX_MEMSET(_tx_thread_preempted_maps, 0, sizeof(_tx_thread_preempted_maps));
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
_tx_thread_preempted_map_active = ((ULONG) 0);
|
||||
#endif
|
||||
|
||||
/* Clear the entry in the preempted thread list. */
|
||||
_tx_thread_preemption_threshold_list[priority] = TX_NULL;
|
||||
#endif
|
||||
|
||||
/* Set the pointer to the thread currently with preemption-threshold set to NULL. */
|
||||
_tx_thread_preemption__threshold_scheduled = TX_NULL;
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Get the core index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Always return a success. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
166
common_smp/src/tx_thread_delete.c
Normal file
166
common_smp/src/tx_thread_delete.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_delete PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function handles application delete thread requests. The */
|
||||
/* thread to delete must be in a terminated or completed state, */
|
||||
/* otherwise this function just returns an error code. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to suspend */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Return completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_delete(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Lockout interrupts while the thread is being deleted. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Check for proper status of this thread to delete. */
|
||||
if (thread_ptr -> tx_thread_state != TX_COMPLETED)
|
||||
{
|
||||
|
||||
/* Now check for terminated state. */
|
||||
if (thread_ptr -> tx_thread_state != TX_TERMINATED)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Thread not completed or terminated - return an error! */
|
||||
status = TX_DELETE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the delete operation is okay. */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Yes, continue with deleting the thread. */
|
||||
|
||||
/* Perform any additional activities for tool or user purpose. */
|
||||
TX_THREAD_DELETE_EXTENSION(thread_ptr)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_DELETE, thread_ptr, TX_POINTER_TO_ULONG_CONVERT(&next_thread), 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* If trace is enabled, unregister this object. */
|
||||
TX_TRACE_OBJECT_UNREGISTER(thread_ptr)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_DELETE_INSERT
|
||||
|
||||
/* Unregister thread in the thread array structure. */
|
||||
TX_EL_THREAD_UNREGISTER(thread_ptr)
|
||||
|
||||
/* Clear the thread ID to make it invalid. */
|
||||
thread_ptr -> tx_thread_id = TX_CLEAR_ID;
|
||||
|
||||
/* Decrement the number of created threads. */
|
||||
_tx_thread_created_count--;
|
||||
|
||||
/* See if the thread is the only one on the list. */
|
||||
if (_tx_thread_created_count == TX_EMPTY)
|
||||
{
|
||||
|
||||
/* Only created thread, just set the created list to NULL. */
|
||||
_tx_thread_created_ptr = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Otherwise, not the only created thread, link-up the neighbors. */
|
||||
next_thread = thread_ptr -> tx_thread_created_next;
|
||||
previous_thread = thread_ptr -> tx_thread_created_previous;
|
||||
next_thread -> tx_thread_created_previous = previous_thread;
|
||||
previous_thread -> tx_thread_created_next = next_thread;
|
||||
|
||||
/* See if we have to update the created list head pointer. */
|
||||
if (_tx_thread_created_ptr == thread_ptr)
|
||||
{
|
||||
|
||||
/* Yes, move the head pointer to the next link. */
|
||||
_tx_thread_created_ptr = next_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_THREAD_DELETE_PORT_COMPLETION(thread_ptr)
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
109
common_smp/src/tx_thread_entry_exit_notify.c
Normal file
109
common_smp/src/tx_thread_entry_exit_notify.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_entry_exit_notify PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function registers an application entry/exit notification */
|
||||
/* callback routine for the application. Once registered, the callback */
|
||||
/* routine is called when the thread is initially entered and called */
|
||||
/* again when the thread completes or is terminated. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread */
|
||||
/* thread_entry_exit_notify Pointer to notify callback */
|
||||
/* function, TX_NULL to disable*/
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id))
|
||||
{
|
||||
|
||||
#ifdef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
TX_THREAD_NOT_USED(thread_ptr);
|
||||
TX_THREAD_ENTRY_EXIT_NOTIFY_NOT_USED(thread_entry_exit_notify);
|
||||
|
||||
/* Feature is not enabled, return error. */
|
||||
return(TX_FEATURE_NOT_ENABLED);
|
||||
#else
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_ENTRY_EXIT_NOTIFY, thread_ptr, thread_ptr -> tx_thread_state, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_EL_THREAD_ENTRY_EXIT_NOTIFY_INSERT
|
||||
|
||||
/* Setup thread entry/exit notification callback function. */
|
||||
thread_ptr -> tx_thread_entry_exit_notify = thread_entry_exit_notify;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success to caller. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
103
common_smp/src/tx_thread_identify.c
Normal file
103
common_smp/src/tx_thread_identify.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_identify PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function returns the control block pointer of the currently */
|
||||
/* executing thread. If the return value is NULL, no thread is */
|
||||
/* executing. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* TX_THREAD * Pointer to control block of */
|
||||
/* currently executing thread */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
TX_THREAD *_tx_thread_identify(VOID)
|
||||
{
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts to put the timer on the created list. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_IDENTIFY, 0, 0, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
#endif
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_IDENTIFY_INSERT
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return the current thread pointer. */
|
||||
return(thread_ptr);
|
||||
}
|
||||
|
||||
163
common_smp/src/tx_thread_info_get.c
Normal file
163
common_smp/src/tx_thread_info_get.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves information from the specified thread. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread control block */
|
||||
/* name Destination for the thread name */
|
||||
/* state Destination for thread state */
|
||||
/* run_count Destination for thread run count */
|
||||
/* priority Destination for thread priority */
|
||||
/* preemption_threshold Destination for thread preemption-*/
|
||||
/* threshold */
|
||||
/* time_slice Destination for thread time-slice */
|
||||
/* next_thread Destination for next created */
|
||||
/* thread */
|
||||
/* next_suspended_thread Destination for next suspended */
|
||||
/* thread */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_info_get(TX_THREAD *thread_ptr, CHAR **name, UINT *state, ULONG *run_count,
|
||||
UINT *priority, UINT *preemption_threshold, ULONG *time_slice,
|
||||
TX_THREAD **next_thread, TX_THREAD **next_suspended_thread)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_INFO_GET, thread_ptr, thread_ptr -> tx_thread_state, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve the name of the thread. */
|
||||
if (name != TX_NULL)
|
||||
{
|
||||
|
||||
*name = thread_ptr -> tx_thread_name;
|
||||
}
|
||||
|
||||
/* Pickup the thread's current state. */
|
||||
if (state != TX_NULL)
|
||||
{
|
||||
|
||||
*state = thread_ptr -> tx_thread_state;
|
||||
}
|
||||
|
||||
/* Pickup the number of times the thread has been scheduled. */
|
||||
if (run_count != TX_NULL)
|
||||
{
|
||||
|
||||
*run_count = thread_ptr -> tx_thread_run_count;
|
||||
}
|
||||
|
||||
/* Pickup the thread's priority. */
|
||||
if (priority != TX_NULL)
|
||||
{
|
||||
|
||||
*priority = thread_ptr -> tx_thread_user_priority;
|
||||
}
|
||||
|
||||
/* Pickup the thread's preemption-threshold. */
|
||||
if (preemption_threshold != TX_NULL)
|
||||
{
|
||||
|
||||
*preemption_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
|
||||
}
|
||||
|
||||
/* Pickup the thread's current time-slice. */
|
||||
if (time_slice != TX_NULL)
|
||||
{
|
||||
|
||||
*time_slice = thread_ptr -> tx_thread_time_slice;
|
||||
}
|
||||
|
||||
/* Pickup the next created thread. */
|
||||
if (next_thread != TX_NULL)
|
||||
{
|
||||
|
||||
*next_thread = thread_ptr -> tx_thread_created_next;
|
||||
}
|
||||
|
||||
/* Pickup the next thread suspended. */
|
||||
if (next_suspended_thread != TX_NULL)
|
||||
{
|
||||
|
||||
*next_suspended_thread = thread_ptr -> tx_thread_suspended_next;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
}
|
||||
|
||||
483
common_smp/src/tx_thread_initialize.c
Normal file
483
common_smp/src/tx_thread_initialize.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
#ifndef TX_MISRA_ENABLE
|
||||
#define TX_THREAD_INIT
|
||||
#endif
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/* Define the pointer that contains the system stack pointer. This is
|
||||
utilized when control returns from a thread to the system to reset the
|
||||
current stack. This is setup in the low-level initialization function. */
|
||||
|
||||
VOID * _tx_thread_system_stack_ptr[TX_THREAD_SMP_MAX_CORES];
|
||||
|
||||
|
||||
/* Define the current thread pointer. This variable points to the currently
|
||||
executing thread. If this variable is NULL, no thread is executing. */
|
||||
|
||||
TX_THREAD * _tx_thread_current_ptr[TX_THREAD_SMP_MAX_CORES];
|
||||
|
||||
|
||||
/* Define the variable that holds the next thread to execute. It is important
|
||||
to remember that this is not necessarily equal to the current thread
|
||||
pointer. */
|
||||
|
||||
TX_THREAD * _tx_thread_execute_ptr[TX_THREAD_SMP_MAX_CORES];
|
||||
|
||||
|
||||
/* Define the ThreadX SMP scheduling and mapping data structures. */
|
||||
|
||||
TX_THREAD * _tx_thread_smp_schedule_list[TX_THREAD_SMP_MAX_CORES];
|
||||
ULONG _tx_thread_smp_reschedule_pending;
|
||||
TX_THREAD_SMP_PROTECT _tx_thread_smp_protection;
|
||||
volatile ULONG _tx_thread_smp_release_cores_flag;
|
||||
ULONG _tx_thread_smp_system_error;
|
||||
ULONG _tx_thread_smp_inter_core_interrupts[TX_THREAD_SMP_MAX_CORES];
|
||||
|
||||
ULONG _tx_thread_smp_protect_wait_list_size;
|
||||
ULONG _tx_thread_smp_protect_wait_list[TX_THREAD_SMP_PROTECT_WAIT_LIST_SIZE];
|
||||
ULONG _tx_thread_smp_protect_wait_counts[TX_THREAD_SMP_MAX_CORES];
|
||||
ULONG _tx_thread_smp_protect_wait_list_lock_protect_in_force;
|
||||
ULONG _tx_thread_smp_protect_wait_list_tail;
|
||||
ULONG _tx_thread_smp_protect_wait_list_head;
|
||||
|
||||
|
||||
/* Define logic for conditional dynamic maximum number of cores. */
|
||||
|
||||
#ifdef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
ULONG _tx_thread_smp_max_cores;
|
||||
ULONG _tx_thread_smp_detected_cores;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Define the head pointer of the created thread list. */
|
||||
|
||||
TX_THREAD * _tx_thread_created_ptr;
|
||||
|
||||
|
||||
/* Define the variable that holds the number of created threads. */
|
||||
|
||||
ULONG _tx_thread_created_count;
|
||||
|
||||
|
||||
/* Define the current state variable. When this value is 0, a thread
|
||||
is executing or the system is idle. Other values indicate that
|
||||
interrupt or initialization processing is active. This variable is
|
||||
initialized to TX_INITIALIZE_IN_PROGRESS to indicate initialization is
|
||||
active. */
|
||||
|
||||
volatile ULONG _tx_thread_system_state[TX_THREAD_SMP_MAX_CORES];
|
||||
|
||||
|
||||
/* Define the 32-bit priority bit-maps. There is one priority bit map for each
|
||||
32 priority levels supported. If only 32 priorities are supported there is
|
||||
only one bit map. Each bit within a priority bit map represents that one
|
||||
or more threads at the associated thread priority are ready. */
|
||||
|
||||
ULONG _tx_thread_priority_maps[TX_MAX_PRIORITIES/32];
|
||||
|
||||
|
||||
/* Define the priority map active bit map that specifies which of the previously
|
||||
defined priority maps have something set. This is only necessary if more than
|
||||
32 priorities are supported. */
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
ULONG _tx_thread_priority_map_active;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Define the 32-bit preempt priority bit maps. There is one preempt bit map
|
||||
for each 32 priority levels supported. If only 32 priorities are supported
|
||||
there is only one bit map. Each set set bit corresponds to a preempted priority
|
||||
level that had preemption-threshold active to protect against preemption of a
|
||||
range of relatively higher priority threads. */
|
||||
|
||||
ULONG _tx_thread_preempted_maps[TX_MAX_PRIORITIES/32];
|
||||
|
||||
|
||||
/* Define the preempt map active bit map that specifies which of the previously
|
||||
defined preempt maps have something set. This is only necessary if more than
|
||||
32 priorities are supported. */
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
ULONG _tx_thread_preempted_map_active;
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the array that contains the thread at each priority level that was scheduled with
|
||||
preemption-threshold enabled. This will be useful when returning from a nested
|
||||
preemption-threshold condition. */
|
||||
|
||||
TX_THREAD *_tx_thread_preemption_threshold_list[TX_MAX_PRIORITIES];
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the last thread scheduled with preemption-threshold. When preemption-threshold is
|
||||
disabled, a thread with preemption-threshold set disables all other threads from running.
|
||||
Effectively, its preemption-threshold is 0. */
|
||||
|
||||
TX_THREAD *_tx_thread_preemption__threshold_scheduled;
|
||||
|
||||
|
||||
/* Define the array of thread pointers. Each entry represents the threads that
|
||||
are ready at that priority group. For example, index 10 in this array
|
||||
represents the first thread ready at priority 10. If this entry is NULL,
|
||||
no threads are ready at that priority. */
|
||||
|
||||
TX_THREAD * _tx_thread_priority_list[TX_MAX_PRIORITIES];
|
||||
|
||||
|
||||
/* Define the global preempt disable variable. If this is non-zero, preemption is
|
||||
disabled. It is used internally by ThreadX to prevent preemption of a thread in
|
||||
the middle of a service that is resuming or suspending another thread. */
|
||||
|
||||
volatile UINT _tx_thread_preempt_disable;
|
||||
|
||||
|
||||
/* Define the global function pointer for mutex cleanup on thread completion or
|
||||
termination. This pointer is setup during mutex initialization. */
|
||||
|
||||
VOID (*_tx_thread_mutex_release)(TX_THREAD *thread_ptr);
|
||||
|
||||
|
||||
/* Define the global build options variable. This contains a bit map representing
|
||||
how the ThreadX library was built. The following are the bit field definitions:
|
||||
|
||||
Bit(s) Meaning
|
||||
|
||||
31 Reserved
|
||||
30 TX_NOT_INTERRUPTABLE defined
|
||||
29-24 Priority groups 1 -> 32 priorities
|
||||
2 -> 64 priorities
|
||||
3 -> 96 priorities
|
||||
|
||||
...
|
||||
|
||||
32 -> 1024 priorities
|
||||
23 TX_TIMER_PROCESS_IN_ISR defined
|
||||
22 TX_REACTIVATE_INLINE defined
|
||||
21 TX_DISABLE_STACK_FILLING defined
|
||||
20 TX_ENABLE_STACK_CHECKING defined
|
||||
19 TX_DISABLE_PREEMPTION_THRESHOLD defined
|
||||
18 TX_DISABLE_REDUNDANT_CLEARING defined
|
||||
17 TX_DISABLE_NOTIFY_CALLBACKS defined
|
||||
16 TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO defined
|
||||
15 TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO defined
|
||||
14 TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO defined
|
||||
13 TX_MUTEX_ENABLE_PERFORMANCE_INFO defined
|
||||
12 TX_QUEUE_ENABLE_PERFORMANCE_INFO defined
|
||||
11 TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO defined
|
||||
10 TX_THREAD_ENABLE_PERFORMANCE_INFO defined
|
||||
9 TX_TIMER_ENABLE_PERFORMANCE_INFO defined
|
||||
8 TX_ENABLE_EVENT_TRACE | TX_ENABLE_EVENT_LOGGING defined
|
||||
7 Reserved
|
||||
6 Reserved
|
||||
5 Reserved
|
||||
4 Reserved
|
||||
3 Reserved
|
||||
2 Reserved
|
||||
1 64-bit FPU Enabled
|
||||
0 Reserved */
|
||||
|
||||
ULONG _tx_build_options;
|
||||
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Define the global function pointer for stack error handling. If a stack error is
|
||||
detected and the application has registered a stack error handler, it will be
|
||||
called via this function pointer. */
|
||||
|
||||
VOID (*_tx_thread_application_stack_error_handler)(TX_THREAD *thread_ptr);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Define the total number of thread resumptions. Each time a thread enters the
|
||||
ready state this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_resume_count;
|
||||
|
||||
|
||||
/* Define the total number of thread suspensions. Each time a thread enters a
|
||||
suspended state this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_suspend_count;
|
||||
|
||||
|
||||
/* Define the total number of solicited thread preemptions. Each time a thread is
|
||||
preempted by directly calling a ThreadX service, this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_solicited_preemption_count;
|
||||
|
||||
|
||||
/* Define the total number of interrupt thread preemptions. Each time a thread is
|
||||
preempted as a result of an ISR calling a ThreadX service, this variable is
|
||||
incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_interrupt_preemption_count;
|
||||
|
||||
|
||||
/* Define the total number of priority inversions. Each time a thread is blocked by
|
||||
a mutex owned by a lower-priority thread, this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_priority_inversion_count;
|
||||
|
||||
|
||||
/* Define the total number of time-slices. Each time a time-slice operation is
|
||||
actually performed (another thread is setup for running) this variable is
|
||||
incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_time_slice_count;
|
||||
|
||||
|
||||
/* Define the total number of thread relinquish operations. Each time a thread
|
||||
relinquish operation is actually performed (another thread is setup for running)
|
||||
this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_relinquish_count;
|
||||
|
||||
|
||||
/* Define the total number of thread timeouts. Each time a thread has a
|
||||
timeout this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_timeout_count;
|
||||
|
||||
|
||||
/* Define the total number of thread wait aborts. Each time a thread's suspension
|
||||
is lifted by the tx_thread_wait_abort call this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_wait_abort_count;
|
||||
|
||||
|
||||
/* Define the total number of idle system thread returns. Each time a thread returns to
|
||||
an idle system (no other thread is ready to run) this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_idle_return_count;
|
||||
|
||||
|
||||
/* Define the total number of non-idle system thread returns. Each time a thread returns to
|
||||
a non-idle system (another thread is ready to run) this variable is incremented. */
|
||||
|
||||
ULONG _tx_thread_performance_non_idle_return_count;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Define special string. */
|
||||
|
||||
#ifndef TX_MISRA_ENABLE
|
||||
const CHAR _tx_thread_special_string[] =
|
||||
"G-ML-EL-ML-BL-DL-BL-GB-GL-M-D-DL-GZ-KH-EL-CM-NH-HA-GF-DD-JC-YZ-CT-AT-DW-USA-CA-SD-SDSU";
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_initialize PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the various control data structures for */
|
||||
/* the thread control component. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_high_level High level initialization */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_initialize(VOID)
|
||||
{
|
||||
|
||||
/* Note: the system stack pointer and the system state variables are
|
||||
initialized by the low and high-level initialization functions,
|
||||
respectively. */
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Set current thread pointer to NULL. */
|
||||
TX_THREAD_SET_CURRENT(0)
|
||||
|
||||
/* Clear the execute thread list. */
|
||||
TX_MEMSET(&_tx_thread_execute_ptr[0], 0, (sizeof(_tx_thread_execute_ptr)));
|
||||
|
||||
/* Initialize the priority information. */
|
||||
TX_MEMSET(&_tx_thread_priority_maps[0], 0, (sizeof(_tx_thread_priority_maps)));
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
TX_MEMSET(&_tx_thread_preempted_maps[0], 0, (sizeof(_tx_thread_preempted_maps)));
|
||||
TX_MEMSET(&_tx_thread_preemption_threshold_list[0], 0, (sizeof(_tx_thread_preemption_threshold_list)));
|
||||
#endif
|
||||
_tx_thread_preemption__threshold_scheduled = TX_NULL;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef TX_DISABLE_REDUNDANT_CLEARING
|
||||
|
||||
/* Initialize the array of priority head pointers. */
|
||||
TX_MEMSET(&_tx_thread_priority_list[0], 0, (sizeof(_tx_thread_priority_list)));
|
||||
|
||||
/* Initialize the head pointer of the created threads list and the
|
||||
number of threads created. */
|
||||
_tx_thread_created_ptr = TX_NULL;
|
||||
_tx_thread_created_count = TX_EMPTY;
|
||||
|
||||
/* Clear the global preempt disable variable. */
|
||||
_tx_thread_preempt_disable = ((UINT) 0);
|
||||
|
||||
/* Initialize the thread mutex release function pointer. */
|
||||
_tx_thread_mutex_release = TX_NULL;
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Clear application registered stack error handler. */
|
||||
_tx_thread_application_stack_error_handler = TX_NULL;
|
||||
#endif
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Clear performance counters. */
|
||||
_tx_thread_performance_resume_count = ((ULONG) 0);
|
||||
_tx_thread_performance_suspend_count = ((ULONG) 0);
|
||||
_tx_thread_performance_solicited_preemption_count = ((ULONG) 0);
|
||||
_tx_thread_performance_interrupt_preemption_count = ((ULONG) 0);
|
||||
_tx_thread_performance_priority_inversion_count = ((ULONG) 0);
|
||||
_tx_thread_performance_time_slice_count = ((ULONG) 0);
|
||||
_tx_thread_performance_relinquish_count = ((ULONG) 0);
|
||||
_tx_thread_performance_timeout_count = ((ULONG) 0);
|
||||
_tx_thread_performance_wait_abort_count = ((ULONG) 0);
|
||||
_tx_thread_performance_idle_return_count = ((ULONG) 0);
|
||||
_tx_thread_performance_non_idle_return_count = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Setup the build options flag. This is used to identify how the ThreadX library was constructed. */
|
||||
_tx_build_options = _tx_build_options
|
||||
| (((ULONG) (TX_MAX_PRIORITIES/32)) << 24)
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
| (((ULONG) 1) << 31)
|
||||
#endif
|
||||
#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
|
||||
| (((ULONG) 1) << 30)
|
||||
#endif
|
||||
#ifdef TX_TIMER_PROCESS_IN_ISR
|
||||
| (((ULONG) 1) << 23)
|
||||
#endif
|
||||
#ifdef TX_REACTIVATE_INLINE
|
||||
| (((ULONG) 1) << 22)
|
||||
#endif
|
||||
#ifdef TX_DISABLE_STACK_FILLING
|
||||
| (((ULONG) 1) << 21)
|
||||
#endif
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
| (((ULONG) 1) << 20)
|
||||
#endif
|
||||
#ifdef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
| (((ULONG) 1) << 19)
|
||||
#endif
|
||||
#ifdef TX_DISABLE_REDUNDANT_CLEARING
|
||||
| (((ULONG) 1) << 18)
|
||||
#endif
|
||||
#ifdef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
| (((ULONG) 1) << 17)
|
||||
#endif
|
||||
#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 16)
|
||||
#endif
|
||||
#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 15)
|
||||
#endif
|
||||
#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 14)
|
||||
#endif
|
||||
#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 13)
|
||||
#endif
|
||||
#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 12)
|
||||
#endif
|
||||
#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 11)
|
||||
#endif
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 10)
|
||||
#endif
|
||||
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
|
||||
| (((ULONG) 1) << 9)
|
||||
#endif
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
| (((ULONG) 1) << 8)
|
||||
#endif
|
||||
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
||||
| (((ULONG) 1) << 7)
|
||||
#endif
|
||||
#if TX_PORT_SPECIFIC_BUILD_OPTIONS != 0
|
||||
| TX_PORT_SPECIFIC_BUILD_OPTIONS
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
297
common_smp/src/tx_thread_performance_info_get.c
Normal file
297
common_smp/src/tx_thread_performance_info_get.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_performance_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves performance information from the specified */
|
||||
/* thread. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread control block */
|
||||
/* resumptions Destination for number of times */
|
||||
/* thread was resumed */
|
||||
/* suspensions Destination for number of times */
|
||||
/* thread was suspended */
|
||||
/* solicited_preemptions Destination for number of times */
|
||||
/* thread called another service */
|
||||
/* that resulted in preemption */
|
||||
/* interrupt_preemptions Destination for number of times */
|
||||
/* thread was preempted by another */
|
||||
/* thread made ready in Interrupt */
|
||||
/* Service Routine (ISR) */
|
||||
/* priority_inversions Destination for number of times */
|
||||
/* a priority inversion was */
|
||||
/* detected for this thread */
|
||||
/* time_slices Destination for number of times */
|
||||
/* thread was time-sliced */
|
||||
/* relinquishes Destination for number of thread */
|
||||
/* relinquishes */
|
||||
/* timeouts Destination for number of timeouts*/
|
||||
/* for thread */
|
||||
/* wait_aborts Destination for number of wait */
|
||||
/* aborts for thread */
|
||||
/* last_preempted_by Destination for pointer of the */
|
||||
/* thread that last preempted this */
|
||||
/* thread */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_performance_info_get(TX_THREAD *thread_ptr, ULONG *resumptions, ULONG *suspensions,
|
||||
ULONG *solicited_preemptions, ULONG *interrupt_preemptions, ULONG *priority_inversions,
|
||||
ULONG *time_slices, ULONG *relinquishes, ULONG *timeouts, ULONG *wait_aborts, TX_THREAD **last_preempted_by)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
if (thread_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Thread pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
|
||||
/* Determine if the thread ID is invalid. */
|
||||
else if (thread_ptr -> tx_thread_id != TX_THREAD_ID)
|
||||
{
|
||||
|
||||
/* Thread pointer is illegal, return error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PERFORMANCE_INFO_GET, thread_ptr, thread_ptr -> tx_thread_state, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve number of resumptions for this thread. */
|
||||
if (resumptions != TX_NULL)
|
||||
{
|
||||
|
||||
*resumptions = thread_ptr -> tx_thread_performance_resume_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of suspensions for this thread. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = thread_ptr -> tx_thread_performance_suspend_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of solicited preemptions for this thread. */
|
||||
if (solicited_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
*solicited_preemptions = thread_ptr -> tx_thread_performance_solicited_preemption_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of interrupt preemptions for this thread. */
|
||||
if (interrupt_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
*interrupt_preemptions = thread_ptr -> tx_thread_performance_interrupt_preemption_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of priority inversions for this thread. */
|
||||
if (priority_inversions != TX_NULL)
|
||||
{
|
||||
|
||||
*priority_inversions = thread_ptr -> tx_thread_performance_priority_inversion_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of time-slices for this thread. */
|
||||
if (time_slices != TX_NULL)
|
||||
{
|
||||
|
||||
*time_slices = thread_ptr -> tx_thread_performance_time_slice_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of relinquishes for this thread. */
|
||||
if (relinquishes != TX_NULL)
|
||||
{
|
||||
|
||||
*relinquishes = thread_ptr -> tx_thread_performance_relinquish_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of timeouts for this thread. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = thread_ptr -> tx_thread_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Retrieve number of wait aborts for this thread. */
|
||||
if (wait_aborts != TX_NULL)
|
||||
{
|
||||
|
||||
*wait_aborts = thread_ptr -> tx_thread_performance_wait_abort_count;
|
||||
}
|
||||
|
||||
/* Retrieve the pointer of the last thread that preempted this thread. */
|
||||
if (last_preempted_by != TX_NULL)
|
||||
{
|
||||
|
||||
*last_preempted_by = thread_ptr -> tx_thread_performance_last_preempting_thread;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
#else
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (resumptions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (solicited_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (interrupt_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (priority_inversions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (time_slices != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (relinquishes != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (wait_aborts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (last_preempted_by != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
287
common_smp/src/tx_thread_performance_system_info_get.c
Normal file
287
common_smp/src/tx_thread_performance_system_info_get.c
Normal file
@@ -0,0 +1,287 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_performance_system_info_get PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function retrieves thread system performance information. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* resumptions Destination for total number of */
|
||||
/* thread resumptions */
|
||||
/* suspensions Destination for total number of */
|
||||
/* thread suspensions */
|
||||
/* solicited_preemptions Destination for total number of */
|
||||
/* thread preemption from thread */
|
||||
/* API calls */
|
||||
/* interrupt_preemptions Destination for total number of */
|
||||
/* thread preemptions as a result */
|
||||
/* of threads made ready inside of */
|
||||
/* Interrupt Service Routines */
|
||||
/* priority_inversions Destination for total number of */
|
||||
/* priority inversions */
|
||||
/* time_slices Destination for total number of */
|
||||
/* time-slices */
|
||||
/* relinquishes Destination for total number of */
|
||||
/* relinquishes */
|
||||
/* timeouts Destination for total number of */
|
||||
/* timeouts */
|
||||
/* wait_aborts Destination for total number of */
|
||||
/* wait aborts */
|
||||
/* non_idle_returns Destination for total number of */
|
||||
/* times threads return when */
|
||||
/* another thread is ready */
|
||||
/* idle_returns Destination for total number of */
|
||||
/* times threads return when no */
|
||||
/* other thread is ready */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_performance_system_info_get(ULONG *resumptions, ULONG *suspensions,
|
||||
ULONG *solicited_preemptions, ULONG *interrupt_preemptions, ULONG *priority_inversions,
|
||||
ULONG *time_slices, ULONG *relinquishes, ULONG *timeouts, ULONG *wait_aborts,
|
||||
ULONG *non_idle_returns, ULONG *idle_returns)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT
|
||||
|
||||
/* Retrieve all the pertinent information and return it in the supplied
|
||||
destinations. */
|
||||
|
||||
/* Retrieve total number of thread resumptions. */
|
||||
if (resumptions != TX_NULL)
|
||||
{
|
||||
|
||||
*resumptions = _tx_thread_performance_resume_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread suspensions. */
|
||||
if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
*suspensions = _tx_thread_performance_suspend_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of solicited thread preemptions. */
|
||||
if (solicited_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
*solicited_preemptions = _tx_thread_performance_solicited_preemption_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of interrupt thread preemptions. */
|
||||
if (interrupt_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
*interrupt_preemptions = _tx_thread_performance_interrupt_preemption_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread priority inversions. */
|
||||
if (priority_inversions != TX_NULL)
|
||||
{
|
||||
|
||||
*priority_inversions = _tx_thread_performance_priority_inversion_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread time-slices. */
|
||||
if (time_slices != TX_NULL)
|
||||
{
|
||||
|
||||
*time_slices = _tx_thread_performance_time_slice_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread relinquishes. */
|
||||
if (relinquishes != TX_NULL)
|
||||
{
|
||||
|
||||
*relinquishes = _tx_thread_performance_relinquish_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread timeouts. */
|
||||
if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
*timeouts = _tx_thread_performance_timeout_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread wait aborts. */
|
||||
if (wait_aborts != TX_NULL)
|
||||
{
|
||||
|
||||
*wait_aborts = _tx_thread_performance_wait_abort_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread non-idle system returns. */
|
||||
if (non_idle_returns != TX_NULL)
|
||||
{
|
||||
|
||||
*non_idle_returns = _tx_thread_performance_non_idle_return_count;
|
||||
}
|
||||
|
||||
/* Retrieve total number of thread idle system returns. */
|
||||
if (idle_returns != TX_NULL)
|
||||
{
|
||||
|
||||
*idle_returns = _tx_thread_performance_idle_return_count;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(TX_SUCCESS);
|
||||
|
||||
#else
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input arguments just for the sake of lint, MISRA, etc. */
|
||||
if (resumptions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (suspensions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (solicited_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (interrupt_preemptions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (priority_inversions != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (time_slices != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (relinquishes != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (timeouts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (wait_aborts != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (non_idle_returns != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else if (idle_returns != TX_NULL)
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Not enabled, return error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#endif
|
||||
}
|
||||
|
||||
298
common_smp/src/tx_thread_preemption_change.c
Normal file
298
common_smp/src/tx_thread_preemption_change.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_preemption_change PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes preemption-threshold change requests. The */
|
||||
/* previous preemption is returned to the caller. If the new request */
|
||||
/* allows a higher priority thread to execute, preemption takes place */
|
||||
/* inside of this function. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread */
|
||||
/* new_threshold New preemption-threshold */
|
||||
/* old_threshold Old preemption-threshold */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT core_index;
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
ULONG priority_bit;
|
||||
UINT base_priority;
|
||||
UINT priority_bit_set;
|
||||
ULONG priority_map;
|
||||
UINT next_preempted;
|
||||
TX_THREAD *preempted_thread;
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
UINT map_index;
|
||||
#endif
|
||||
#endif
|
||||
UINT status;
|
||||
|
||||
|
||||
#ifdef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Only allow 0 (disable all preemption) and returning preemption-threshold to the
|
||||
current thread priority if preemption-threshold is disabled. All other threshold
|
||||
values are converted to 0. */
|
||||
if (new_threshold < thread_ptr -> tx_thread_user_priority)
|
||||
{
|
||||
|
||||
/* Is the new threshold zero? */
|
||||
if (new_threshold != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Convert the new threshold to disable all preemption, since preemption-threshold is
|
||||
not supported. */
|
||||
new_threshold = ((UINT) 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Default status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Lockout interrupts while the thread is being resumed. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PREEMPTION_CHANGE, thread_ptr, new_threshold, thread_ptr -> tx_thread_preempt_threshold, thread_ptr -> tx_thread_state, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_PREEMPTION_CHANGE_INSERT
|
||||
|
||||
/* Determine if the new threshold is greater than the current user priority. */
|
||||
if (new_threshold > thread_ptr -> tx_thread_user_priority)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return error. */
|
||||
status = TX_THRESH_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Return the user's preemption-threshold. */
|
||||
*old_threshold = thread_ptr -> tx_thread_user_preempt_threshold;
|
||||
|
||||
/* Setup the new threshold. */
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_threshold;
|
||||
|
||||
/* Determine if the new threshold represents a higher priority than the priority inheritance threshold. */
|
||||
if (new_threshold < thread_ptr -> tx_thread_inherit_priority)
|
||||
{
|
||||
|
||||
/* Update the actual preemption-threshold with the new threshold. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_threshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Update the actual preemption-threshold with the priority inheritance. */
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
|
||||
}
|
||||
|
||||
/* Determine if the thread is ready and scheduled. */
|
||||
if (thread_ptr -> tx_thread_state == TX_READY)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Determine if the new threshold is the same as the priority. */
|
||||
if (thread_ptr -> tx_thread_user_priority == new_threshold)
|
||||
{
|
||||
|
||||
/* Yes, preemption-threshold is being disabled. */
|
||||
|
||||
/* Determine if this thread was scheduled with preemption-threshold in force. */
|
||||
if (_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_user_priority] == thread_ptr)
|
||||
{
|
||||
|
||||
/* Clear the entry in the preempted list. */
|
||||
_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_user_priority] = TX_NULL;
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Calculate the index into the bit map array. */
|
||||
map_index = (thread_ptr -> tx_thread_user_priority)/((UINT) 32);
|
||||
#endif
|
||||
|
||||
/* Yes, this thread is at the front of the list. Make sure
|
||||
the preempted bit is cleared for this thread. */
|
||||
TX_MOD32_BIT_SET(thread_ptr -> tx_thread_user_priority, priority_bit)
|
||||
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Determine if there are any other bits set in this preempt map. */
|
||||
if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No, clear the active bit to signify this preempt map has nothing set. */
|
||||
TX_DIV32_BIT_SET(thread_ptr -> tx_thread_user_priority, priority_bit)
|
||||
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if this thread has global preemption disabled. */
|
||||
if (thread_ptr == _tx_thread_preemption__threshold_scheduled)
|
||||
{
|
||||
|
||||
/* Clear the global preemption disable flag. */
|
||||
_tx_thread_preemption__threshold_scheduled = TX_NULL;
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Calculate the first thread with preemption-threshold active. */
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
if (_tx_thread_preempted_map_active != ((ULONG) 0))
|
||||
#else
|
||||
if (_tx_thread_preempted_maps[0] != ((ULONG) 0))
|
||||
#endif
|
||||
{
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Calculate the index to find the next highest priority thread ready for execution. */
|
||||
priority_map = _tx_thread_preempted_map_active;
|
||||
|
||||
/* Calculate the lowest bit set in the priority map. */
|
||||
TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
|
||||
|
||||
/* Calculate the base priority as well. */
|
||||
base_priority = map_index * ((UINT) 32);
|
||||
#else
|
||||
|
||||
/* Setup the base priority to zero. */
|
||||
base_priority = ((UINT) 0);
|
||||
#endif
|
||||
|
||||
/* Setup temporary preempted map. */
|
||||
priority_map = _tx_thread_preempted_maps[MAP_INDEX];
|
||||
|
||||
/* Calculate the lowest bit set in the priority map. */
|
||||
TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit_set)
|
||||
|
||||
/* Move priority bit set into priority bit. */
|
||||
priority_bit = (ULONG) priority_bit_set;
|
||||
|
||||
/* Setup the highest priority preempted thread. */
|
||||
next_preempted = base_priority + priority_bit;
|
||||
|
||||
/* Pickup the previously preempted thread. */
|
||||
preempted_thread = _tx_thread_preemption_threshold_list[next_preempted];
|
||||
|
||||
/* Pickup the preempted thread. */
|
||||
_tx_thread_preemption__threshold_scheduled = preempted_thread;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* See if preemption needs to take place. */
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(12, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(13, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
514
common_smp/src/tx_thread_priority_change.c
Normal file
514
common_smp/src/tx_thread_priority_change.c
Normal file
@@ -0,0 +1,514 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_priority_change PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function changes the priority of the specified thread. It */
|
||||
/* also returns the old priority and handles preemption if the calling */
|
||||
/* thread is currently executing and the priority change results in a */
|
||||
/* higher priority thread ready for execution. */
|
||||
/* */
|
||||
/* Note: the preemption-threshold is automatically changed to the new */
|
||||
/* priority. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to suspend */
|
||||
/* new_priority New thread priority */
|
||||
/* old_priority Old thread priority */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
|
||||
/* _tx_thread_smp_simple_priority_change Change priority */
|
||||
/* _tx_thread_system_resume Resume thread */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume */
|
||||
/* _tx_thread_system_suspend Suspend thread */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend */
|
||||
/* _tx_thread_system_preempt_check Check for preemption */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, UINT *old_priority)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *execute_ptr;
|
||||
UINT core_index;
|
||||
UINT original_priority;
|
||||
UINT lowest_priority;
|
||||
TX_THREAD *original_pt_thread;
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
TX_THREAD *new_pt_thread;
|
||||
UINT priority;
|
||||
ULONG priority_bit;
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
UINT map_index;
|
||||
#endif
|
||||
#endif
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default status to not done. */
|
||||
status = TX_NOT_DONE;
|
||||
|
||||
/* Lockout interrupts while the thread is being suspended. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PRIORITY_CHANGE, thread_ptr, new_priority, thread_ptr -> tx_thread_priority, thread_ptr -> tx_thread_state, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_PRIORITY_CHANGE_INSERT
|
||||
|
||||
/* Save the previous priority. */
|
||||
*old_priority = thread_ptr -> tx_thread_user_priority;
|
||||
|
||||
/* Determine if the new priority is the same as the last requested priority. */
|
||||
if ((thread_ptr -> tx_thread_user_priority == new_priority) &&
|
||||
(thread_ptr -> tx_thread_user_preempt_threshold == new_priority))
|
||||
{
|
||||
|
||||
/* Nothing to do at this point, simply return. */
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Done, return success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Determine if the inherit priority is in effect and there is no preemption-threshold in force. */
|
||||
else if ((thread_ptr -> tx_thread_inherit_priority < new_priority) &&
|
||||
(thread_ptr -> tx_thread_user_preempt_threshold == thread_ptr -> tx_thread_user_priority))
|
||||
{
|
||||
|
||||
/* In this case, simply setup the user priority and preemption-threshold and return. */
|
||||
|
||||
/* Setup the new priority for this thread. */
|
||||
thread_ptr -> tx_thread_user_priority = new_priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Done, return success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Default the execute pointer to NULL. */
|
||||
execute_ptr = TX_NULL;
|
||||
|
||||
/* Determine if this thread is currently ready. */
|
||||
if (thread_ptr -> tx_thread_state != TX_READY)
|
||||
{
|
||||
|
||||
/* Setup the user priority and threshold in the thread's control
|
||||
block. */
|
||||
thread_ptr -> tx_thread_user_priority = new_priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
|
||||
|
||||
/* Determine if the actual thread priority should be setup, which is the
|
||||
case if the new priority is higher than the priority inheritance. */
|
||||
if (new_priority < thread_ptr -> tx_thread_inherit_priority)
|
||||
{
|
||||
|
||||
/* Change thread priority to the new user's priority. */
|
||||
thread_ptr -> tx_thread_priority = new_priority;
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change thread priority to the priority inheritance. */
|
||||
thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_inherit_priority;
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Done, return success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Pickup the core index. */
|
||||
core_index = thread_ptr -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Save the original priority. */
|
||||
original_priority = thread_ptr -> tx_thread_priority;
|
||||
|
||||
/* Determine if this thread is the currently scheduled thread. */
|
||||
if (thread_ptr == _tx_thread_execute_ptr[core_index])
|
||||
{
|
||||
|
||||
/* Yes, this thread is scheduled. */
|
||||
|
||||
/* Remember this thread as the currently executing thread. */
|
||||
execute_ptr = thread_ptr;
|
||||
|
||||
/* Determine if the thread is being set to a higher-priority and it does't have
|
||||
preemption-threshold set. */
|
||||
if ((new_priority < thread_ptr -> tx_thread_priority) &&
|
||||
(thread_ptr -> tx_thread_user_priority == thread_ptr -> tx_thread_user_preempt_threshold))
|
||||
{
|
||||
|
||||
/* Simple case, remove the thread from the current priority list and place in
|
||||
the higher priority list. */
|
||||
_tx_thread_smp_simple_priority_change(thread_ptr, new_priority);
|
||||
|
||||
/* Setup the new priority for this thread. */
|
||||
thread_ptr -> tx_thread_user_priority = new_priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return a successful completion. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Thread is not currently executing, so it can just be moved to the lower priority in the list. */
|
||||
|
||||
/* Determine if the thread is being set to a lower-priority and it does't have
|
||||
preemption-threshold set. */
|
||||
if ((new_priority > thread_ptr -> tx_thread_priority) &&
|
||||
(thread_ptr -> tx_thread_user_priority == thread_ptr -> tx_thread_user_preempt_threshold))
|
||||
{
|
||||
|
||||
/* Simple case, remove the thread from the current priority list and place in
|
||||
the lower priority list. */
|
||||
_tx_thread_smp_simple_priority_change(thread_ptr, new_priority);
|
||||
|
||||
/* Setup the new priority for this thread. */
|
||||
thread_ptr -> tx_thread_user_priority = new_priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return a successful completion. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if we are done. */
|
||||
if (status == TX_NOT_DONE)
|
||||
{
|
||||
|
||||
/* Yes, more to do. */
|
||||
|
||||
/* Default the status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Save the original preemption-threshold thread. */
|
||||
original_pt_thread = _tx_thread_preemption__threshold_scheduled;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
|
||||
|
||||
/* At this point, the preempt disable flag is still set, so we still have
|
||||
protection against all preemption. */
|
||||
|
||||
/* Setup the new priority for this thread. */
|
||||
thread_ptr -> tx_thread_user_priority = new_priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
|
||||
|
||||
/* Determine if the actual thread priority should be setup, which is the
|
||||
case if the new priority is higher than the priority inheritance. */
|
||||
if (new_priority < thread_ptr -> tx_thread_inherit_priority)
|
||||
{
|
||||
|
||||
/* Change thread priority to the new user's priority. */
|
||||
thread_ptr -> tx_thread_priority = new_priority;
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change thread priority to the priority inheritance. */
|
||||
thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_inherit_priority;
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
|
||||
}
|
||||
|
||||
/* Resume the thread with the new priority. */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Decrement the preempt disable flag. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#else
|
||||
|
||||
/* Increment the preempt disable flag. */
|
||||
_tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 3);
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* The thread is ready and must first be removed from the list. Call the
|
||||
system suspend function to accomplish this. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
|
||||
/* Lockout interrupts again. */
|
||||
TX_DISABLE
|
||||
|
||||
/* At this point, the preempt disable flag is still set, so we still have
|
||||
protection against all preemption. */
|
||||
|
||||
/* Setup the new priority for this thread. */
|
||||
thread_ptr -> tx_thread_user_priority = new_priority;
|
||||
thread_ptr -> tx_thread_user_preempt_threshold = new_priority;
|
||||
|
||||
/* Determine if the actual thread priority should be setup, which is the
|
||||
case if the new priority is higher than the priority inheritance. */
|
||||
if (new_priority < thread_ptr -> tx_thread_inherit_priority)
|
||||
{
|
||||
|
||||
/* Change thread priority to the new user's priority. */
|
||||
thread_ptr -> tx_thread_priority = new_priority;
|
||||
thread_ptr -> tx_thread_preempt_threshold = new_priority;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Change thread priority to the priority inheritance. */
|
||||
thread_ptr -> tx_thread_priority = thread_ptr -> tx_thread_inherit_priority;
|
||||
thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_inherit_priority;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Resume the thread with the new priority. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_THREAD_PRIORITY_CHANGE_EXTENSION
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Decrement the preemption-threshold flag. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#endif
|
||||
|
||||
/* Determine if the thread was previously executing. */
|
||||
if (thread_ptr == execute_ptr)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
/* Determine if preemption-threshold is in force at the new priority level. */
|
||||
if (_tx_thread_preemption_threshold_list[thread_ptr -> tx_thread_priority] == TX_NULL)
|
||||
{
|
||||
|
||||
/* Ensure that this thread is placed at the front of the priority list. */
|
||||
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Ensure that this thread is placed at the front of the priority list. */
|
||||
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pickup the core index. */
|
||||
core_index = thread_ptr -> tx_thread_smp_core_mapped;
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
/* Pickup the next thread to execute. */
|
||||
if (core_index < ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
#else
|
||||
|
||||
/* Pickup the next thread to execute. */
|
||||
if (core_index < _tx_thread_smp_max_cores)
|
||||
#endif
|
||||
{
|
||||
|
||||
/* Determine if this thread is not the next thread to execute. */
|
||||
if (thread_ptr != _tx_thread_execute_ptr[core_index])
|
||||
{
|
||||
|
||||
/* Now determine if this thread was previously executing thread. */
|
||||
if (thread_ptr == execute_ptr)
|
||||
{
|
||||
|
||||
/* Determine if we moved to a lower priority. If so, move the thread to the front of the priority list. */
|
||||
if (original_priority < new_priority)
|
||||
{
|
||||
|
||||
/* Make sure the thread is still ready. */
|
||||
if (thread_ptr -> tx_thread_state == TX_READY)
|
||||
{
|
||||
|
||||
/* Determine the lowest priority scheduled thread. */
|
||||
lowest_priority = _tx_thread_smp_lowest_priority_get();
|
||||
|
||||
/* Determine if this thread has a higher or same priority as the lowest priority
|
||||
in the list. */
|
||||
if (thread_ptr -> tx_thread_priority <= lowest_priority)
|
||||
{
|
||||
|
||||
/* Yes, we need to rebalance to make it possible for this thread to execute. */
|
||||
|
||||
/* Determine if the thread with preemption-threshold thread has changed... and is
|
||||
not the scheduled thread. */
|
||||
if ((original_pt_thread != _tx_thread_preemption__threshold_scheduled) &&
|
||||
(original_pt_thread != thread_ptr))
|
||||
{
|
||||
|
||||
/* Yes, preemption-threshold has changed. Determine if it can or should
|
||||
be reversed. */
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Pickup the preemption-threshold thread. */
|
||||
new_pt_thread = _tx_thread_preemption__threshold_scheduled;
|
||||
#endif
|
||||
|
||||
/* Restore the original preemption-threshold thread. */
|
||||
_tx_thread_preemption__threshold_scheduled = original_pt_thread;
|
||||
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Determine if there is a new preemption-threshold thread to reverse. */
|
||||
if (new_pt_thread != TX_NULL)
|
||||
{
|
||||
|
||||
/* Clear the information associated with the new preemption-threshold thread. */
|
||||
|
||||
/* Pickup the priority. */
|
||||
priority = new_pt_thread -> tx_thread_priority;
|
||||
|
||||
/* Clear the preempted list entry. */
|
||||
_tx_thread_preemption_threshold_list[priority] = TX_NULL;
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
/* Calculate the bit map array index. */
|
||||
map_index = new_priority/((UINT) 32);
|
||||
#endif
|
||||
|
||||
/* Ensure that this thread's priority is clear in the preempt map. */
|
||||
TX_MOD32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Determine if there are any other bits set in this preempt map. */
|
||||
if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No, clear the active bit to signify this preempted map has nothing set. */
|
||||
TX_DIV32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Check for preemption. */
|
||||
_tx_thread_system_preempt_check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
504
common_smp/src/tx_thread_relinquish.c
Normal file
504
common_smp/src/tx_thread_relinquish.c
Normal file
@@ -0,0 +1,504 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_trace.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_relinquish PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function determines if there is another higher or equal */
|
||||
/* priority, non-executing thread that can execute on this processor. */
|
||||
/* such a thread is found, the calling thread relinquishes control. */
|
||||
/* Otherwise, this function simply returns. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
|
||||
/* _tx_thread_system_return Return to the system */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_relinquish(VOID)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT priority;
|
||||
TX_THREAD *thread_ptr;
|
||||
TX_THREAD *head_ptr;
|
||||
TX_THREAD *tail_ptr;
|
||||
TX_THREAD *next_thread;
|
||||
TX_THREAD *previous_thread;
|
||||
UINT core_index;
|
||||
UINT rebalance;
|
||||
UINT mapped_core;
|
||||
ULONG excluded;
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
UINT base_priority;
|
||||
UINT priority_bit_set;
|
||||
UINT next_preempted;
|
||||
ULONG priority_bit;
|
||||
ULONG priority_map;
|
||||
TX_THREAD *preempted_thread;
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
UINT map_index;
|
||||
#endif
|
||||
#endif
|
||||
UINT finished;
|
||||
|
||||
|
||||
/* Default finished to false. */
|
||||
finished = TX_FALSE;
|
||||
|
||||
/* Initialize the rebalance flag to false. */
|
||||
rebalance = TX_FALSE;
|
||||
|
||||
/* Lockout interrupts while thread attempts to relinquish control. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Pickup the current thread pointer. */
|
||||
thread_ptr = _tx_thread_current_ptr[core_index];
|
||||
|
||||
#ifndef TX_NO_TIMER
|
||||
|
||||
/* Reset time slice for current thread. */
|
||||
_tx_timer_time_slice[core_index] = thread_ptr -> tx_thread_new_time_slice;
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Check this thread's stack. */
|
||||
TX_THREAD_STACK_CHECK(thread_ptr)
|
||||
#endif
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RELINQUISH, &thread_ptr, TX_POINTER_TO_ULONG_CONVERT(thread_ptr -> tx_thread_ready_next), 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_RELINQUISH_INSERT
|
||||
|
||||
/* Pickup the thread's priority. */
|
||||
priority = thread_ptr -> tx_thread_priority;
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(0, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Pickup the next thread. */
|
||||
next_thread = thread_ptr -> tx_thread_ready_next;
|
||||
|
||||
/* Pickup the head of the list. */
|
||||
head_ptr = _tx_thread_priority_list[priority];
|
||||
|
||||
/* Pickup the list tail. */
|
||||
tail_ptr = head_ptr -> tx_thread_ready_previous;
|
||||
|
||||
/* Determine if this thread is not the tail pointer. */
|
||||
if (thread_ptr != tail_ptr)
|
||||
{
|
||||
|
||||
/* Not the tail pointer, this thread must be moved to the end of the ready list. */
|
||||
|
||||
/* Determine if this thread is at the head of the list. */
|
||||
if (head_ptr == thread_ptr)
|
||||
{
|
||||
|
||||
/* Simply move the head pointer to put this thread at the end of the ready list at this priority. */
|
||||
_tx_thread_priority_list[priority] = next_thread;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Now we need to remove this thread from its current position and place it at the end of the list. */
|
||||
|
||||
/* Pickup the previous thread pointer. */
|
||||
previous_thread = thread_ptr -> tx_thread_ready_previous;
|
||||
|
||||
/* Remove the thread from the ready list. */
|
||||
next_thread -> tx_thread_ready_previous = previous_thread;
|
||||
previous_thread -> tx_thread_ready_next = next_thread;
|
||||
|
||||
/* Insert the thread at the end of the list. */
|
||||
tail_ptr -> tx_thread_ready_next = thread_ptr;
|
||||
head_ptr -> tx_thread_ready_previous = thread_ptr;
|
||||
thread_ptr -> tx_thread_ready_previous = tail_ptr;
|
||||
thread_ptr -> tx_thread_ready_next = head_ptr;
|
||||
}
|
||||
|
||||
/* Pickup the mapped core of the relinquishing thread - this can be different from the current core. */
|
||||
mapped_core = thread_ptr -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Determine if the relinquishing thread is no longer present in the execute list. */
|
||||
if (thread_ptr != _tx_thread_execute_ptr[mapped_core])
|
||||
{
|
||||
|
||||
/* Yes, the thread is no longer mapped. Set the rebalance flag to determine if there is a new mapping due to moving
|
||||
this thread to the end of the priority list. */
|
||||
|
||||
/* Set the rebalance flag to true. */
|
||||
rebalance = TX_FALSE;
|
||||
}
|
||||
|
||||
/* Determine if preemption-threshold is in force. */
|
||||
else if (thread_ptr -> tx_thread_preempt_threshold == priority)
|
||||
{
|
||||
|
||||
/* No preemption-threshold is in force. */
|
||||
|
||||
/* Determine if there is a thread at the same priority that isn't currently executing. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Isolate the exclusion for this core. */
|
||||
excluded = (next_thread -> tx_thread_smp_cores_excluded >> mapped_core) & ((ULONG) 1);
|
||||
|
||||
/* Determine if the next thread has preemption-threshold set or is excluded from running on the
|
||||
mapped core. */
|
||||
if ((next_thread -> tx_thread_preempt_threshold < next_thread -> tx_thread_priority) ||
|
||||
(excluded == ((ULONG) 1)))
|
||||
{
|
||||
|
||||
/* Set the rebalance flag. */
|
||||
rebalance = TX_TRUE;
|
||||
|
||||
/* Get out of the loop. We need to rebalance the list when we detect preemption-threshold. */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is the next thread already in the execute list? */
|
||||
if (next_thread != _tx_thread_execute_ptr[next_thread -> tx_thread_smp_core_mapped])
|
||||
{
|
||||
|
||||
/* No, we can place this thread in the position the relinquishing thread
|
||||
was in. */
|
||||
|
||||
/* Remember this index in the thread control block. */
|
||||
next_thread -> tx_thread_smp_core_mapped = mapped_core;
|
||||
|
||||
/* Setup the entry in the execution list. */
|
||||
_tx_thread_execute_ptr[mapped_core] = next_thread;
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(1, 0, next_thread);
|
||||
#endif
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the number of thread relinquishes. */
|
||||
thread_ptr -> tx_thread_performance_relinquish_count++;
|
||||
|
||||
/* Increment the total number of thread relinquish operations. */
|
||||
_tx_thread_performance_relinquish_count++;
|
||||
|
||||
/* No, there is another thread ready to run and will be scheduled upon return. */
|
||||
_tx_thread_performance_non_idle_return_count++;
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Check this thread's stack. */
|
||||
TX_THREAD_STACK_CHECK(next_thread)
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag in order to keep the protection. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Transfer control to the system so the scheduler can execute
|
||||
the next thread. */
|
||||
_tx_thread_system_return();
|
||||
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Set the finished flag. */
|
||||
finished = TX_TRUE;
|
||||
|
||||
}
|
||||
|
||||
/* Move to the next thread at this priority. */
|
||||
next_thread = next_thread -> tx_thread_ready_next;
|
||||
|
||||
}
|
||||
} while ((next_thread != thread_ptr) && (finished == TX_FALSE));
|
||||
|
||||
/* Determine if we are finished. */
|
||||
if (finished == TX_FALSE)
|
||||
{
|
||||
|
||||
/* No other thread is ready at this priority... simply return. */
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(1, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Set the finished flag. */
|
||||
finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Preemption-threshold is in force. */
|
||||
|
||||
/* Set the rebalance flag. */
|
||||
rebalance = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if preemption-threshold is in force. */
|
||||
if (thread_ptr -> tx_thread_preempt_threshold < priority)
|
||||
{
|
||||
|
||||
/* Set the rebalance flag. */
|
||||
rebalance = TX_TRUE;
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Calculate the index into the bit map array. */
|
||||
map_index = priority/((UINT) 32);
|
||||
#endif
|
||||
|
||||
/* Ensure that this thread's priority is clear in the preempt map. */
|
||||
TX_MOD32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] & (~(priority_bit));
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Determine if there are any other bits set in this preempt map. */
|
||||
if (_tx_thread_preempted_maps[MAP_INDEX] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No, clear the active bit to signify this preempted map has nothing set. */
|
||||
TX_DIV32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clear the entry in the preempted list. */
|
||||
_tx_thread_preemption_threshold_list[priority] = TX_NULL;
|
||||
|
||||
/* Does this thread have preemption-threshold? */
|
||||
if (_tx_thread_preemption__threshold_scheduled == thread_ptr)
|
||||
{
|
||||
|
||||
/* Yes, set the preempted thread to NULL. */
|
||||
_tx_thread_preemption__threshold_scheduled = TX_NULL;
|
||||
}
|
||||
|
||||
/* Calculate the first thread with preemption-threshold active. */
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
if (_tx_thread_preempted_map_active != ((ULONG) 0))
|
||||
#else
|
||||
if (_tx_thread_preempted_maps[0] != ((ULONG) 0))
|
||||
#endif
|
||||
{
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Calculate the index to find the next highest priority thread ready for execution. */
|
||||
priority_map = _tx_thread_preempted_map_active;
|
||||
|
||||
/* Calculate the lowest bit set in the priority map. */
|
||||
TX_LOWEST_SET_BIT_CALCULATE(priority_map, map_index)
|
||||
|
||||
/* Calculate the base priority as well. */
|
||||
base_priority = map_index * ((UINT) 32);
|
||||
#else
|
||||
|
||||
/* Setup the base priority to zero. */
|
||||
base_priority = ((UINT) 0);
|
||||
#endif
|
||||
|
||||
/* Setup temporary preempted map. */
|
||||
priority_map = _tx_thread_preempted_maps[MAP_INDEX];
|
||||
|
||||
/* Calculate the lowest bit set in the priority map. */
|
||||
TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit_set)
|
||||
|
||||
/* Move priority bit set into priority bit. */
|
||||
priority_bit = (ULONG) priority_bit_set;
|
||||
|
||||
/* Setup the highest priority preempted thread. */
|
||||
next_preempted = base_priority + priority_bit;
|
||||
|
||||
/* Pickup the previously preempted thread. */
|
||||
preempted_thread = _tx_thread_preemption_threshold_list[next_preempted];
|
||||
|
||||
/* Setup the preempted thread. */
|
||||
_tx_thread_preemption__threshold_scheduled = preempted_thread;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Determine if this thread has preemption-threshold disabled. */
|
||||
if (thread_ptr == _tx_thread_preemption__threshold_scheduled)
|
||||
{
|
||||
|
||||
/* Clear the global preemption disable flag. */
|
||||
_tx_thread_preemption__threshold_scheduled = TX_NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check to see if there is still work to do. */
|
||||
if (finished == TX_FALSE)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(1, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Determine if we need to rebalance the execute list. */
|
||||
if (rebalance == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Rebalance the excute list. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
}
|
||||
|
||||
/* Determine if this thread needs to return to the system. */
|
||||
if (_tx_thread_execute_ptr[core_index] != thread_ptr)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the number of thread relinquishes. */
|
||||
thread_ptr -> tx_thread_performance_relinquish_count++;
|
||||
|
||||
/* Increment the total number of thread relinquish operations. */
|
||||
_tx_thread_performance_relinquish_count++;
|
||||
|
||||
/* Determine if an idle system return is present. */
|
||||
if (_tx_thread_execute_ptr[core_index] == TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, increment the return to idle return count. */
|
||||
_tx_thread_performance_idle_return_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, there is another thread ready to run and will be scheduled upon return. */
|
||||
_tx_thread_performance_non_idle_return_count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Pickup new thread pointer. */
|
||||
thread_ptr = _tx_thread_execute_ptr[core_index];
|
||||
|
||||
/* Check this thread's stack. */
|
||||
TX_THREAD_STACK_CHECK(thread_ptr)
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag in order to keep the protection. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Transfer control to the system so the scheduler can execute
|
||||
the next thread. */
|
||||
_tx_thread_system_return();
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
163
common_smp/src/tx_thread_reset.c
Normal file
163
common_smp/src/tx_thread_reset.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_reset PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function prepares the thread to run again from the entry */
|
||||
/* point specified during thread creation. The application must */
|
||||
/* call tx_thread_resume after this call completes for the thread */
|
||||
/* to actually run. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to reset */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_stack_build Build initial thread stack */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_reset(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *current_thread;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default a successful completion status. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(current_thread)
|
||||
|
||||
/* Check for a call from the current thread, which is not allowed! */
|
||||
if (current_thread == thread_ptr)
|
||||
{
|
||||
|
||||
/* Thread not completed or terminated - return an error! */
|
||||
status = TX_NOT_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Check for proper status of this thread to reset. */
|
||||
if (thread_ptr -> tx_thread_state != TX_COMPLETED)
|
||||
{
|
||||
|
||||
/* Now check for terminated state. */
|
||||
if (thread_ptr -> tx_thread_state != TX_TERMINATED)
|
||||
{
|
||||
|
||||
/* Thread not completed or terminated - return an error! */
|
||||
status = TX_NOT_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Is the request valid? */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Modify the thread status to prevent additional reset calls. */
|
||||
thread_ptr -> tx_thread_state = TX_NOT_DONE;
|
||||
|
||||
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
|
||||
TX_THREAD_RESET_PORT_COMPLETION(thread_ptr)
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#ifndef TX_DISABLE_STACK_FILLING
|
||||
|
||||
/* Set the thread stack to a pattern prior to creating the initial
|
||||
stack frame. This pattern is used by the stack checking routines
|
||||
to see how much has been used. */
|
||||
TX_MEMSET(thread_ptr -> tx_thread_stack_start, ((UCHAR) TX_STACK_FILL), thread_ptr -> tx_thread_stack_size);
|
||||
#endif
|
||||
|
||||
/* Call the target specific stack frame building routine to build the
|
||||
thread's initial stack and to setup the actual stack pointer in the
|
||||
control block. */
|
||||
_tx_thread_stack_build(thread_ptr, _tx_thread_shell_entry);
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Finally, move into a suspended state to allow for the thread to be resumed. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESET, thread_ptr, thread_ptr -> tx_thread_state, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_RESET_INSERT
|
||||
|
||||
/* Log the thread status change. */
|
||||
TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_SUSPENDED)
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status to caller. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
178
common_smp/src/tx_thread_resume.c
Normal file
178
common_smp/src/tx_thread_resume.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_initialize.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_resume PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes application resume thread services. Actual */
|
||||
/* thread resumption is performed in the core service. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to resume */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
|
||||
/* _tx_thread_system_resume Resume thread */
|
||||
/* _tx_thread_system_ni_resume Non-interruptable resume */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_resume(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
UINT core_index;
|
||||
|
||||
|
||||
/* Lockout interrupts while the thread is being resumed. */
|
||||
TX_DISABLE
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_RESUME_INSERT
|
||||
|
||||
/* Determine if the thread is suspended or in the process of suspending.
|
||||
If so, call the thread resume processing. */
|
||||
if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
|
||||
{
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Resume the thread! */
|
||||
_tx_thread_system_ni_resume(thread_ptr);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call the actual resume service to resume the thread. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the thread's preemption-threshold needs to be restored. */
|
||||
if (_tx_thread_smp_current_state_get() >= TX_INITIALIZE_IN_PROGRESS)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* Clear the preemption bit maps, since nothing has yet run during initialization. */
|
||||
TX_MEMSET(_tx_thread_preempted_maps, 0, sizeof(_tx_thread_preempted_maps));
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
_tx_thread_preempted_map_active = ((ULONG) 0);
|
||||
#endif
|
||||
#endif
|
||||
_tx_thread_preemption__threshold_scheduled = TX_NULL;
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(14, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Get the core index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(15, 0, thread_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Setup successful return status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else if (thread_ptr -> tx_thread_delayed_suspend != TX_FALSE)
|
||||
{
|
||||
|
||||
/* Clear the delayed suspension. */
|
||||
thread_ptr -> tx_thread_delayed_suspend = TX_FALSE;
|
||||
|
||||
/* Setup delayed suspend lifted return status. */
|
||||
status = TX_SUSPEND_LIFTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Setup invalid resume return status. */
|
||||
status = TX_RESUME_ERROR;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
201
common_smp/src/tx_thread_shell_entry.c
Normal file
201
common_smp/src/tx_thread_shell_entry.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_shell_entry PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function calls the specified entry function of the thread. It */
|
||||
/* also provides a place for the thread's entry function to return. */
|
||||
/* If the thread returns, this function places the thread in a */
|
||||
/* "COMPLETED" state. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* thread_entry Thread's entry function */
|
||||
/* _tx_thread_system_suspend Thread suspension routine */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Initial thread stack frame */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_shell_entry(VOID)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *thread_ptr;
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
VOID (*entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type);
|
||||
#endif
|
||||
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Perform any additional activities for tool or user purpose. */
|
||||
TX_THREAD_STARTED_EXTENSION(thread_ptr)
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup the entry/exit application callback routine. */
|
||||
entry_exit_notify = thread_ptr -> tx_thread_entry_exit_notify;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Determine if an application callback routine is specified. */
|
||||
if (entry_exit_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, notify application that this thread has been entered! */
|
||||
(entry_exit_notify)(thread_ptr, TX_THREAD_ENTRY);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call current thread's entry function. */
|
||||
(thread_ptr -> tx_thread_entry) (thread_ptr -> tx_thread_entry_parameter);
|
||||
|
||||
/* Suspend thread with a "completed" state. */
|
||||
|
||||
/* Determine if the application is using mutexes. */
|
||||
if (_tx_thread_mutex_release != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, call the mutex release function via a function pointer that
|
||||
is setup during mutex initialization. */
|
||||
(_tx_thread_mutex_release)(thread_ptr);
|
||||
}
|
||||
|
||||
/* Lockout interrupts while the thread state is setup. */
|
||||
TX_DISABLE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Pickup the entry/exit application callback routine again. */
|
||||
entry_exit_notify = thread_ptr -> tx_thread_entry_exit_notify;
|
||||
#endif
|
||||
|
||||
/* Set the status to suspending, in order to indicate the suspension
|
||||
is in progress. */
|
||||
thread_ptr -> tx_thread_state = TX_COMPLETED;
|
||||
|
||||
/* Thread state change. */
|
||||
TX_THREAD_STATE_CHANGE(thread_ptr, TX_COMPLETED)
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if an application callback routine is specified. */
|
||||
if (entry_exit_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, notify application that this thread has exited! */
|
||||
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform any additional activities for tool or user purpose. */
|
||||
TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup for no timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0);
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Perform any additional activities for tool or user purpose. */
|
||||
TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
|
||||
|
||||
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
|
||||
|
||||
/* Determine if an application callback routine is specified. */
|
||||
if (entry_exit_notify != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, notify application that this thread has exited! */
|
||||
(entry_exit_notify)(thread_ptr, TX_THREAD_EXIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TX_SAFETY_CRITICAL
|
||||
|
||||
/* If we ever get here, raise safety critical exception. */
|
||||
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
198
common_smp/src/tx_thread_sleep.c
Normal file
198
common_smp/src/tx_thread_sleep.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_timer.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_sleep PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function handles application thread sleep requests. If the */
|
||||
/* sleep request was called from a non-thread, an error is returned. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* timer_ticks Number of timer ticks to sleep*/
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Return completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Actual thread suspension */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_sleep(ULONG timer_ticks)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT status;
|
||||
TX_THREAD *thread_ptr;
|
||||
|
||||
|
||||
/* Lockout interrupts while the thread is being resumed. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(thread_ptr)
|
||||
|
||||
/* Determine if this is a legal request. */
|
||||
|
||||
/* Is there a current thread? */
|
||||
if (thread_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Illegal caller of this service. */
|
||||
status = TX_CALLER_ERROR;
|
||||
}
|
||||
|
||||
/* Is the caller an ISR or Initialization? */
|
||||
else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Illegal caller of this service. */
|
||||
status = TX_CALLER_ERROR;
|
||||
}
|
||||
|
||||
#ifndef TX_TIMER_PROCESS_IN_ISR
|
||||
|
||||
/* Is the caller the system timer thread? */
|
||||
else if (thread_ptr == &_tx_timer_thread)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Illegal caller of this service. */
|
||||
status = TX_CALLER_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if the requested number of ticks is zero. */
|
||||
else if (timer_ticks == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Just return with a successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion. */
|
||||
status = TX_CALLER_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SLEEP, TX_ULONG_TO_POINTER_CONVERT(timer_ticks), thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_SLEEP_INSERT
|
||||
|
||||
/* Suspend the current thread. */
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SLEEP;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, timer_ticks);
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Initialize the status to successful. */
|
||||
thread_ptr -> tx_thread_suspend_status = TX_SUCCESS;
|
||||
|
||||
/* Setup the timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = timer_ticks;
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Return status to the caller. */
|
||||
status = thread_ptr -> tx_thread_suspend_status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
237
common_smp/src/tx_thread_smp_core_exclude.c
Normal file
237
common_smp/src/tx_thread_smp_core_exclude.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread - High Level SMP Support */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_smp_core_exclude PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function allows the application to exclude one or more cores */
|
||||
/* from executing the specified thread. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to the thread */
|
||||
/* exclusion_map Bit map of exclusion list, */
|
||||
/* where bit 0 set means that */
|
||||
/* this thread cannot run on */
|
||||
/* core0, etc. */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* Status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list Build execution list */
|
||||
/* _tx_thread_system_return System return */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_smp_core_exclude(TX_THREAD *thread_ptr, ULONG exclusion_map)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT core_index;
|
||||
UINT new_mapped_core;
|
||||
ULONG mapped_core;
|
||||
ULONG available_cores;
|
||||
UINT restore_needed;
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Default status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* First, make sure the thread pointer is valid. */
|
||||
if (thread_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_THREAD_ERROR;
|
||||
}
|
||||
|
||||
/* Check for valid ID. */
|
||||
else if (thread_ptr -> tx_thread_id != TX_THREAD_ID)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_THREAD_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Set the restore needed flag. */
|
||||
restore_needed = TX_TRUE;
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(2, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Build the bitmap for the last mapped core. */
|
||||
mapped_core = (((ULONG) 1) << thread_ptr -> tx_thread_smp_core_mapped);
|
||||
|
||||
/* Calculate the available cores map. */
|
||||
available_cores = (~exclusion_map) & ((ULONG) TX_THREAD_SMP_CORE_MASK);
|
||||
|
||||
/* Save the excluded and available cores. */
|
||||
thread_ptr -> tx_thread_smp_cores_excluded = exclusion_map;
|
||||
thread_ptr -> tx_thread_smp_cores_allowed = available_cores;
|
||||
|
||||
/* Determine if this is within the now available cores. */
|
||||
if ((mapped_core & available_cores) == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Determine if there are any cores available. */
|
||||
if (available_cores == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No cores are available, simply set the last running core to 0. */
|
||||
thread_ptr -> tx_thread_smp_core_mapped = ((UINT) 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, we need set the last mapped core to a valid core. */
|
||||
TX_LOWEST_SET_BIT_CALCULATE(available_cores, new_mapped_core)
|
||||
|
||||
/* Now setup the last core mapped. */
|
||||
thread_ptr -> tx_thread_smp_core_mapped = new_mapped_core;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Determine if the thread is in a ready state. */
|
||||
if (thread_ptr -> tx_thread_state != TX_READY)
|
||||
{
|
||||
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(3, 0, thread_ptr);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if the thread is ready. */
|
||||
if (thread_ptr -> tx_thread_state == TX_READY)
|
||||
{
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(3, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
/* Determine if this thread needs to return to the system. */
|
||||
|
||||
/* Is there a difference between the current and execute thread pointers? */
|
||||
if (_tx_thread_execute_ptr[core_index] != _tx_thread_current_ptr[core_index])
|
||||
{
|
||||
|
||||
/* Yes, check to see if we are at the thread level. */
|
||||
if (_tx_thread_system_state[core_index] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* At the thread level, check for the preempt disable flag being set. */
|
||||
if (_tx_thread_preempt_disable == ((UINT) 0))
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag in order to keep the protection. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Transfer control to the system so the scheduler can execute
|
||||
the next thread. */
|
||||
_tx_thread_system_return();
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Clear the restore needed flag, since the interrupt poster/protection has been done. */
|
||||
restore_needed = TX_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the protection still needs to be restored. */
|
||||
if (restore_needed == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
}
|
||||
|
||||
/* Return status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
116
common_smp/src/tx_thread_smp_core_exclude_get.c
Normal file
116
common_smp/src/tx_thread_smp_core_exclude_get.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread - High Level SMP Support */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_smp_core_exclude_get PROTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function returns the current exclusion list. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to the thread */
|
||||
/* exclusion_map_ptr Destination for the current */
|
||||
/* exclusion list */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* Status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_smp_core_exclude_get(TX_THREAD *thread_ptr, ULONG *exclusion_map_ptr)
|
||||
{
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* First, make sure the thread pointer is valid. */
|
||||
if (thread_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_THREAD_ERROR;
|
||||
}
|
||||
|
||||
/* Check for valid ID. */
|
||||
else if (thread_ptr -> tx_thread_id != TX_THREAD_ID)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_THREAD_ERROR;
|
||||
}
|
||||
|
||||
/* Is the destination pointer NULL? */
|
||||
else if (exclusion_map_ptr == TX_NULL)
|
||||
{
|
||||
|
||||
/* Return pointer error. */
|
||||
status = TX_PTR_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Save the current exclusion map in the destination. */
|
||||
*exclusion_map_ptr = thread_ptr -> tx_thread_smp_cores_excluded;
|
||||
|
||||
/* Return a successful status. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Return status. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
100
common_smp/src/tx_thread_smp_current_state_set.c
Normal file
100
common_smp/src/tx_thread_smp_current_state_set.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread - High Level SMP Support */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_smp_current_state_set PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is sets the current state to all of the cores. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* new_state New per-system state */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_kernel_enter ThreadX entry */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
void _tx_thread_smp_current_state_set(ULONG new_state)
|
||||
{
|
||||
|
||||
UINT i;
|
||||
|
||||
/* Initialize the state for each to initialization. */
|
||||
i = ((UINT) (TX_THREAD_SMP_MAX_CORES-1));
|
||||
do
|
||||
{
|
||||
|
||||
/* Set this core's state. */
|
||||
_tx_thread_system_state[i] = new_state;
|
||||
|
||||
if (i == ((UINT) 0))
|
||||
{
|
||||
|
||||
/* We are finished, exit the loop. */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Decrement the index. */
|
||||
i--;
|
||||
}
|
||||
} while (TX_LOOP_FOREVER);
|
||||
}
|
||||
|
||||
223
common_smp/src/tx_thread_smp_debug_entry_insert.c
Normal file
223
common_smp/src/tx_thread_smp_debug_entry_insert.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/* Determine if debugging is enabled. */
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
|
||||
/* Define the maximum number of debug entries. */
|
||||
|
||||
#ifndef TX_THREAD_SMP_MAX_DEBUG_ENTRIES
|
||||
#define TX_THREAD_SMP_MAX_DEBUG_ENTRIES 100
|
||||
#endif
|
||||
|
||||
|
||||
/* Define the debug information structures. */
|
||||
|
||||
typedef struct TX_THREAD_SMP_DEBUG_ENTRY_STRUCT
|
||||
{
|
||||
|
||||
ULONG tx_thread_smp_debug_entry_id;
|
||||
ULONG tx_thread_smp_debug_entry_suspend;
|
||||
ULONG tx_thread_smp_debug_entry_core_index;
|
||||
ULONG tx_thread_smp_debug_entry_time;
|
||||
ULONG tx_thread_smp_debug_entry_timer_clock;
|
||||
TX_THREAD *tx_thread_smp_debug_entry_thread;
|
||||
UINT tx_thread_smp_debug_entry_thread_priority;
|
||||
UINT tx_thread_smp_debug_entry_thread_threshold;
|
||||
ULONG tx_thread_smp_debug_entry_thread_core_control;
|
||||
TX_THREAD *tx_thread_smp_debug_entry_current_thread;
|
||||
TX_THREAD_SMP_PROTECT tx_thread_smp_debug_protection;
|
||||
ULONG tx_thread_smp_debug_entry_preempt_disable;
|
||||
ULONG tx_thread_smp_debug_entry_system_state[TX_THREAD_SMP_MAX_CORES];
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
ULONG tx_thread_smp_debug_entry_preempt_map;
|
||||
#endif
|
||||
TX_THREAD *tx_thread_smp_debug_entry_preempt_thread;
|
||||
ULONG tx_thread_smp_debug_entry_priority_map;
|
||||
ULONG tx_thread_smp_debug_entry_reschedule_pending;
|
||||
TX_THREAD *tx_thread_smp_debug_entry_current_threads[TX_THREAD_SMP_MAX_CORES];
|
||||
TX_THREAD *tx_thread_smp_debug_entry_execute_threads[TX_THREAD_SMP_MAX_CORES];
|
||||
|
||||
} TX_THREAD_SMP_DEBUG_ENTRY_INFO;
|
||||
|
||||
|
||||
/* Define the circular array of debug entries. */
|
||||
|
||||
TX_THREAD_SMP_DEBUG_ENTRY_INFO _tx_thread_smp_debug_info_array[TX_THREAD_SMP_MAX_DEBUG_ENTRIES];
|
||||
|
||||
|
||||
/* Define the starting index. */
|
||||
|
||||
ULONG _tx_thread_smp_debug_info_current_index;
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_smp_debug_entry_insert PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is responsible for making an entry in the circular */
|
||||
/* debug log. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* id ID of event */
|
||||
/* suspend Flag set to true for suspend */
|
||||
/* events */
|
||||
/* thread_ptr Specified thread */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_time_get Get global time stamp */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Internal routines */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
void _tx_thread_smp_debug_entry_insert(ULONG id, ULONG suspend, VOID *thread_void_ptr)
|
||||
{
|
||||
|
||||
ULONG i;
|
||||
ULONG core_index;
|
||||
TX_THREAD_SMP_DEBUG_ENTRY_INFO *entry_ptr;
|
||||
TX_THREAD *thread_ptr;
|
||||
|
||||
|
||||
/* Spin, if an error is detected. No sense in populating the debug after the error occurs. */
|
||||
while (_tx_thread_smp_system_error)
|
||||
{
|
||||
|
||||
/* Spin here! */
|
||||
}
|
||||
|
||||
/* Check for a bad current index. */
|
||||
while (_tx_thread_smp_debug_info_current_index >= TX_THREAD_SMP_MAX_DEBUG_ENTRIES)
|
||||
{
|
||||
|
||||
/* Spin here! */
|
||||
}
|
||||
|
||||
thread_ptr = (TX_THREAD *) thread_void_ptr;
|
||||
|
||||
/* It is assumed that interrupts are locked out at this point. */
|
||||
|
||||
/* Setup pointer to debug entry. */
|
||||
entry_ptr = &_tx_thread_smp_debug_info_array[_tx_thread_smp_debug_info_current_index++];
|
||||
|
||||
/* Check for wrap on the index. */
|
||||
if (_tx_thread_smp_debug_info_current_index >= TX_THREAD_SMP_MAX_DEBUG_ENTRIES)
|
||||
{
|
||||
|
||||
/* Wrap back to 0. */
|
||||
_tx_thread_smp_debug_info_current_index = 0;
|
||||
}
|
||||
|
||||
/* Get the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* We know at this point that multithreading and interrupts are disabled... so start populating the array. */
|
||||
entry_ptr -> tx_thread_smp_debug_entry_id = id;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_suspend = suspend;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread = thread_ptr;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_time = _tx_thread_smp_time_get();
|
||||
entry_ptr -> tx_thread_smp_debug_entry_timer_clock = _tx_timer_system_clock;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_core_index = core_index;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_current_thread = _tx_thread_current_ptr[core_index];
|
||||
if (entry_ptr -> tx_thread_smp_debug_entry_current_thread)
|
||||
{
|
||||
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread_priority = (entry_ptr -> tx_thread_smp_debug_entry_current_thread) -> tx_thread_priority;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread_threshold = (entry_ptr -> tx_thread_smp_debug_entry_current_thread) -> tx_thread_preempt_threshold;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread_core_control = (entry_ptr -> tx_thread_smp_debug_entry_current_thread) -> tx_thread_smp_core_control;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread_priority = 0;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread_threshold = 0;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_thread_core_control = 0;
|
||||
}
|
||||
|
||||
entry_ptr -> tx_thread_smp_debug_protection = _tx_thread_smp_protection;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_preempt_disable = _tx_thread_preempt_disable;
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
entry_ptr -> tx_thread_smp_debug_entry_preempt_map = _tx_thread_preempted_maps[0];
|
||||
#endif
|
||||
entry_ptr -> tx_thread_smp_debug_entry_preempt_thread = _tx_thread_preemption__threshold_scheduled;
|
||||
entry_ptr -> tx_thread_smp_debug_entry_priority_map = _tx_thread_priority_maps[0];
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
/* Loop to save the current and execute lists. */
|
||||
for (i = 0; i < TX_THREAD_SMP_MAX_CORES; i++)
|
||||
#else
|
||||
|
||||
/* Loop to save the current and execute lists. */
|
||||
for (i = 0; i < _tx_thread_smp_max_cores; i++)
|
||||
#endif
|
||||
{
|
||||
|
||||
/* Save the pointers. */
|
||||
entry_ptr -> tx_thread_smp_debug_entry_current_threads[i] = _tx_thread_current_ptr[i];
|
||||
entry_ptr -> tx_thread_smp_debug_entry_execute_threads[i] = _tx_thread_execute_ptr[i];
|
||||
|
||||
/* Save the system state. */
|
||||
entry_ptr -> tx_thread_smp_debug_entry_system_state[i] = _tx_thread_system_state[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
118
common_smp/src/tx_thread_smp_high_level_initialize.c
Normal file
118
common_smp/src/tx_thread_smp_high_level_initialize.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Initialization */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_smp_high_level_initialize PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function initializes the ThreadX SMP data structures and */
|
||||
/* CPU registers. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_initialize_kernel_enter ThreadX entry */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
void _tx_thread_smp_high_level_initialize(void)
|
||||
{
|
||||
|
||||
/* Clear the system error flag. */
|
||||
_tx_thread_smp_system_error = TX_FALSE;
|
||||
|
||||
/* Ensure that the system state variable is set to indicate
|
||||
initialization is in progress. Note that this variable is
|
||||
later used to represent interrupt nesting. */
|
||||
_tx_thread_smp_current_state_set(TX_INITIALIZE_IN_PROGRESS);
|
||||
|
||||
/* Clear the thread protection. */
|
||||
TX_MEMSET(&_tx_thread_smp_protection, 0, sizeof(TX_THREAD_SMP_PROTECT));
|
||||
|
||||
/* Set the field of the protection to all ones to indicate it is invalid. */
|
||||
_tx_thread_smp_protection.tx_thread_smp_protect_core = ((ULONG) 0xFFFFFFFFUL);
|
||||
|
||||
/* Clear the thread schedule list. */
|
||||
TX_MEMSET(&_tx_thread_smp_schedule_list[0], 0, sizeof(_tx_thread_smp_schedule_list));
|
||||
|
||||
/* Initialize core list. */
|
||||
TX_MEMSET(&_tx_thread_smp_protect_wait_list[0], 0xff, sizeof(_tx_thread_smp_protect_wait_list));
|
||||
|
||||
/* Set the wait list size so we can access it from assembly functions. */
|
||||
_tx_thread_smp_protect_wait_list_size = TX_THREAD_SMP_PROTECT_WAIT_LIST_SIZE;
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
/* Call low-level SMP initialize. */
|
||||
_tx_thread_smp_low_level_initialize(((UINT) TX_THREAD_SMP_MAX_CORES));
|
||||
#else
|
||||
|
||||
/* Determine if the dynamic maximum number of cores is 0. If so, default it
|
||||
to the compile-time maximum. */
|
||||
if (_tx_thread_smp_max_cores == 0)
|
||||
{
|
||||
|
||||
/* Default to the compile-time maximum. */
|
||||
_tx_thread_smp_max_cores = TX_THREAD_SMP_MAX_CORES;
|
||||
}
|
||||
|
||||
/* Call low-level SMP initialize. */
|
||||
_tx_thread_smp_low_level_initialize(_tx_thread_smp_max_cores);
|
||||
#endif
|
||||
}
|
||||
581
common_smp/src/tx_thread_smp_rebalance_execute_list.c
Normal file
581
common_smp/src/tx_thread_smp_rebalance_execute_list.c
Normal file
@@ -0,0 +1,581 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread - High Level SMP Support */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_smp_rebalance_execute_list PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function is responsible for mapping ready ThreadX threads with */
|
||||
/* cores in the SMP . The basic idea is the standard ThreadX */
|
||||
/* ready list is traversed to build the _tx_thread_execute_ptr list. */
|
||||
/* Each index represents the and the corresponding entry in this */
|
||||
/* array contains the thread that should be executed by that core. If */
|
||||
/* the was previously running a different thread, it will be */
|
||||
/* preempted and restarted so it can run the new thread. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_execute_list_clear Clear the thread execute list */
|
||||
/* _tx_thread_smp_execute_list_setup Setup the thread execute list */
|
||||
/* _tx_thread_smp_next_priority_find Find next priority with one */
|
||||
/* or more ready threads */
|
||||
/* _tx_thread_smp_remap_solution_find Attempt to remap threads to */
|
||||
/* schedule another thread */
|
||||
/* _tx_thread_smp_schedule_list_clear Clear the thread schedule list*/
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_mutex_priority_change Mutex priority change */
|
||||
/* _tx_thread_create Thread create */
|
||||
/* _tx_thread_preemption_change Thread preemption change */
|
||||
/* _tx_thread_priority_change Thread priority change */
|
||||
/* _tx_thread_relinquish Thread relinquish */
|
||||
/* _tx_thread_resume Thread resume */
|
||||
/* _tx_thread_smp_core_exclude Thread SMP core exclude */
|
||||
/* _tx_thread_system_resume Thread system resume */
|
||||
/* _tx_thread_system_suspend Thread suspend */
|
||||
/* _tx_thread_time_slice Thread time-slice */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
void _tx_thread_smp_rebalance_execute_list(UINT core_index)
|
||||
{
|
||||
|
||||
UINT i, j, core;
|
||||
UINT next_priority;
|
||||
UINT last_priority;
|
||||
TX_THREAD *schedule_thread;
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
TX_THREAD *mapped_thread;
|
||||
#endif
|
||||
TX_THREAD *preempted_thread;
|
||||
ULONG possible_cores;
|
||||
ULONG thread_possible_cores;
|
||||
ULONG available_cores;
|
||||
ULONG test_possible_cores;
|
||||
ULONG test_cores;
|
||||
UINT this_pass_complete;
|
||||
UINT loop_finished;
|
||||
|
||||
#ifdef TX_THREAD_SMP_EQUAL_PRIORITY
|
||||
TX_THREAD *highest_priority_thread;
|
||||
#endif
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
ULONG priority_bit;
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
UINT map_index;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* It is assumed that the preempt disable flag is still set at this point. */
|
||||
|
||||
/* Pickup the last schedule thread with preemption-threshold enabled. */
|
||||
preempted_thread = _tx_thread_preemption__threshold_scheduled;
|
||||
|
||||
/* Clear the schedule list. */
|
||||
_tx_thread_smp_schedule_list_clear();
|
||||
|
||||
/* Initialize the next priority to 0, the highest priority. */
|
||||
next_priority = ((UINT) 0);
|
||||
|
||||
/* Initialize the last priority. */
|
||||
last_priority = ((UINT) 0);
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
/* Set the possible cores bit map to all cores. */
|
||||
possible_cores = ((ULONG) TX_THREAD_SMP_CORE_MASK);
|
||||
#else
|
||||
|
||||
/* Set the possible cores bit map to all cores. */
|
||||
possible_cores = (((ULONG) 1) << _tx_thread_smp_max_cores) - 1;
|
||||
#endif
|
||||
|
||||
/* Setup the available cores bit map. */
|
||||
available_cores = possible_cores;
|
||||
|
||||
/* Clear the schedule thread pointer. */
|
||||
schedule_thread = TX_NULL;
|
||||
|
||||
#ifdef TX_THREAD_SMP_EQUAL_PRIORITY
|
||||
|
||||
/* Set the highest priority thread to NULL. */
|
||||
highest_priority_thread = TX_NULL;
|
||||
#endif
|
||||
|
||||
/* Loop to rebuild the schedule list. */
|
||||
i = ((UINT) 0);
|
||||
loop_finished = TX_FALSE;
|
||||
do
|
||||
{
|
||||
|
||||
/* Clear the pass complete flag, which is used to skip the remaining processing
|
||||
of this loop on certain conditions. */
|
||||
this_pass_complete = TX_FALSE;
|
||||
|
||||
/* Determine if there is a thread to schedule. */
|
||||
if (schedule_thread == TX_NULL)
|
||||
{
|
||||
|
||||
/* Calculate the next ready priority. */
|
||||
next_priority = _tx_thread_smp_next_priority_find(next_priority);
|
||||
|
||||
/* Determine if there are no more threads to execute. */
|
||||
if (next_priority == ((UINT) TX_MAX_PRIORITIES))
|
||||
{
|
||||
|
||||
/* Break out of loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
this_pass_complete = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if a thread was executed with preemption-threshold set. */
|
||||
if (preempted_thread != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, a thread was previously preempted. Let's first see if we reached the
|
||||
interrupted preemption-threshold level. */
|
||||
if (next_priority >= preempted_thread -> tx_thread_preempt_threshold)
|
||||
{
|
||||
|
||||
/* Yes, now lets see if we are within the preemption-threshold level. */
|
||||
if (next_priority <= preempted_thread -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, move the next priority to the preempted priority. */
|
||||
next_priority = preempted_thread -> tx_thread_priority;
|
||||
|
||||
/* Setup the schedule thread to the preempted thread. */
|
||||
schedule_thread = preempted_thread;
|
||||
|
||||
/* Start at the top of the loop. */
|
||||
this_pass_complete = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Nothing else is allowed to execute after the preemption-threshold thread. */
|
||||
next_priority = ((UINT) TX_MAX_PRIORITIES);
|
||||
|
||||
/* Break out of loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
this_pass_complete = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if this pass through the loop is already complete. */
|
||||
if (this_pass_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Pickup the next thread to schedule. */
|
||||
schedule_thread = _tx_thread_priority_list[next_priority];
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if this pass through the loop is already complete. */
|
||||
if (this_pass_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Determine what the possible cores are for this thread. */
|
||||
thread_possible_cores = schedule_thread -> tx_thread_smp_cores_allowed;
|
||||
|
||||
/* Apply the current possible cores. */
|
||||
thread_possible_cores = thread_possible_cores & (available_cores | possible_cores);
|
||||
|
||||
/* Determine if it is possible to schedule this thread. */
|
||||
if (thread_possible_cores == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No, this thread can't be scheduled. */
|
||||
|
||||
/* Look at the next thread at the same priority level. */
|
||||
schedule_thread = schedule_thread -> tx_thread_ready_next;
|
||||
|
||||
/* Determine if this is the head of the list. */
|
||||
if (schedule_thread == _tx_thread_priority_list[next_priority])
|
||||
{
|
||||
|
||||
/* Set the schedule thread to NULL to force examination of the next priority level. */
|
||||
schedule_thread = TX_NULL;
|
||||
|
||||
/* Move to the next priority level. */
|
||||
next_priority++;
|
||||
|
||||
/* Determine if there are no more threads to execute. */
|
||||
if (next_priority == ((UINT) TX_MAX_PRIORITIES))
|
||||
{
|
||||
|
||||
/* Break out of loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* It is possible to schedule this thread. */
|
||||
|
||||
/* Determine if this thread has preemption-threshold set. */
|
||||
if (schedule_thread -> tx_thread_preempt_threshold < schedule_thread -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* Yes, preemption-threshold is set. */
|
||||
|
||||
/* Determine if the last priority is above the preemption-threshold. If not, we can't
|
||||
schedule this thread with preemption-threshold set. */
|
||||
if ((last_priority >= schedule_thread -> tx_thread_preempt_threshold) && (i != ((UINT) 0)))
|
||||
{
|
||||
|
||||
/* A thread was found that violates the next thread to be scheduled's preemption-threshold. We will simply
|
||||
skip this thread and see if there is anything else we can schedule. */
|
||||
|
||||
/* Look at the next thread at the same priority level. */
|
||||
schedule_thread = schedule_thread -> tx_thread_ready_next;
|
||||
|
||||
/* Determine if this is the head of the list. */
|
||||
if (schedule_thread == _tx_thread_priority_list[next_priority])
|
||||
{
|
||||
|
||||
/* Set the schedule thread to NULL to force examination of the next priority level. */
|
||||
schedule_thread = TX_NULL;
|
||||
|
||||
/* Move to the next priority level. */
|
||||
next_priority++;
|
||||
|
||||
/* Determine if there are no more threads to execute. */
|
||||
if (next_priority == ((UINT) TX_MAX_PRIORITIES))
|
||||
{
|
||||
|
||||
/* Break out of loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart the loop. */
|
||||
this_pass_complete = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if this pass through the loop is already complete. */
|
||||
if (this_pass_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Initialize index to an invalid value. */
|
||||
j = ((UINT) TX_THREAD_SMP_MAX_CORES);
|
||||
#endif
|
||||
|
||||
/* Determine if there is an available core for this thread to execute on. */
|
||||
if ((thread_possible_cores & available_cores) != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Pickup the last executed core for this thread. */
|
||||
j = schedule_thread -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Is this core valid and available? */
|
||||
if ((thread_possible_cores & available_cores & (((ULONG) 1) << j)) == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* No, we must find the next core for this thread. */
|
||||
test_cores = (thread_possible_cores & available_cores);
|
||||
TX_LOWEST_SET_BIT_CALCULATE(test_cores, j)
|
||||
|
||||
/* Setup the last executed core for this thread. */
|
||||
schedule_thread -> tx_thread_smp_core_mapped = j;
|
||||
}
|
||||
|
||||
/* Place the this thread on this core. */
|
||||
_tx_thread_smp_schedule_list[j] = schedule_thread;
|
||||
|
||||
/* Clear the associated available cores bit. */
|
||||
available_cores = available_cores & ~(((ULONG) 1) << j);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Note that we know that the thread must have at least one core excluded at this point,
|
||||
since we didn't find a match and we have available cores. */
|
||||
|
||||
/* Now we need to see if one of the other threads in the non-excluded cores can be moved to make room
|
||||
for this thread. */
|
||||
|
||||
/* Determine the possible core remapping attempt. */
|
||||
test_possible_cores = possible_cores & ~(thread_possible_cores);
|
||||
|
||||
/* Attempt to remap the cores in order to schedule this thread. */
|
||||
core = _tx_thread_smp_remap_solution_find(schedule_thread, available_cores, thread_possible_cores, test_possible_cores);
|
||||
|
||||
/* Determine if remapping was successful. */
|
||||
if (core != ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
{
|
||||
|
||||
/* Yes, remapping was successful. Update the available cores accordingly. */
|
||||
available_cores = available_cores & ~(((ULONG) 1) << core);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* We couldn't assign the thread to any of the cores possible for the thread. */
|
||||
|
||||
/* Check to see if the thread is the last thread preempted. */
|
||||
if (schedule_thread == preempted_thread)
|
||||
{
|
||||
|
||||
/* To honor the preemption-threshold, we cannot schedule any more threads. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* update the available cores for the next pass so we don't waste time looking at them again! */
|
||||
possible_cores = possible_cores & (~thread_possible_cores);
|
||||
|
||||
/* No, we couldn't load the thread because none of the required cores were available. Look at the next thread at the same priority level. */
|
||||
schedule_thread = schedule_thread -> tx_thread_ready_next;
|
||||
|
||||
/* Determine if this is the head of the list. */
|
||||
if (schedule_thread == _tx_thread_priority_list[next_priority])
|
||||
{
|
||||
|
||||
/* Set the schedule thread to NULL to force examination of the next priority level. */
|
||||
schedule_thread = TX_NULL;
|
||||
|
||||
/* Move to the next priority level. */
|
||||
next_priority++;
|
||||
|
||||
/* Determine if there are no more threads to execute. */
|
||||
if (next_priority == ((UINT) TX_MAX_PRIORITIES))
|
||||
{
|
||||
|
||||
/* Break out of loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart the loop. */
|
||||
this_pass_complete = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if this pass through the loop is already complete. */
|
||||
if (this_pass_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_SMP_EQUAL_PRIORITY
|
||||
|
||||
/* Determine if this is the highest priority thread. */
|
||||
if (highest_priority_thread == TX_NULL)
|
||||
{
|
||||
|
||||
/* No highest priority yet, remember this thread. */
|
||||
highest_priority_thread = schedule_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Increment the number of threads loaded. */
|
||||
i++;
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Determine if the thread was mapped. */
|
||||
if (j != ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
{
|
||||
|
||||
/* Pickup the currently mapped thread. */
|
||||
mapped_thread = _tx_thread_execute_ptr[j];
|
||||
|
||||
/* Determine if preemption is present. */
|
||||
if ((mapped_thread != TX_NULL) && (schedule_thread != mapped_thread))
|
||||
{
|
||||
|
||||
/* Determine if the previously mapped thread is still ready. */
|
||||
if (mapped_thread -> tx_thread_state == TX_READY)
|
||||
{
|
||||
|
||||
/* Determine if the caller is an interrupt or from a thread. */
|
||||
if (_tx_thread_system_state[core_index] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Caller is a thread, so this is a solicited preemption. */
|
||||
_tx_thread_performance_solicited_preemption_count++;
|
||||
|
||||
/* Increment the thread's solicited preemption counter. */
|
||||
mapped_thread -> tx_thread_performance_solicited_preemption_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Is this an interrupt? */
|
||||
if (_tx_thread_system_state[core_index] < TX_INITIALIZE_IN_PROGRESS)
|
||||
{
|
||||
|
||||
/* Caller is an interrupt, so this is an interrupt preemption. */
|
||||
_tx_thread_performance_interrupt_preemption_count++;
|
||||
|
||||
/* Increment the thread's interrupt preemption counter. */
|
||||
mapped_thread -> tx_thread_performance_interrupt_preemption_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if this thread has preemption-threshold set. */
|
||||
if (schedule_thread -> tx_thread_preempt_threshold < schedule_thread -> tx_thread_priority)
|
||||
{
|
||||
|
||||
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
|
||||
|
||||
/* mark the bit map to show that a thread with preemption-threshold has been executed. */
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Calculate the index into the bit map array. */
|
||||
map_index = (schedule_thread -> tx_thread_priority)/((UINT) 32);
|
||||
|
||||
/* Set the active bit to remember that the preempt map has something set. */
|
||||
TX_DIV32_BIT_SET(schedule_thread -> tx_thread_priority, priority_bit)
|
||||
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
|
||||
#endif
|
||||
|
||||
/* Remember that this thread was executed with preemption-threshold set. */
|
||||
TX_MOD32_BIT_SET(schedule_thread -> tx_thread_priority, priority_bit)
|
||||
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
|
||||
|
||||
/* Place the thread in the preempted list indicating preemption-threshold is in force. */
|
||||
_tx_thread_preemption_threshold_list[schedule_thread -> tx_thread_priority] = schedule_thread;
|
||||
#endif
|
||||
|
||||
/* Set the last thread with preemption-threshold enabled. */
|
||||
_tx_thread_preemption__threshold_scheduled = schedule_thread;
|
||||
|
||||
/* Now break out of the scheduling loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Remember the last priority. */
|
||||
last_priority = next_priority;
|
||||
|
||||
/* Pickup the next ready thread at the current priority level. */
|
||||
schedule_thread = schedule_thread -> tx_thread_ready_next;
|
||||
|
||||
/* Determine if this is the head of the list, which implies that we have exhausted this priority level. */
|
||||
if (schedule_thread == _tx_thread_priority_list[next_priority])
|
||||
{
|
||||
|
||||
/* Set the schedule thread to NULL to force examination of the next priority level. */
|
||||
schedule_thread = TX_NULL;
|
||||
|
||||
/* Move to the next priority level. */
|
||||
next_priority++;
|
||||
|
||||
#ifdef TX_THREAD_SMP_EQUAL_PRIORITY
|
||||
|
||||
/* Determine if there is a highest priority thread. */
|
||||
if (highest_priority_thread)
|
||||
{
|
||||
|
||||
/* Yes, break out of the loop, since only same priority threads can be
|
||||
scheduled in this mode. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if there are no more threads to execute. */
|
||||
if (next_priority == ((UINT) TX_MAX_PRIORITIES))
|
||||
{
|
||||
|
||||
/* Break out of loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the loop is finished. */
|
||||
if (loop_finished == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Finished, break the loop. */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
|
||||
} while (i < ((UINT) TX_THREAD_SMP_MAX_CORES));
|
||||
#else
|
||||
|
||||
} while (i < _tx_thread_smp_max_cores);
|
||||
#endif
|
||||
|
||||
/* Clear the execute list. */
|
||||
_tx_thread_smp_execute_list_clear();
|
||||
|
||||
/* Setup the execute list based on the updated schedule list. */
|
||||
_tx_thread_smp_execute_list_setup(core_index);
|
||||
}
|
||||
|
||||
1120
common_smp/src/tx_thread_smp_utilities.c
Normal file
1120
common_smp/src/tx_thread_smp_utilities.c
Normal file
File diff suppressed because it is too large
Load Diff
181
common_smp/src/tx_thread_stack_analyze.c
Normal file
181
common_smp/src/tx_thread_stack_analyze.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_stack_analyze PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function analyzes the stack to calculate the highest stack */
|
||||
/* pointer in the thread's stack. This can then be used to derive the */
|
||||
/* minimum amount of stack left for any given thread. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Thread control block pointer */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* ThreadX internal code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_stack_analyze(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
ULONG *stack_ptr;
|
||||
ULONG *stack_lowest;
|
||||
ULONG *stack_highest;
|
||||
ULONG size;
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the thread pointer is NULL. */
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Determine if the thread ID is invalid. */
|
||||
if (thread_ptr -> tx_thread_id == TX_THREAD_ID)
|
||||
{
|
||||
|
||||
/* Pickup the current stack variables. */
|
||||
stack_lowest = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_start);
|
||||
|
||||
/* Determine if the pointer is null. */
|
||||
if (stack_lowest != TX_NULL)
|
||||
{
|
||||
|
||||
/* Pickup the highest stack pointer. */
|
||||
stack_highest = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr);
|
||||
|
||||
/* Determine if the pointer is null. */
|
||||
if (stack_highest != TX_NULL)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* We need to binary search the remaining stack for missing 0xEFEFEFEF 32-bit data pattern.
|
||||
This is a best effort algorithm to find the highest stack usage. */
|
||||
do
|
||||
{
|
||||
|
||||
/* Calculate the size again. */
|
||||
size = (ULONG) (TX_ULONG_POINTER_DIF(stack_highest, stack_lowest))/((ULONG) 2);
|
||||
stack_ptr = TX_ULONG_POINTER_ADD(stack_lowest, size);
|
||||
|
||||
/* Determine if the pattern is still there. */
|
||||
if (*stack_ptr != TX_STACK_FILL)
|
||||
{
|
||||
|
||||
/* Update the stack highest, since we need to look in the upper half now. */
|
||||
stack_highest = stack_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Update the stack lowest, since we need to look in the lower half now. */
|
||||
stack_lowest = stack_ptr;
|
||||
}
|
||||
|
||||
} while(size > ((ULONG) 1));
|
||||
|
||||
/* Position to first used word - at this point we are within a few words. */
|
||||
while (*stack_ptr == TX_STACK_FILL)
|
||||
{
|
||||
|
||||
/* Position to next word in stack. */
|
||||
stack_ptr = TX_ULONG_POINTER_ADD(stack_ptr, 1);
|
||||
}
|
||||
|
||||
/* Optional processing extension. */
|
||||
TX_THREAD_STACK_ANALYZE_EXTENSION
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Check to see if the thread is still created. */
|
||||
if (thread_ptr -> tx_thread_id == TX_THREAD_ID)
|
||||
{
|
||||
|
||||
/* Yes, thread is still created. */
|
||||
|
||||
/* Now check the new highest stack pointer is past the stack start. */
|
||||
if (stack_ptr > (TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_start)))
|
||||
{
|
||||
|
||||
/* Yes, now check that the new highest stack pointer is less than the previous highest stack pointer. */
|
||||
if (stack_ptr < (TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_stack_highest_ptr)))
|
||||
{
|
||||
|
||||
/* Yes, is the current highest stack pointer pointing at used memory? */
|
||||
if (*stack_ptr != TX_STACK_FILL)
|
||||
{
|
||||
|
||||
/* Yes, setup the highest stack usage. */
|
||||
thread_ptr -> tx_thread_stack_highest_ptr = stack_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
|
||||
105
common_smp/src/tx_thread_stack_error_handler.c
Normal file
105
common_smp/src/tx_thread_stack_error_handler.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_stack_error_handler PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function processes stack errors detected during run-time. The */
|
||||
/* processing currently consists of a spin loop. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Thread control block pointer */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* ThreadX internal code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_stack_error_handler(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Determine if the application has registered an error handler. */
|
||||
if (_tx_thread_application_stack_error_handler != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, an error handler is present, simply call the application error handler. */
|
||||
(_tx_thread_application_stack_error_handler)(thread_ptr);
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
#else
|
||||
|
||||
/* Access input argument just for the sake of lint, MISRA, etc. */
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
125
common_smp/src/tx_thread_stack_error_notify.c
Normal file
125
common_smp/src/tx_thread_stack_error_notify.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
#include "tx_trace.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_stack_error_notify PORTABLE C */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function registers an application stack error handler. If */
|
||||
/* ThreadX detects a stack error, this application handler is called. */
|
||||
/* */
|
||||
/* Note: stack checking must be enabled for this routine to serve any */
|
||||
/* purpose via the TX_ENABLE_STACK_CHECKING define. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* stack_error_handler Pointer to stack error */
|
||||
/* handler, TX_NULL to disable */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Service return status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application Code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_stack_error_notify(VOID (*stack_error_handler)(TX_THREAD *thread_ptr))
|
||||
{
|
||||
|
||||
#ifndef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
UINT status;
|
||||
|
||||
|
||||
/* Access input argument just for the sake of lint, MISRA, etc. */
|
||||
if (stack_error_handler != TX_NULL)
|
||||
{
|
||||
|
||||
/* Stack checking is not enabled, just return an error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Stack checking is not enabled, just return an error. */
|
||||
status = TX_FEATURE_NOT_ENABLED;
|
||||
}
|
||||
|
||||
/* Return completion status. */
|
||||
return(status);
|
||||
#else
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_STACK_ERROR_NOTIFY, 0, 0, 0, 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Make entry in event log. */
|
||||
TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT
|
||||
|
||||
/* Setup global thread stack error handler. */
|
||||
_tx_thread_application_stack_error_handler = stack_error_handler;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Return success to caller. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
207
common_smp/src/tx_thread_suspend.c
Normal file
207
common_smp/src/tx_thread_suspend.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_trace.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_suspend PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function handles application suspend requests. If the suspend */
|
||||
/* requires actual processing, this function calls the actual suspend */
|
||||
/* thread routine. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to suspend */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* status Return completion status */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_suspend Actual thread suspension */
|
||||
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Application code */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
UINT _tx_thread_suspend(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
TX_THREAD *current_thread;
|
||||
UINT status;
|
||||
UINT core_index;
|
||||
|
||||
|
||||
/* Lockout interrupts while the thread is being suspended. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Pickup thread pointer. */
|
||||
TX_THREAD_GET_CURRENT(current_thread)
|
||||
|
||||
/* If trace is enabled, insert this event into the trace buffer. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_SUSPEND_API, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&status), 0, TX_TRACE_THREAD_EVENTS)
|
||||
|
||||
/* Log this kernel call. */
|
||||
TX_EL_THREAD_SUSPEND_INSERT
|
||||
|
||||
/* Check the specified thread's current status. */
|
||||
if (thread_ptr -> tx_thread_state == TX_READY)
|
||||
{
|
||||
|
||||
/* Initialize status to success. */
|
||||
status = TX_SUCCESS;
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Determine if we are in a thread context. */
|
||||
if (_tx_thread_system_state[core_index] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, we are in a thread context. */
|
||||
|
||||
/* Determine if the current thread is also the suspending thread. */
|
||||
if (current_thread == thread_ptr)
|
||||
{
|
||||
|
||||
/* Determine if the preempt disable flag is non-zero. */
|
||||
if (_tx_thread_preempt_disable != ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Thread is terminated or completed. */
|
||||
status = TX_SUSPEND_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the status is still successful. */
|
||||
if (status == TX_SUCCESS)
|
||||
{
|
||||
|
||||
/* Set the state to suspended. */
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Call actual non-interruptable thread suspension routine. */
|
||||
_tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#else
|
||||
|
||||
/* Set the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_TRUE;
|
||||
|
||||
/* Setup for no timeout period. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0);
|
||||
|
||||
/* Temporarily disable preemption. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Call actual thread suspension routine. */
|
||||
_tx_thread_system_suspend(thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Return success. */
|
||||
status = TX_SUCCESS;
|
||||
#else
|
||||
|
||||
/* If MISRA is not enabled, return directly. */
|
||||
return(TX_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (thread_ptr -> tx_thread_state == TX_TERMINATED)
|
||||
{
|
||||
|
||||
/* Thread is terminated. */
|
||||
status = TX_SUSPEND_ERROR;
|
||||
}
|
||||
else if (thread_ptr -> tx_thread_state == TX_COMPLETED)
|
||||
{
|
||||
|
||||
/* Thread is completed. */
|
||||
status = TX_SUSPEND_ERROR;
|
||||
}
|
||||
else if (thread_ptr -> tx_thread_state == TX_SUSPENDED)
|
||||
{
|
||||
|
||||
/* Already suspended, just set status to success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Just set the delayed suspension flag. */
|
||||
thread_ptr -> tx_thread_delayed_suspend = TX_TRUE;
|
||||
|
||||
/* Set status to success. */
|
||||
status = TX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
|
||||
/* Always return success, since this function does not perform error
|
||||
checking. */
|
||||
return(status);
|
||||
}
|
||||
|
||||
168
common_smp/src/tx_thread_system_preempt_check.c
Normal file
168
common_smp/src/tx_thread_system_preempt_check.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_thread.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_system_preempt_check PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function checks for preemption that could have occurred as a */
|
||||
/* result scheduling activities occurring while the preempt disable */
|
||||
/* flag was set. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_system_return Return to the system */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* Other ThreadX Components */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_system_preempt_check(VOID)
|
||||
{
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
UINT core_index;
|
||||
UINT restore_needed;
|
||||
|
||||
|
||||
/* Disable interrupts. */
|
||||
TX_DISABLE
|
||||
|
||||
/* Set the restore needed flag. */
|
||||
restore_needed = TX_TRUE;
|
||||
|
||||
/* Pickup the index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
/* Determine if the call is from initialization, an ISR or if the preempt disable flag is set. */
|
||||
if (_tx_thread_system_state[core_index] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Ensure the preempt disable flag is not set. */
|
||||
if (_tx_thread_preempt_disable == ((UINT) 0))
|
||||
{
|
||||
|
||||
/* Thread execution - now determine if preemption should take place. */
|
||||
if (_tx_thread_current_ptr[core_index] != _tx_thread_execute_ptr[core_index])
|
||||
{
|
||||
|
||||
/* Yes, thread preemption should take place. */
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
TX_THREAD *thread_ptr;
|
||||
|
||||
/* Pickup the next execute pointer. */
|
||||
thread_ptr = _tx_thread_execute_ptr[core_index];
|
||||
|
||||
/* Determine if there is a thread pointer. */
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Check this thread's stack. */
|
||||
TX_THREAD_STACK_CHECK(thread_ptr)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Determine if an idle system return is present. */
|
||||
if (_tx_thread_execute_ptr[core_index] == TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, increment the return to idle return count. */
|
||||
_tx_thread_performance_idle_return_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, there is another thread ready to run and will be scheduled upon return. */
|
||||
_tx_thread_performance_non_idle_return_count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag in order to keep the protection. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Return to the system so the higher priority thread can be scheduled. */
|
||||
_tx_thread_system_return();
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Clear the restore needed flag, since the interrupt poster/protection has been done. */
|
||||
restore_needed = TX_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if the protection still needs to be restored. */
|
||||
if (restore_needed == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
}
|
||||
|
||||
969
common_smp/src/tx_thread_system_resume.c
Normal file
969
common_smp/src/tx_thread_system_resume.c
Normal file
@@ -0,0 +1,969 @@
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
||||
/* */
|
||||
/* This software is licensed under the Microsoft Software License */
|
||||
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
|
||||
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
|
||||
/* and in the root directory of this software. */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
/** */
|
||||
/** ThreadX Component */
|
||||
/** */
|
||||
/** Thread */
|
||||
/** */
|
||||
/**************************************************************************/
|
||||
/**************************************************************************/
|
||||
|
||||
#define TX_SOURCE_CODE
|
||||
#define TX_THREAD_SMP_SOURCE_CODE
|
||||
|
||||
|
||||
/* Include necessary system files. */
|
||||
|
||||
#include "tx_api.h"
|
||||
#include "tx_initialize.h"
|
||||
#include "tx_timer.h"
|
||||
#include "tx_thread.h"
|
||||
#include "tx_trace.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/* */
|
||||
/* FUNCTION RELEASE */
|
||||
/* */
|
||||
/* _tx_thread_system_resume PORTABLE SMP */
|
||||
/* 6.0.1 */
|
||||
/* AUTHOR */
|
||||
/* */
|
||||
/* William E. Lamie, Microsoft Corporation */
|
||||
/* */
|
||||
/* DESCRIPTION */
|
||||
/* */
|
||||
/* This function places the specified thread on the list of ready */
|
||||
/* threads at the thread's specific priority. If a thread preemption */
|
||||
/* is detected, this function returns a TX_TRUE. */
|
||||
/* */
|
||||
/* INPUT */
|
||||
/* */
|
||||
/* thread_ptr Pointer to thread to resume */
|
||||
/* */
|
||||
/* OUTPUT */
|
||||
/* */
|
||||
/* None */
|
||||
/* */
|
||||
/* CALLS */
|
||||
/* */
|
||||
/* _tx_thread_smp_available_cores_get Get available cores bitmap */
|
||||
/* _tx_thread_smp_core_preempt Preempt core for new thread */
|
||||
/* _tx_thread_smp_core_wakeup Wakeup other core */
|
||||
/* _tx_thread_smp_execute_list_clear Clear the thread execute list */
|
||||
/* _tx_thread_smp_execute_list_setup Setup the thread execute list */
|
||||
/* _tx_thread_smp_core_interrupt Interrupt other core */
|
||||
/* _tx_thread_smp_lowest_priority_get Get lowest priority scheduled */
|
||||
/* thread */
|
||||
/* _tx_thread_smp_next_priority_find Find next priority with one */
|
||||
/* or more ready threads */
|
||||
/* _tx_thread_smp_possible_cores_get Get possible cores bitmap */
|
||||
/* _tx_thread_smp_preemptable_threads_get */
|
||||
/* Get list of thread preemption */
|
||||
/* possibilities */
|
||||
/* [_tx_thread_smp_protect] Get protection */
|
||||
/* _tx_thread_smp_rebalance_execute_list Rebalance the execution list */
|
||||
/* _tx_thread_smp_remap_solution_find Attempt to remap threads to */
|
||||
/* schedule another thread */
|
||||
/* _tx_thread_smp_schedule_list_clear Clear the thread schedule list*/
|
||||
/* _tx_thread_smp_schedule_list_setup Inherit schedule list from */
|
||||
/* execute list */
|
||||
/* _tx_thread_system_return Return to the system */
|
||||
/* */
|
||||
/* CALLED BY */
|
||||
/* */
|
||||
/* _tx_thread_create Thread create function */
|
||||
/* _tx_thread_priority_change Thread priority change */
|
||||
/* _tx_thread_resume Application resume service */
|
||||
/* _tx_thread_timeout Thread timeout */
|
||||
/* _tx_thread_wait_abort Thread wait abort */
|
||||
/* Other ThreadX Components */
|
||||
/* */
|
||||
/* RELEASE HISTORY */
|
||||
/* */
|
||||
/* DATE NAME DESCRIPTION */
|
||||
/* */
|
||||
/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
|
||||
/* */
|
||||
/**************************************************************************/
|
||||
VOID _tx_thread_system_resume(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
TX_INTERRUPT_SAVE_AREA
|
||||
|
||||
#endif
|
||||
|
||||
UINT priority;
|
||||
ULONG priority_bit;
|
||||
TX_THREAD *head_ptr;
|
||||
TX_THREAD *tail_ptr;
|
||||
UINT core_index;
|
||||
#ifndef TX_THREAD_SMP_EQUAL_PRIORITY
|
||||
UINT j;
|
||||
UINT lowest_priority;
|
||||
TX_THREAD *next_thread;
|
||||
ULONG test_cores;
|
||||
UINT core;
|
||||
UINT thread_mapped;
|
||||
TX_THREAD *preempt_thread;
|
||||
ULONG possible_cores;
|
||||
ULONG thread_possible_cores;
|
||||
ULONG available_cores;
|
||||
ULONG test_possible_cores;
|
||||
TX_THREAD *possible_preemption_list[TX_THREAD_SMP_MAX_CORES];
|
||||
#endif
|
||||
TX_THREAD *execute_thread;
|
||||
UINT i;
|
||||
UINT loop_finished;
|
||||
UINT processing_complete;
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
TX_TRACE_BUFFER_ENTRY *entry_ptr;
|
||||
ULONG time_stamp = ((ULONG) 0);
|
||||
#endif
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
UINT map_index;
|
||||
#endif
|
||||
|
||||
#ifndef TX_NO_TIMER
|
||||
TX_TIMER_INTERNAL *timer_ptr;
|
||||
TX_TIMER_INTERNAL **list_head;
|
||||
TX_TIMER_INTERNAL *next_timer;
|
||||
TX_TIMER_INTERNAL *previous_timer;
|
||||
#endif
|
||||
|
||||
|
||||
/* Set the processing complete flag to false. */
|
||||
processing_complete = TX_FALSE;
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Lockout interrupts while the thread is being resumed. */
|
||||
TX_DISABLE
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef TX_NO_TIMER
|
||||
|
||||
/* Deactivate the timeout timer if necessary. */
|
||||
if ((thread_ptr -> tx_thread_timer.tx_timer_internal_list_head) != TX_NULL)
|
||||
{
|
||||
|
||||
/* Deactivate the thread's timeout timer. This is now done in-line
|
||||
for ThreadX SMP so the additional protection logic can be avoided. */
|
||||
|
||||
/* Deactivate the timer. */
|
||||
|
||||
/* Pickup internal timer pointer. */
|
||||
timer_ptr = &(thread_ptr -> tx_thread_timer);
|
||||
|
||||
/* Pickup the list head pointer. */
|
||||
list_head = timer_ptr -> tx_timer_internal_list_head;
|
||||
|
||||
/* Pickup the next active timer. */
|
||||
next_timer = timer_ptr -> tx_timer_internal_active_next;
|
||||
|
||||
/* See if this is the only timer in the list. */
|
||||
if (timer_ptr == next_timer)
|
||||
{
|
||||
|
||||
/* Yes, the only timer on the list. */
|
||||
|
||||
/* Determine if the head pointer needs to be updated. */
|
||||
if (*(list_head) == timer_ptr)
|
||||
{
|
||||
|
||||
/* Update the head pointer. */
|
||||
*(list_head) = TX_NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* At least one more timer is on the same expiration list. */
|
||||
|
||||
/* Update the links of the adjacent timers. */
|
||||
previous_timer = timer_ptr -> tx_timer_internal_active_previous;
|
||||
next_timer -> tx_timer_internal_active_previous = previous_timer;
|
||||
previous_timer -> tx_timer_internal_active_next = next_timer;
|
||||
|
||||
/* Determine if the head pointer needs to be updated. */
|
||||
if (*(list_head) == timer_ptr)
|
||||
{
|
||||
|
||||
/* Update the next timer in the list with the list head pointer. */
|
||||
next_timer -> tx_timer_internal_list_head = list_head;
|
||||
|
||||
/* Update the head pointer. */
|
||||
*(list_head) = next_timer;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the timer's list head pointer. */
|
||||
timer_ptr -> tx_timer_internal_list_head = TX_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Clear the remaining time to ensure timer doesn't get activated. */
|
||||
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Check this thread's stack. */
|
||||
TX_THREAD_STACK_CHECK(thread_ptr)
|
||||
#endif
|
||||
|
||||
|
||||
/* Pickup index. */
|
||||
core_index = TX_SMP_CORE_ID;
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* If trace is enabled, save the current event pointer. */
|
||||
entry_ptr = _tx_trace_buffer_current_ptr;
|
||||
#endif
|
||||
|
||||
/* Log the thread status change. */
|
||||
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&time_stamp), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr[core_index]), TX_TRACE_INTERNAL_EVENTS)
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(4, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* Save the time stamp for later comparison to verify that
|
||||
the event hasn't been overwritten by the time we have
|
||||
computed the next thread to execute. */
|
||||
if (entry_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Save time stamp. */
|
||||
time_stamp = entry_ptr -> tx_trace_buffer_entry_time_stamp;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Determine if the thread is in the process of suspending. If so, the thread
|
||||
control block is already on the linked list so nothing needs to be done. */
|
||||
if (thread_ptr -> tx_thread_suspending == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Make sure the type of suspension under way is not a terminate or
|
||||
thread completion. In either of these cases, do not void the
|
||||
interrupted suspension processing. */
|
||||
if (thread_ptr -> tx_thread_state != TX_COMPLETED)
|
||||
{
|
||||
|
||||
/* Make sure the thread isn't terminated. */
|
||||
if (thread_ptr -> tx_thread_state != TX_TERMINATED)
|
||||
{
|
||||
|
||||
/* No, now check to see if the delayed suspension flag is set. */
|
||||
if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Clear the suspending flag. */
|
||||
thread_ptr -> tx_thread_suspending = TX_FALSE;
|
||||
|
||||
/* Restore the state to ready. */
|
||||
thread_ptr -> tx_thread_state = TX_READY;
|
||||
|
||||
/* Thread state change. */
|
||||
TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY)
|
||||
|
||||
/* Log the thread status change. */
|
||||
TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Clear the delayed suspend flag and change the state. */
|
||||
thread_ptr -> tx_thread_delayed_suspend = TX_FALSE;
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
}
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total number of thread resumptions. */
|
||||
_tx_thread_performance_resume_count++;
|
||||
|
||||
/* Increment this thread's resume count. */
|
||||
thread_ptr -> tx_thread_performance_resume_count++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Check to make sure the thread has not already been resumed. */
|
||||
if (thread_ptr -> tx_thread_state != TX_READY)
|
||||
{
|
||||
|
||||
/* Check for a delayed suspend flag. */
|
||||
if (thread_ptr -> tx_thread_delayed_suspend == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Clear the delayed suspend flag and change the state. */
|
||||
thread_ptr -> tx_thread_delayed_suspend = TX_FALSE;
|
||||
thread_ptr -> tx_thread_state = TX_SUSPENDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Thread state change. */
|
||||
TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY)
|
||||
|
||||
/* Log the thread status change. */
|
||||
TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY)
|
||||
|
||||
/* Make this thread ready. */
|
||||
|
||||
/* Change the state to ready. */
|
||||
thread_ptr -> tx_thread_state = TX_READY;
|
||||
|
||||
/* Pickup priority of thread. */
|
||||
priority = thread_ptr -> tx_thread_priority;
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* Increment the total number of thread resumptions. */
|
||||
_tx_thread_performance_resume_count++;
|
||||
|
||||
/* Increment this thread's resume count. */
|
||||
thread_ptr -> tx_thread_performance_resume_count++;
|
||||
#endif
|
||||
|
||||
/* Determine if there are other threads at this priority that are
|
||||
ready. */
|
||||
head_ptr = _tx_thread_priority_list[priority];
|
||||
if (head_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, there are other threads at this priority already ready. */
|
||||
|
||||
/* Just add this thread to the priority list. */
|
||||
tail_ptr = head_ptr -> tx_thread_ready_previous;
|
||||
tail_ptr -> tx_thread_ready_next = thread_ptr;
|
||||
head_ptr -> tx_thread_ready_previous = thread_ptr;
|
||||
thread_ptr -> tx_thread_ready_previous = tail_ptr;
|
||||
thread_ptr -> tx_thread_ready_next = head_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* First thread at this priority ready. Add to the front of the list. */
|
||||
_tx_thread_priority_list[priority] = thread_ptr;
|
||||
thread_ptr -> tx_thread_ready_next = thread_ptr;
|
||||
thread_ptr -> tx_thread_ready_previous = thread_ptr;
|
||||
|
||||
#if TX_MAX_PRIORITIES > 32
|
||||
|
||||
/* Calculate the index into the bit map array. */
|
||||
map_index = priority/((UINT) 32);
|
||||
|
||||
/* Set the active bit to remember that the priority map has something set. */
|
||||
TX_DIV32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_priority_map_active = _tx_thread_priority_map_active | priority_bit;
|
||||
#endif
|
||||
|
||||
/* Or in the thread's priority bit. */
|
||||
TX_MOD32_BIT_SET(priority, priority_bit)
|
||||
_tx_thread_priority_maps[MAP_INDEX] = _tx_thread_priority_maps[MAP_INDEX] | priority_bit;
|
||||
}
|
||||
|
||||
/* Determine if a thread with preemption-threshold is currently scheduled. */
|
||||
if (_tx_thread_preemption__threshold_scheduled != TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, there has been a thread with preemption-threshold scheduled. */
|
||||
|
||||
/* Determine if this thread can run with the current preemption-threshold. */
|
||||
if (priority >= _tx_thread_preemption__threshold_scheduled -> tx_thread_preempt_threshold)
|
||||
{
|
||||
|
||||
/* The thread cannot run because of the current preemption-threshold. Simply
|
||||
return at this point. */
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Decrement the preemption disable flag. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#endif
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(5, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Processing is complete, set the complete flag. */
|
||||
processing_complete = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is the processing complete at this point? */
|
||||
if (processing_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Determine if this newly ready thread has preemption-threshold set. If so, determine
|
||||
if any other threads would need to be unscheduled for this thread to execute. */
|
||||
if (thread_ptr -> tx_thread_preempt_threshold < priority)
|
||||
{
|
||||
|
||||
/* Is there a place in the execution list for the newly ready thread? */
|
||||
i = ((UINT) 0);
|
||||
loop_finished = TX_FALSE;
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
while(i < ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
#else
|
||||
while(i < _tx_thread_smp_max_cores)
|
||||
#endif
|
||||
{
|
||||
|
||||
/* Pickup the current execute thread for this core. */
|
||||
execute_thread = _tx_thread_execute_ptr[i];
|
||||
|
||||
/* Is there a thread mapped to this core? */
|
||||
if (execute_thread == TX_NULL)
|
||||
{
|
||||
|
||||
/* Get out of the loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if this thread should preempt the thread in the execution list. */
|
||||
if (priority < execute_thread -> tx_thread_preempt_threshold)
|
||||
{
|
||||
|
||||
/* Get out of the loop. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if we need to get out of the loop. */
|
||||
if (loop_finished == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Get out of the loop. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Move to next index. */
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Determine if there is a reason to rebalance the list. */
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
if (i < ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
#else
|
||||
if (i < _tx_thread_smp_max_cores)
|
||||
#endif
|
||||
{
|
||||
|
||||
/* Yes, the new thread has preemption-threshold set and there is a slot in the
|
||||
execution list for it. */
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
}
|
||||
}
|
||||
#ifdef TX_THREAD_SMP_EQUAL_PRIORITY
|
||||
else
|
||||
{
|
||||
|
||||
/* For equal priority SMP, we simply use the rebalance list function. */
|
||||
|
||||
/* Call the rebalance routine. This routine maps cores and ready threads. */
|
||||
_tx_thread_smp_rebalance_execute_list(core_index);
|
||||
}
|
||||
#else
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if this thread has any available cores to execute on. */
|
||||
if (thread_ptr -> tx_thread_smp_cores_allowed != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* At this point we know that the newly ready thread does not have preemption-threshold set and that
|
||||
any existing preemption-threshold is not blocking this thread from executing. */
|
||||
|
||||
/* Pickup the core this thread was previously executing on. */
|
||||
i = thread_ptr -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Pickup the currently executing thread for the previously mapped core. */
|
||||
execute_thread = _tx_thread_execute_ptr[i];
|
||||
|
||||
/* First, let's see if the last core this thread executed on is available. */
|
||||
if (execute_thread == TX_NULL)
|
||||
{
|
||||
|
||||
/* Yes, simply place this thread into the execute list at the same location. */
|
||||
_tx_thread_execute_ptr[i] = thread_ptr;
|
||||
|
||||
/* If necessary, interrupt the core with the new thread to schedule. */
|
||||
_tx_thread_smp_core_interrupt(thread_ptr, core_index, i);
|
||||
|
||||
/* If necessary, wakeup the target core. */
|
||||
_tx_thread_smp_core_wakeup(core_index, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* This core is not able to execute on the core it last executed on
|
||||
because another thread is already scheduled on that core. */
|
||||
|
||||
/* Pickup the available cores for the newly ready thread. */
|
||||
available_cores = thread_ptr -> tx_thread_smp_cores_allowed;
|
||||
|
||||
/* Isolate the lowest set bit so we can determine if more than one core is
|
||||
available. */
|
||||
available_cores = available_cores & ((~available_cores) + ((ULONG) 1));
|
||||
|
||||
/* Determine if either this thread or the currently schedule thread can
|
||||
run on more than one core or on a different core and preemption is not
|
||||
possible. */
|
||||
if ((available_cores == thread_ptr -> tx_thread_smp_cores_allowed) &&
|
||||
(available_cores == execute_thread -> tx_thread_smp_cores_allowed))
|
||||
{
|
||||
|
||||
/* Both this thread and the execute thread can only execute on the same core,
|
||||
so this thread can only be scheduled if its priority is less. Otherwise,
|
||||
there is nothing else to examine. */
|
||||
if (thread_ptr -> tx_thread_priority < execute_thread -> tx_thread_priority)
|
||||
{
|
||||
|
||||
/* We know that we have to preempt the executing thread. */
|
||||
|
||||
/* Preempt the executing thread. */
|
||||
_tx_thread_execute_ptr[i] = thread_ptr;
|
||||
|
||||
/* If necessary, interrupt the core with the new thread to schedule. */
|
||||
_tx_thread_smp_core_interrupt(thread_ptr, core_index, i);
|
||||
|
||||
/* If necessary, wakeup the core. */
|
||||
_tx_thread_smp_core_wakeup(core_index, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine if there are any available cores to execute on. */
|
||||
available_cores = _tx_thread_smp_available_cores_get();
|
||||
|
||||
/* Determine what the possible cores are for this thread. */
|
||||
thread_possible_cores = thread_ptr -> tx_thread_smp_cores_allowed;
|
||||
|
||||
/* Set the thread mapped flag to false. */
|
||||
thread_mapped = TX_FALSE;
|
||||
|
||||
/* Determine if there are available cores. */
|
||||
if (available_cores != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Determine if one of the available cores is allowed for this thread. */
|
||||
if ((available_cores & thread_possible_cores) != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Calculate the lowest set bit of allowed cores. */
|
||||
test_cores = (thread_possible_cores & available_cores);
|
||||
TX_LOWEST_SET_BIT_CALCULATE(test_cores, i)
|
||||
|
||||
/* Remember this index in the thread control block. */
|
||||
thread_ptr -> tx_thread_smp_core_mapped = i;
|
||||
|
||||
/* Map this thread to the free slot. */
|
||||
_tx_thread_execute_ptr[i] = thread_ptr;
|
||||
|
||||
/* Indicate this thread was mapped. */
|
||||
thread_mapped = TX_TRUE;
|
||||
|
||||
/* If necessary, wakeup the target core. */
|
||||
_tx_thread_smp_core_wakeup(core_index, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* There are available cores, however, they are all excluded. */
|
||||
|
||||
/* Calculate the possible cores from the cores currently scheduled. */
|
||||
possible_cores = _tx_thread_smp_possible_cores_get();
|
||||
|
||||
/* Determine if it is worthwhile to try to remap the execution list. */
|
||||
if ((available_cores & possible_cores) != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Yes, some of the currently scheduled threads can be moved. */
|
||||
|
||||
/* Now determine if there could be a remap solution that will allow us to schedule this thread. */
|
||||
|
||||
/* Narrow to the current possible cores. */
|
||||
thread_possible_cores = thread_possible_cores & possible_cores;
|
||||
|
||||
/* Now we need to see if one of the other threads in the non-excluded cores can be moved to make room
|
||||
for this thread. */
|
||||
|
||||
/* Default the schedule list to the current execution list. */
|
||||
_tx_thread_smp_schedule_list_setup();
|
||||
|
||||
/* Determine the possible core mapping. */
|
||||
test_possible_cores = possible_cores & ~(thread_possible_cores);
|
||||
|
||||
/* Attempt to remap the cores in order to schedule this thread. */
|
||||
core = _tx_thread_smp_remap_solution_find(thread_ptr, available_cores, thread_possible_cores, test_possible_cores);
|
||||
|
||||
/* Determine if remapping was successful. */
|
||||
if (core != ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
{
|
||||
|
||||
/* Clear the execute list. */
|
||||
_tx_thread_smp_execute_list_clear();
|
||||
|
||||
/* Setup the execute list based on the updated schedule list. */
|
||||
_tx_thread_smp_execute_list_setup(core_index);
|
||||
|
||||
/* Indicate this thread was mapped. */
|
||||
thread_mapped = TX_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if we need to investigate thread preemption. */
|
||||
if (thread_mapped == TX_FALSE)
|
||||
{
|
||||
|
||||
/* At this point, we need to first check for thread preemption possibilities. */
|
||||
lowest_priority = _tx_thread_smp_lowest_priority_get();
|
||||
|
||||
/* Does this thread have a higher priority? */
|
||||
if (thread_ptr -> tx_thread_priority < lowest_priority)
|
||||
{
|
||||
|
||||
/* Yes, preemption is possible. */
|
||||
|
||||
/* Pickup the thread to preempt. */
|
||||
preempt_thread = _tx_thread_priority_list[lowest_priority];
|
||||
|
||||
/* Determine if there are more than one thread ready at this priority level. */
|
||||
if (preempt_thread -> tx_thread_ready_next != preempt_thread)
|
||||
{
|
||||
|
||||
/* Remember the list head. */
|
||||
head_ptr = preempt_thread;
|
||||
|
||||
/* Setup thread search pointer to the start of the list. */
|
||||
next_thread = preempt_thread -> tx_thread_ready_next;
|
||||
|
||||
/* Loop to find the last thread scheduled at this priority. */
|
||||
i = ((UINT) 0);
|
||||
#ifndef TX_THREAD_SMP_DYNAMIC_CORE_MAX
|
||||
while (i < ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
#else
|
||||
|
||||
while (i < _tx_thread_smp_max_cores)
|
||||
#endif
|
||||
{
|
||||
|
||||
/* Is this thread currently scheduled? */
|
||||
if (next_thread == _tx_thread_execute_ptr[next_thread -> tx_thread_smp_core_mapped])
|
||||
{
|
||||
|
||||
/* Yes, this is the new preempt thread. */
|
||||
preempt_thread = next_thread;
|
||||
|
||||
/* Increment core count. */
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Move to the next thread. */
|
||||
next_thread = next_thread -> tx_thread_ready_next;
|
||||
|
||||
/* Are we at the head of the list? */
|
||||
if (next_thread == head_ptr)
|
||||
{
|
||||
|
||||
/* End the loop. */
|
||||
i = ((UINT) TX_THREAD_SMP_MAX_CORES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the core that this thread is scheduled on. */
|
||||
possible_cores = (((ULONG) 1) << preempt_thread -> tx_thread_smp_core_mapped);
|
||||
|
||||
/* Determine if preemption is possible. */
|
||||
if ((thread_possible_cores & possible_cores) != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Pickup the newly available core. */
|
||||
i = preempt_thread -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Remember this index in the thread control block. */
|
||||
thread_ptr -> tx_thread_smp_core_mapped = i;
|
||||
|
||||
/* Map this thread to the free slot. */
|
||||
_tx_thread_execute_ptr[i] = thread_ptr;
|
||||
|
||||
/* If necessary, interrupt the core with the new thread to schedule. */
|
||||
_tx_thread_smp_core_interrupt(thread_ptr, core_index, i);
|
||||
|
||||
/* If necessary, wakeup the target core. */
|
||||
_tx_thread_smp_core_wakeup(core_index, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Build the list of possible thread preemptions, ordered lowest priority first. */
|
||||
possible_cores = _tx_thread_smp_preemptable_threads_get(thread_ptr -> tx_thread_priority, possible_preemption_list);
|
||||
|
||||
/* Determine if preemption is possible. */
|
||||
|
||||
/* Loop through the potential threads can can be preempted. */
|
||||
i = ((UINT) 0);
|
||||
loop_finished = TX_FALSE;
|
||||
while (possible_preemption_list[i] != TX_NULL)
|
||||
{
|
||||
|
||||
/* Pickup the thread to preempt. */
|
||||
preempt_thread = possible_preemption_list[i];
|
||||
|
||||
/* Pickup the core this thread is mapped to. */
|
||||
j = preempt_thread -> tx_thread_smp_core_mapped;
|
||||
|
||||
/* Calculate the core that this thread is scheduled on. */
|
||||
available_cores = (((ULONG) 1) << j);
|
||||
|
||||
/* Can this thread execute on this core? */
|
||||
if ((thread_possible_cores & available_cores) != ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Remember this index in the thread control block. */
|
||||
thread_ptr -> tx_thread_smp_core_mapped = j;
|
||||
|
||||
/* Map this thread to the free slot. */
|
||||
_tx_thread_execute_ptr[j] = thread_ptr;
|
||||
|
||||
/* If necessary, interrupt the core with the new thread to schedule. */
|
||||
_tx_thread_smp_core_interrupt(thread_ptr, core_index, j);
|
||||
|
||||
/* If necessary, wakeup the target core. */
|
||||
_tx_thread_smp_core_wakeup(core_index, j);
|
||||
|
||||
/* Finished with the preemption condition. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* No, the thread to preempt is not running on a core available to the new thread.
|
||||
Attempt to find a remapping solution. */
|
||||
|
||||
/* Narrow to the current possible cores. */
|
||||
thread_possible_cores = thread_possible_cores & possible_cores;
|
||||
|
||||
/* Now we need to see if one of the other threads in the non-excluded cores can be moved to make room
|
||||
for this thread. */
|
||||
|
||||
/* Temporarily set the execute thread to NULL. */
|
||||
_tx_thread_execute_ptr[j] = TX_NULL;
|
||||
|
||||
/* Default the schedule list to the current execution list. */
|
||||
_tx_thread_smp_schedule_list_setup();
|
||||
|
||||
/* Determine the possible core mapping. */
|
||||
test_possible_cores = possible_cores & ~(thread_possible_cores);
|
||||
|
||||
/* Attempt to remap the cores in order to schedule this thread. */
|
||||
core = _tx_thread_smp_remap_solution_find(thread_ptr, available_cores, thread_possible_cores, test_possible_cores);
|
||||
|
||||
/* Determine if remapping was successful. */
|
||||
if (core != ((UINT) TX_THREAD_SMP_MAX_CORES))
|
||||
{
|
||||
|
||||
/* Clear the execute list. */
|
||||
_tx_thread_smp_execute_list_clear();
|
||||
|
||||
/* Setup the execute list based on the updated schedule list. */
|
||||
_tx_thread_smp_execute_list_setup(core_index);
|
||||
|
||||
/* Finished with the preemption condition. */
|
||||
loop_finished = TX_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Restore the preempted thread and examine the next thread. */
|
||||
_tx_thread_execute_ptr[j] = preempt_thread;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if we should get out of the loop. */
|
||||
if (loop_finished == TX_TRUE)
|
||||
{
|
||||
|
||||
/* Yes, get out of the loop. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Move to the next possible thread preemption. */
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine if there is more processing. */
|
||||
if (processing_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
|
||||
|
||||
/* Debug entry. */
|
||||
_tx_thread_smp_debug_entry_insert(5, 0, thread_ptr);
|
||||
#endif
|
||||
|
||||
#ifdef TX_ENABLE_EVENT_TRACE
|
||||
|
||||
/* Check that the event time stamp is unchanged. A different
|
||||
timestamp means that a later event wrote over the thread
|
||||
resume event. In that case, do nothing here. */
|
||||
if ((entry_ptr != TX_NULL) && (time_stamp == entry_ptr -> tx_trace_buffer_entry_time_stamp))
|
||||
{
|
||||
|
||||
/* Timestamp is the same, set the "next thread pointer" to NULL. This can
|
||||
be used by the trace analysis tool to show idle system conditions. */
|
||||
#ifdef TX_MISRA_ENABLE
|
||||
entry_ptr -> tx_trace_buffer_entry_info_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr[core_index]);
|
||||
#else
|
||||
entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr[core_index]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Decrement the preemption disable flag. */
|
||||
_tx_thread_preempt_disable--;
|
||||
#endif
|
||||
|
||||
if (_tx_thread_current_ptr[core_index] != _tx_thread_execute_ptr[core_index])
|
||||
{
|
||||
|
||||
#ifdef TX_ENABLE_STACK_CHECKING
|
||||
|
||||
/* Pickup the next thread to execute. */
|
||||
thread_ptr = _tx_thread_execute_ptr[core_index];
|
||||
|
||||
/* Determine if there is a thread pointer. */
|
||||
if (thread_ptr != TX_NULL)
|
||||
{
|
||||
|
||||
/* Check this thread's stack. */
|
||||
TX_THREAD_STACK_CHECK(thread_ptr)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now determine if preemption should take place. This is only possible if the current thread pointer is
|
||||
not the same as the execute thread pointer AND the system state and preempt disable flags are clear. */
|
||||
if (_tx_thread_system_state[core_index] == ((ULONG) 0))
|
||||
{
|
||||
|
||||
/* Is the preempt disable flag set? */
|
||||
if (_tx_thread_preempt_disable == ((UINT) 0))
|
||||
{
|
||||
|
||||
|
||||
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
|
||||
|
||||
/* No, there is another thread ready to run and will be scheduled upon return. */
|
||||
_tx_thread_performance_non_idle_return_count++;
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Increment the preempt disable flag in order to keep the protection. */
|
||||
_tx_thread_preempt_disable++;
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
#endif
|
||||
|
||||
/* Preemption is needed - return to the system! */
|
||||
_tx_thread_system_return();
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Setup protection again since caller is expecting that it is still in force. */
|
||||
_tx_thread_smp_protect();
|
||||
#endif
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Set the processing complete flag. */
|
||||
processing_complete = TX_TRUE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TX_NOT_INTERRUPTABLE
|
||||
|
||||
/* Determine if processing is complete. If so, no need to restore interrupts. */
|
||||
if (processing_complete == TX_FALSE)
|
||||
{
|
||||
|
||||
/* Restore interrupts. */
|
||||
TX_RESTORE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TX_NOT_INTERRUPTABLE
|
||||
VOID _tx_thread_system_ni_resume(TX_THREAD *thread_ptr)
|
||||
{
|
||||
|
||||
/* Call system resume. */
|
||||
_tx_thread_system_resume(thread_ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
1013
common_smp/src/tx_thread_system_suspend.c
Normal file
1013
common_smp/src/tx_thread_system_suspend.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user