开启 ThreadX
All checks were successful
Build and Upload Artifact / build and upload-artifact (push) Successful in 25m8s

This commit is contained in:
chauyin
2025-05-07 22:53:45 +08:00
parent 7f9bede0c7
commit 559760be0c
194 changed files with 42018 additions and 91 deletions

View File

@@ -0,0 +1,374 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,209 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,148 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,133 @@
/**************************************************************************/
/* */
/* 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
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_block pool_initialize PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* opt out of function when */
/* TX_INLINE_INITIALIZATION is */
/* defined, */
/* resulting in version 6.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
}
#endif

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,411 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,214 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,199 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,148 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,151 @@
/**************************************************************************/
/* */
/* 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
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_byte_pool_initialize PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* opt out of function when */
/* TX_INLINE_INITIALIZATION is */
/* defined, */
/* resulting in version 6.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
}
#endif

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,354 @@
/**************************************************************************/
/* */
/* 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 C */
/* 6.1.7 */
/* 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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 06-02-2021 Scott Larson Improve possible free bytes */
/* calculation, */
/* resulting in version 6.1.7 */
/* */
/**************************************************************************/
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;
ULONG total_theoretical_available;
/* Disable interrupts. */
TX_DISABLE
/* First, determine if there are enough bytes in the pool. */
/* Theoretical bytes available = free bytes + ((fragments-2) * overhead of each block) */
total_theoretical_available = pool_ptr -> tx_byte_pool_available + ((pool_ptr -> tx_byte_pool_fragments - 2) * ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE))));
if (memory_size >= total_theoretical_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--;
}
/* Restore interrupts temporarily. */
TX_RESTORE
/* Disable interrupts. */
TX_DISABLE
/* 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);
}

View 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 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,239 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View 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_create PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,209 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,407 @@
/**************************************************************************/
/* */
/* 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.2.0 */
/* 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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 04-25-2022 Scott Larson Modified comment(s), */
/* handle 0 flags case, */
/* resulting in version 6.1.11 */
/* 10-31-2022 Scott Larson Modified comment(s), always */
/* return actual flags, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
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;
/* Return the actual event flags and apply delayed clearing. */
*actual_flags_ptr = current_flags & ~group_ptr -> tx_event_flags_group_delayed_clear;
/* 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))
{
/* 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. */
/* 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
{
/* flags_satisfied is 0. */
/* Determine if the request specifies suspension. */
if (wait_option != TX_NO_WAIT)
{
/* Determine if the preempt disable flag is non-zero OR the requested events is 0. */
if ((_tx_thread_preempt_disable != ((UINT) 0)) || (requested_flags == (UINT) 0))
{
/* Suspension is not allowed if the preempt disable flag is non-zero at this point,
or if requested_flags is 0, 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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,134 @@
/**************************************************************************/
/* */
/* 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
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_event_flags_initialize PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* opt out of function when */
/* TX_INLINE_INITIALIZATION is */
/* defined, */
/* resulting in version 6.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
}
#endif

View File

@@ -0,0 +1,625 @@
/**************************************************************************/
/* */
/* 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.1.11 */
/* 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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 04-25-2022 William E. Lamie Modified comment(s), and */
/* added corrected preemption */
/* check logic, resulting in */
/* version 6.1.11 */
/* */
/**************************************************************************/
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. */
/* 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++;
/* Since we have temporarily disabled preemption globally, set the preempt
check flag to check for any preemption condition - including from
unrelated ISR processing. */
preempt_check = TX_TRUE;
/* 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. */
/* 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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,152 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View 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 */
/** */
/** Initialize */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_initialize.h"
#include "tx_thread.h"
#include "tx_timer.h"
#if defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)
extern VOID _tx_execution_initialize(VOID);
#endif
/* 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 C */
/* 6.3.0 */
/* 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_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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 04-25-2022 Scott Larson Modified comment(s), */
/* added EPK initialization, */
/* resulting in version 6.1.11 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added random generator */
/* initialization, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
VOID _tx_initialize_kernel_enter(VOID)
{
/* Determine if the compiler has pre-initialized ThreadX. */
if (_tx_thread_system_state != 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_system_state = 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();
/* 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 = TX_INITIALIZE_IN_PROGRESS;
/* Optional random number generator initialization. */
TX_INITIALIZE_RANDOM_GENERATOR_INITIALIZATION
/* Call the application provided initialization function. Pass the
first available memory address to it. */
tx_application_define(_tx_initialize_unused_memory);
/* Set the system state in preparation for entering the thread
scheduler. */
_tx_thread_system_state = TX_INITIALIZE_IS_FINISHED;
/* Call any port specific pre-scheduler processing. */
TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION
#if defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)
/* Initialize Execution Profile Kit. */
_tx_execution_initialize();
#endif
/* 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
}

View File

@@ -0,0 +1,102 @@
/**************************************************************************/
/* */
/* 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_initialize.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_initialize_kernel_setup PORTABLE C */
/* 6.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_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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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_system_state = 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();
/* 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 = TX_INITIALIZE_ALMOST_DONE;
}

View File

@@ -0,0 +1,317 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,148 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,245 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,411 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,149 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_mutex_initialize PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* opt out of function when */
/* TX_INLINE_INITIALIZATION is */
/* defined, */
/* resulting in version 6.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
}
#endif

View File

@@ -0,0 +1,267 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,339 @@
/**************************************************************************/
/* */
/* 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_priority_change PORTABLE C */
/* 6.1.6 */
/* 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 */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* change thread state from */
/* TX_SUSPENDED to */
/* TX_PRIORITY_CHANGE before */
/* calling */
/* _tx_thread_system_suspend, */
/* resulting in version 6.1 */
/* 04-02-2021 Scott Larson Modified comments, fixed */
/* mapping current thread's */
/* priority rather than next, */
/* resulting in version 6.1.6 */
/* */
/**************************************************************************/
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;
TX_THREAD *next_execute_ptr;
UINT original_priority;
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
ULONG priority_bit;
#if TX_MAX_PRIORITIES > 32
UINT map_index;
#endif
#endif
#ifndef TX_NOT_INTERRUPTABLE
/* Lockout interrupts while the thread is being suspended. */
TX_DISABLE
#endif
/* 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;
}
#ifndef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
}
else
{
/* Pickup the next thread to execute. */
execute_ptr = _tx_thread_execute_ptr;
/* Save the original priority. */
original_priority = thread_ptr -> tx_thread_priority;
#ifdef TX_NOT_INTERRUPTABLE
/* Increment the preempt disable flag. */
_tx_thread_preempt_disable++;
/* Set the state to priority change. */
thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
/* 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. */
/* 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 priority change. */
thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
/* 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);
/* Disable interrupts. */
TX_DISABLE
/* At this point, the preempt disable flag is still set, so we still have
protection against all preemption. */
/* 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
/* Pickup the next thread to execute. */
next_execute_ptr = _tx_thread_execute_ptr;
/* Determine if this thread is not the next thread to execute. */
if (thread_ptr != next_execute_ptr)
{
/* Make sure the thread is still ready. */
if (thread_ptr -> tx_thread_state == TX_READY)
{
/* Now check and see if this thread has an equal or higher priority. */
if (thread_ptr -> tx_thread_priority <= next_execute_ptr -> tx_thread_priority)
{
/* Now determine if this thread was the previously executing thread. */
if (thread_ptr == execute_ptr)
{
/* Yes, this thread was previously executing before we temporarily suspended and resumed
it in order to change the priority. A lower or same priority thread cannot be the next thread
to execute in this case since this thread really didn't suspend. Simply reset the execute
pointer to this thread. */
_tx_thread_execute_ptr = thread_ptr;
/* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
if (original_priority < new_priority)
{
/* 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
{
/* Now determine if this thread's preemption-threshold needs to be enforced. */
if (thread_ptr -> tx_thread_preempt_threshold < thread_ptr -> tx_thread_priority)
{
/* Yes, preemption-threshold is in force for this thread. */
/* Compare the next thread to execute thread's priority against the thread's preemption-threshold. */
if (thread_ptr -> tx_thread_preempt_threshold <= next_execute_ptr -> tx_thread_priority)
{
/* We must swap execute pointers to enforce the preemption-threshold of a thread coming out of
priority inheritance. */
_tx_thread_execute_ptr = thread_ptr;
/* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
if (original_priority < new_priority)
{
/* Ensure that this thread is placed at the front of the priority list. */
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
}
}
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
else
{
/* In this case, we need to mark the preempted map to indicate a thread executed above the
preemption-threshold. */
#if TX_MAX_PRIORITIES > 32
/* Calculate the index into the bit map array. */
map_index = (thread_ptr -> tx_thread_priority)/ ((UINT) 32);
/* Set the active bit to remember that the preempt map has something set. */
TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
#endif
/* Remember that this thread was preempted by a thread above the thread's threshold. */
TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
}
#endif
}
}
}
}
#ifndef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
}
}

View File

@@ -0,0 +1,656 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,227 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,172 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,208 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,423 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_queue_initialize PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* opt out of function when */
/* TX_INLINE_INITIALIZATION is */
/* defined, */
/* resulting in version 6.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
}
#endif

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,488 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,428 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,245 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,217 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,144 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,209 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,234 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,133 @@
/**************************************************************************/
/* */
/* 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
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_semaphore_initialize PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* opt out of function when */
/* TX_INLINE_INITIALIZATION is */
/* defined, */
/* resulting in version 6.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
}
#endif

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,224 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View 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 */
/** */
/** 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,391 @@
/**************************************************************************/
/* */
/* 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_initialize.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_create PORTABLE C */
/* 6.3.0 */
/* 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 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 */
/* (default 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_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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* changed stack calculations */
/* to use ALIGN_TYPE integers, */
/* resulting in version 6.1 */
/* 06-02-2021 William E. Lamie Modified comment(s), and */
/* supported TX_MISRA_ENABLE, */
/* 08-02-2021 Scott Larson Removed unneeded cast, */
/* resulting in version 6.1.8 */
/* 10-31-2023 Xiuwen Cai Modified comment(s), */
/* added option for random */
/* number stack filling, */
/* resulting in version 6.3.0 */
/* */
/**************************************************************************/
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
TX_THREAD *next_thread;
TX_THREAD *previous_thread;
TX_THREAD *saved_thread_ptr;
UINT saved_threshold = ((UINT) 0);
UCHAR *temp_ptr;
#ifdef TX_ENABLE_STACK_CHECKING
ALIGN_TYPE new_stack_start;
ALIGN_TYPE updated_stack_start;
#endif
#ifndef TX_DISABLE_STACK_FILLING
#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING)
/* Initialize the stack fill value to a 8-bit random value. */
thread_ptr -> tx_thread_stack_fill_value = ((ULONG) TX_RAND()) & 0xFFUL;
/* Duplicate the random value in each of the 4 bytes of the stack fill value. */
thread_ptr -> tx_thread_stack_fill_value = thread_ptr -> tx_thread_stack_fill_value |
(thread_ptr -> tx_thread_stack_fill_value << 8) |
(thread_ptr -> tx_thread_stack_fill_value << 16) |
(thread_ptr -> tx_thread_stack_fill_value << 24);
#endif
/* 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. */
#ifdef TX_MISRA_ENABLE
new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start);
#else
new_stack_start = TX_POINTER_TO_ALIGN_TYPE_CONVERT(stack_start);
#endif /* TX_MISRA_ENABLE */
updated_stack_start = (((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. */
#ifdef TX_MISRA_ENABLE
stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start);
#else
stack_start = TX_ALIGN_TYPE_TO_POINTER_CONVERT(updated_stack_start);
#endif /* TX_MISRA_ENABLE */
#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);
/* 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
#ifndef TX_NOT_INTERRUPTABLE
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
#endif
/* 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)
{
/* Determine if the create call is being called from initialization. */
if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
{
/* Yes, this create call was made from initialization. */
/* Pickup the current thread execute pointer, which corresponds to the
highest priority thread ready to execute. Interrupt lockout is
not required, since interrupts are assumed to be disabled during
initialization. */
saved_thread_ptr = _tx_thread_execute_ptr;
/* Determine if there is thread ready for execution. */
if (saved_thread_ptr != TX_NULL)
{
/* Yes, a thread is ready for execution when initialization completes. */
/* Save the current preemption-threshold. */
saved_threshold = saved_thread_ptr -> tx_thread_preempt_threshold;
/* For initialization, temporarily set the preemption-threshold to the
priority level to make sure the highest-priority thread runs once
initialization is complete. */
saved_thread_ptr -> tx_thread_preempt_threshold = saved_thread_ptr -> tx_thread_priority;
}
}
else
{
/* Simply set the saved thread pointer to NULL. */
saved_thread_ptr = TX_NULL;
}
#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);
/* Restore previous interrupt posture. */
TX_RESTORE
#else
/* 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);
#endif
/* Determine if the thread's preemption-threshold needs to be restored. */
if (saved_thread_ptr != TX_NULL)
{
/* Yes, restore the previous highest-priority thread's preemption-threshold. This
can only happen if this routine is called from initialization. */
saved_thread_ptr -> tx_thread_preempt_threshold = saved_threshold;
}
}
else
{
#ifdef TX_NOT_INTERRUPTABLE
/* Perform any additional activities for tool or user purpose. */
TX_THREAD_CREATE_EXTENSION(thread_ptr)
/* Restore interrupts. */
TX_RESTORE
#else
/* Restore interrupts. */
TX_RESTORE
/* Perform any additional activities for tool or user purpose. */
TX_THREAD_CREATE_EXTENSION(thread_ptr)
/* Disable interrupts. */
TX_DISABLE
/* Re-enable preemption. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
/* Check for preemption. */
_tx_thread_system_preempt_check();
#endif
}
/* Always return a success. */
return(TX_SUCCESS);
}

View 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
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_delete PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,111 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View 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"
#ifdef TX_ENABLE_EVENT_TRACE
#include "tx_trace.h"
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_identify PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,165 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,456 @@
/**************************************************************************/
/* */
/* 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
#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;
/* 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;
/* 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;
/* 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_INITIALIZE_IN_PROGRESS;
/* 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
#endif
/* Define the variable that holds the highest priority group ready for
execution. It is important to note that this is not necessarily the same
as the priority of the thread pointed to by _tx_execute_thread. */
UINT _tx_thread_highest_priority;
/* 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 TX_NOT_INTERRUPTABLE defined
30 TX_INLINE_THREAD_RESUME_SUSPEND define
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 defined
7 TX_ENABLE_EXECUTION_CHANGE_NOTIFY defined
6-0 Port Specific */
ULONG _tx_build_options;
#if defined(TX_ENABLE_STACK_CHECKING) || defined(TX_PORT_THREAD_STACK_ERROR_HANDLING)
/* 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;
/* Define the last TX_THREAD_EXECUTE_LOG_SIZE threads scheduled in ThreadX. This
is a circular list, where the index points to the oldest entry. */
ULONG _tx_thread_performance__execute_log_index;
TX_THREAD * _tx_thread_performance_execute_log[TX_THREAD_EXECUTE_LOG_SIZE];
#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 C */
/* 6.1.9 */
/* 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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 06-02-2021 Yuxin Zhou Modified comment(s), added */
/* Execution Profile support, */
/* resulting in version 6.1.7 */
/* 10-15-2021 Yuxin Zhou Modified comment(s), improved */
/* stack check error handling, */
/* resulting in version 6.1.9 */
/* */
/**************************************************************************/
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(TX_NULL)
/* Initialize the execute thread pointer to NULL. */
_tx_thread_execute_ptr = TX_NULL;
/* 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)));
#endif
#endif
/* Setup the highest priority variable to the max, indicating no thread is currently
ready. */
_tx_thread_highest_priority = ((UINT) TX_MAX_PRIORITIES);
#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);
/* Initialize the execute thread log. */
TX_MEMSET(&_tx_thread_performance_execute_log[0], 0, (sizeof(_tx_thread_performance_execute_log)));
#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
#if defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)
| (((ULONG) 1) << 7)
#endif
#if TX_PORT_SPECIFIC_BUILD_OPTIONS != 0
| TX_PORT_SPECIFIC_BUILD_OPTIONS
#endif
;
}

View File

@@ -0,0 +1,282 @@
/**************************************************************************/
/* */
/* 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_preemption_change PORTABLE C */
/* 6.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_system_preempt_check Check for preemption */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold)
{
TX_INTERRUPT_SAVE_AREA
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
ULONG priority_bit;
#if TX_MAX_PRIORITIES > 32
UINT map_index;
#endif
#endif
UINT status;
/* Default status to success. */
status = TX_SUCCESS;
#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 (thread_ptr -> tx_thread_user_priority != new_threshold)
{
/* 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
/* 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)
{
/* Return error. */
status = TX_THRESH_ERROR;
}
else
{
#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)
{
/* Determine if this thread is at the head of the list. */
if (_tx_thread_priority_list[thread_ptr -> tx_thread_priority] == thread_ptr)
{
#if TX_MAX_PRIORITIES > 32
/* Calculate the index into the bit map array. */
map_index = (thread_ptr -> tx_thread_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_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_priority, priority_bit)
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active & (~(priority_bit));
}
#endif
}
}
#endif
/* 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;
}
/* Is the thread priority less than the current highest priority? If not, no preemption is required. */
if (_tx_thread_highest_priority < thread_ptr -> tx_thread_priority)
{
/* Is the new thread preemption-threshold less than the current highest priority? If not, no preemption is required. */
if (_tx_thread_highest_priority < new_threshold)
{
/* If the current execute pointer is the same at this thread, preemption needs to take place. */
if (_tx_thread_execute_ptr == thread_ptr)
{
/* Preemption needs to take place. */
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
/* Determine if this thread has preemption threshold set. */
if (thread_ptr -> tx_thread_preempt_threshold != thread_ptr -> tx_thread_priority)
{
#if TX_MAX_PRIORITIES > 32
/* Calculate the index into the bit map array. */
map_index = (thread_ptr -> tx_thread_priority)/((UINT) 32);
/* Set the active bit to remember that the preempt map has something set. */
TX_DIV32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
#endif
/* Remember that this thread was preempted by a thread above the thread's threshold. */
TX_MOD32_BIT_SET(thread_ptr -> tx_thread_priority, priority_bit)
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
}
#endif
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Determine if the caller is an interrupt or from a thread. */
if (TX_THREAD_GET_SYSTEM_STATE() == ((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. */
thread_ptr -> tx_thread_performance_solicited_preemption_count++;
}
/* Remember the thread that preempted this thread. */
thread_ptr -> tx_thread_performance_last_preempting_thread = _tx_thread_priority_list[_tx_thread_highest_priority];
/* Is the execute pointer different? */
if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
{
/* Move to next entry. */
_tx_thread_performance__execute_log_index++;
/* Check for wrap condition. */
if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
{
/* Set the index to the beginning. */
_tx_thread_performance__execute_log_index = ((UINT) 0);
}
/* Log the new execute pointer. */
_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_ptr;
}
#endif
/* Setup the highest priority thread to execute. */
_tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
/* Restore interrupts. */
TX_RESTORE
/* Check for preemption. */
_tx_thread_system_preempt_check();
/* Disable interrupts. */
TX_DISABLE
}
}
}
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return(status);
}

View 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_trace.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_priority_change PORTABLE C */
/* 6.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_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 */
/* _tx_thread_system_preempt_check Check for preemption */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 William E. Lamie Modified comment(s), and */
/* change thread state from */
/* TX_SUSPENDED to */
/* TX_PRIORITY_CHANGE before */
/* calling */
/* _tx_thread_system_suspend, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, UINT *old_priority)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *execute_ptr;
TX_THREAD *next_execute_ptr;
UINT original_priority;
/* Lockout interrupts while the thread is being suspended. */
TX_DISABLE
/* Save the previous priority. */
*old_priority = thread_ptr -> tx_thread_user_priority;
/* 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
/* 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
}
else
{
/* Set the state to priority change. */
thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE;
/* Pickup the next thread to execute. */
execute_ptr = _tx_thread_execute_ptr;
/* Save the original priority. */
original_priority = thread_ptr -> tx_thread_priority;
#ifdef TX_NOT_INTERRUPTABLE
/* Increment the preempt disable flag. */
_tx_thread_preempt_disable++;
/* 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);
#else
/* Increment the preempt disable flag by 2 to prevent system suspend from
returning to the system. */
_tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 3);
/* 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);
/* 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_resume(thread_ptr);
/* Disable interrupts. */
TX_DISABLE
#endif
/* Decrement the preempt disable flag. */
_tx_thread_preempt_disable--;
/* Pickup the next thread to execute. */
next_execute_ptr = _tx_thread_execute_ptr;
/* Determine if this thread is not the next thread to execute. */
if (thread_ptr != next_execute_ptr)
{
/* Make sure the thread is still ready. */
if (thread_ptr -> tx_thread_state == TX_READY)
{
/* Now check and see if this thread has an equal or higher priority. */
if (thread_ptr -> tx_thread_priority <= next_execute_ptr -> tx_thread_priority)
{
/* Now determine if this thread was the previously executing thread. */
if (thread_ptr == execute_ptr)
{
/* Yes, this thread was previously executing before we temporarily suspended and resumed
it in order to change the priority. A lower or same priority thread cannot be the next thread
to execute in this case since this thread really didn't suspend. Simply reset the execute
pointer to this thread. */
_tx_thread_execute_ptr = thread_ptr;
/* Determine if we moved to a lower priority. If so, move the thread to the front of its priority list. */
if (original_priority < new_priority)
{
/* Ensure that this thread is placed at the front of the priority list. */
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr;
}
}
}
}
}
/* Restore interrupts. */
TX_RESTORE
/* Check for preemption. */
_tx_thread_system_preempt_check();
}
/* Return success if we get here! */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,171 @@
/**************************************************************************/
/* */
/* 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"
#ifndef TX_NO_TIMER
#include "tx_timer.h"
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_relinquish PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function moves the currently executing thread to the end of */
/* the list of threads ready at the same priority. If no other threads */
/* of the same or higher priority are ready, this function simply */
/* returns. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_system_return Return to the system */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_relinquish(VOID)
{
TX_INTERRUPT_SAVE_AREA
UINT priority;
TX_THREAD *thread_ptr;
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(thread_ptr)
#ifdef TX_ENABLE_STACK_CHECKING
/* Check this thread's stack. */
TX_THREAD_STACK_CHECK(thread_ptr)
#endif
/* Disable interrupts. */
TX_DISABLE
#ifndef TX_NO_TIMER
/* Reset time slice for current thread. */
_tx_timer_time_slice = thread_ptr -> tx_thread_new_time_slice;
#endif
/* Pickup the thread's priority. */
priority = thread_ptr -> tx_thread_priority;
/* Determine if there is another thread at the same priority. */
if (thread_ptr -> tx_thread_ready_next != thread_ptr)
{
/* Yes, there is another thread at this priority, make it the highest at
this priority level. */
_tx_thread_priority_list[priority] = thread_ptr -> tx_thread_ready_next;
/* Mark the new thread as the one to execute. */
_tx_thread_execute_ptr = thread_ptr -> tx_thread_ready_next;
}
/* Determine if there is a higher-priority thread ready. */
if (_tx_thread_highest_priority < priority)
{
/* Yes, there is a higher priority thread ready to execute. Make
it visible to the thread scheduler. */
_tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
/* No need to clear the preempted bit in this case, since the currently running
thread must already have its preempted bit clear. */
}
/* 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(_tx_thread_execute_ptr), 0, 0, TX_TRACE_THREAD_EVENTS)
/* Log this kernel call. */
TX_EL_THREAD_RELINQUISH_INSERT
/* Restore previous interrupt posture. */
TX_RESTORE
/* Determine if this thread needs to return to the system. */
if (_tx_thread_execute_ptr != 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++;
/* Increment the non-idle return count. */
_tx_thread_performance_non_idle_return_count++;
#endif
#ifdef TX_ENABLE_STACK_CHECKING
/* Pickup the next execute pointer. */
thread_ptr = _tx_thread_execute_ptr;
/* Check this thread's stack. */
TX_THREAD_STACK_CHECK(thread_ptr)
#endif
/* Transfer control to the system so the scheduler can execute
the next thread. */
_tx_thread_system_return();
}
}

View File

@@ -0,0 +1,165 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,583 @@
/**************************************************************************/
/* */
/* 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_initialize.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_resume PORTABLE C */
/* 6.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_system_resume Resume thread */
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_resume(TX_THREAD *thread_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT status;
TX_THREAD *saved_thread_ptr;
UINT saved_threshold = ((UINT) 0);
#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
UINT priority;
ULONG priority_bit;
TX_THREAD *head_ptr;
TX_THREAD *tail_ptr;
TX_THREAD *execute_ptr;
TX_THREAD *current_thread;
ULONG combined_flags;
#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
#ifdef TX_ENABLE_STACK_CHECKING
/* Check this thread's stack. */
TX_THREAD_STACK_CHECK(thread_ptr)
#endif
#endif
/* 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)
{
/* Determine if the create call is being called from initialization. */
if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS)
{
/* Yes, this resume call was made from initialization. */
/* Pickup the current thread execute pointer, which corresponds to the
highest priority thread ready to execute. Interrupt lockout is
not required, since interrupts are assumed to be disabled during
initialization. */
saved_thread_ptr = _tx_thread_execute_ptr;
/* Determine if there is thread ready for execution. */
if (saved_thread_ptr != TX_NULL)
{
/* Yes, a thread is ready for execution when initialization completes. */
/* Save the current preemption-threshold. */
saved_threshold = saved_thread_ptr -> tx_thread_preempt_threshold;
/* For initialization, temporarily set the preemption-threshold to the
priority level to make sure the highest-priority thread runs once
initialization is complete. */
saved_thread_ptr -> tx_thread_preempt_threshold = saved_thread_ptr -> tx_thread_priority;
}
}
else
{
/* Simply set the saved thread pointer to NULL. */
saved_thread_ptr = TX_NULL;
}
#ifndef TX_INLINE_THREAD_RESUME_SUSPEND
#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
/* Determine if the thread's preemption-threshold needs to be restored. */
if (saved_thread_ptr != TX_NULL)
{
/* Yes, restore the previous highest-priority thread's preemption-threshold. This
can only happen if this routine is called from initialization. */
saved_thread_ptr -> tx_thread_preempt_threshold = saved_threshold;
}
#ifdef TX_MISRA_ENABLE
/* Disable interrupts. */
TX_DISABLE
/* Setup successful return status. */
status = TX_SUCCESS;
#else
/* Return successful completion. */
return(TX_SUCCESS);
#endif
#else
/* In-line thread resumption processing follows, which is effectively just taking the
logic in tx_thread_system_resume.c and placing it here! */
/* Resume the thread! */
#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(&execute_ptr), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
#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
/* 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;
/* 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)
#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)
{
/* 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 this newly ready thread is the highest priority. */
if (priority < _tx_thread_highest_priority)
{
/* A new highest priority thread is present. */
/* Update the highest priority variable. */
_tx_thread_highest_priority = priority;
/* Pickup the execute pointer. Since it is going to be referenced multiple
times, it is placed in a local variable. */
execute_ptr = _tx_thread_execute_ptr;
/* Determine if no thread is currently executing. */
if (execute_ptr == TX_NULL)
{
/* Simply setup the execute pointer. */
_tx_thread_execute_ptr = thread_ptr;
}
else
{
/* Another thread has been scheduled for execution. */
/* Check to see if this is a higher priority thread and determine if preemption is allowed. */
if (priority < execute_ptr -> tx_thread_preempt_threshold)
{
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
/* Determine if the preempted thread had preemption-threshold set. */
if (execute_ptr -> tx_thread_preempt_threshold != execute_ptr -> tx_thread_priority)
{
#if TX_MAX_PRIORITIES > 32
/* Calculate the index into the bit map array. */
map_index = (execute_ptr -> tx_thread_priority)/((UINT) 32);
/* Set the active bit to remember that the preempt map has something set. */
TX_DIV32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
_tx_thread_preempted_map_active = _tx_thread_preempted_map_active | priority_bit;
#endif
/* Remember that this thread was preempted by a thread above the thread's threshold. */
TX_MOD32_BIT_SET(execute_ptr -> tx_thread_priority, priority_bit)
_tx_thread_preempted_maps[MAP_INDEX] = _tx_thread_preempted_maps[MAP_INDEX] | priority_bit;
}
#endif
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Determine if the caller is an interrupt or from a thread. */
if (TX_THREAD_GET_SYSTEM_STATE() == ((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. */
execute_ptr -> tx_thread_performance_solicited_preemption_count++;
}
else
{
if (TX_THREAD_GET_SYSTEM_STATE() < 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. */
execute_ptr -> tx_thread_performance_interrupt_preemption_count++;
}
}
/* Remember the thread that preempted this thread. */
execute_ptr -> tx_thread_performance_last_preempting_thread = thread_ptr;
#endif
/* Yes, modify the execute thread pointer. */
_tx_thread_execute_ptr = thread_ptr;
#ifndef TX_MISRA_ENABLE
/* If MISRA is not-enabled, insert a preemption and return in-line for performance. */
/* Determine if the thread's preemption-threshold needs to be restored. */
if (saved_thread_ptr != TX_NULL)
{
/* Yes, restore the previous highest-priority thread's preemption-threshold. This
can only happen if this routine is called from initialization. */
saved_thread_ptr -> tx_thread_preempt_threshold = saved_threshold;
}
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Is the execute pointer different? */
if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
{
/* Move to next entry. */
_tx_thread_performance__execute_log_index++;
/* Check for wrap condition. */
if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
{
/* Set the index to the beginning. */
_tx_thread_performance__execute_log_index = ((UINT) 0);
}
/* Log the new execute pointer. */
_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_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)
{
/* Is the timestamp the same? */
if (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. */
entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
}
}
#endif
/* Restore interrupts. */
TX_RESTORE
#ifdef TX_ENABLE_STACK_CHECKING
/* Pickup the next execute pointer. */
thread_ptr = _tx_thread_execute_ptr;
/* 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. */
TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
if (combined_flags == ((ULONG) 0))
{
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* There is another thread ready to run and will be scheduled upon return. */
_tx_thread_performance_non_idle_return_count++;
#endif
/* Preemption is needed - return to the system! */
_tx_thread_system_return();
}
/* Return in-line when MISRA is not enabled. */
return(TX_SUCCESS);
#endif
}
}
}
}
else
{
/* No, 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;
}
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Determine if we should log the execute pointer. */
/* Is the execute pointer different? */
if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
{
/* Move to next entry. */
_tx_thread_performance__execute_log_index++;
/* Check for wrap condition. */
if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
{
/* Set the index to the beginning. */
_tx_thread_performance__execute_log_index = ((UINT) 0);
}
/* Log the new execute pointer. */
_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_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)
{
/* Is the timestamp the same? */
if (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);
#else
entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
#endif
}
}
#endif
/* Determine if the thread's preemption-threshold needs to be restored. */
if (saved_thread_ptr != TX_NULL)
{
/* Yes, restore the previous highest-priority thread's preemption-threshold. This
can only happen if this routine is called from initialization. */
saved_thread_ptr -> tx_thread_preempt_threshold = saved_threshold;
}
/* Setup successful return status. */
status = TX_SUCCESS;
#endif
}
else if (thread_ptr -> tx_thread_delayed_suspend == TX_TRUE)
{
/* 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
#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(current_thread)
/* Determine if a preemption condition is present. */
if (current_thread != _tx_thread_execute_ptr)
{
#ifdef TX_ENABLE_STACK_CHECKING
/* Pickup the next execute pointer. */
thread_ptr = _tx_thread_execute_ptr;
/* 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. */
TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
if (combined_flags == ((ULONG) 0))
{
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* There is another thread ready to run and will be scheduled upon return. */
_tx_thread_performance_non_idle_return_count++;
#endif
/* Preemption is needed - return to the system! */
_tx_thread_system_return();
}
}
#endif
/* Return completion status. */
return(status);
}

View File

@@ -0,0 +1,203 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,200 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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);
}

View File

@@ -0,0 +1,183 @@
/**************************************************************************/
/* */
/* 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.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.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
}

View File

@@ -0,0 +1,120 @@
/**************************************************************************/
/* */
/* 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"
#if defined(TX_MISRA_ENABLE) || defined(TX_ENABLE_STACK_CHECKING) || defined(TX_PORT_THREAD_STACK_ERROR_HANDLING)
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_stack_error_handler PORTABLE C */
/* 6.1.9 */
/* 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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* update misra support, */
/* resulting in version 6.1 */
/* 10-16-2020 William E. Lamie Modified comment(s), */
/* fixed link issue, */
/* resulting in version 6.1.1 */
/* 06-02-2021 William E. Lamie Modified comment(s), */
/* fixed link issue, added */
/* conditional compilation */
/* for ARMv8-M (Cortex M23/33) */
/* resulting in version 6.1.7 */
/* 10-15-2021 Yuxin Zhou Modified comment(s), improved */
/* stack check error handling, */
/* resulting in version 6.1.9 */
/* */
/**************************************************************************/
VOID _tx_thread_stack_error_handler(TX_THREAD *thread_ptr)
{
TX_INTERRUPT_SAVE_AREA
#if defined(TX_ENABLE_STACK_CHECKING) || defined(TX_PORT_THREAD_STACK_ERROR_HANDLING)
/* 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
}
#endif

View File

@@ -0,0 +1,134 @@
/**************************************************************************/
/* */
/* 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"
#if defined(TX_ENABLE_STACK_CHECKING) || defined(TX_PORT_THREAD_STACK_ERROR_HANDLING)
#include "tx_trace.h"
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_stack_error_notify PORTABLE C */
/* 6.1.9 */
/* 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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 06-02-2021 Yuxin Zhou Modified comment(s), added */
/* conditional compilation */
/* for ARMv8-M (Cortex M23/33) */
/* resulting in version 6.1.7 */
/* 10-15-2021 Yuxin Zhou Modified comment(s), improved */
/* stack check error handling, */
/* resulting in version 6.1.9 */
/* */
/**************************************************************************/
UINT _tx_thread_stack_error_notify(VOID (*stack_error_handler)(TX_THREAD *thread_ptr))
{
#if !defined(TX_ENABLE_STACK_CHECKING) && !defined(TX_PORT_THREAD_STACK_ERROR_HANDLING)
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
}

View File

@@ -0,0 +1,849 @@
/**************************************************************************/
/* */
/* 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"
#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
#ifndef TX_NO_TIMER
#include "tx_timer.h"
#endif
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_suspend PORTABLE C */
/* 6.1.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 10-16-2020 Yuxin Zhou Modified comment(s), and */
/* added type cast to address */
/* a MISRA compliance issue, */
/* resulting in version 6.1.1 */
/* */
/**************************************************************************/
UINT _tx_thread_suspend(TX_THREAD *thread_ptr)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *current_thread;
UINT status;
#ifndef TX_INLINE_THREAD_RESUME_SUSPEND
/* 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;
/* Determine if we are in a thread context. */
if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
{
/* Yes, we are in a thread context. */
/* Determine if the current thread is also the suspending thread. */
if (current_thread == thread_ptr)
{
/* Now determine if the preempt disable flag is non-zero. */
if (_tx_thread_preempt_disable != ((UINT) 0))
{
/* Current thread cannot suspend when the preempt disable flag is non-zero,
return an error. */
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);
#else
/* In-line thread suspension processing follows, which is effectively just taking the
logic in tx_thread_system_suspend.c and placing it here! */
UINT priority;
UINT base_priority;
ULONG priority_map;
ULONG priority_bit;
ULONG combined_flags;
TX_THREAD *ready_next;
TX_THREAD *ready_previous;
#if TX_MAX_PRIORITIES > 32
UINT map_index;
#endif
#ifdef TX_ENABLE_EVENT_TRACE
TX_TRACE_BUFFER_ENTRY *entry_ptr;
ULONG time_stamp = ((ULONG) 0);
#endif
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(current_thread)
#ifdef TX_ENABLE_STACK_CHECKING
/* Check this thread's stack. */
TX_THREAD_STACK_CHECK(thread_ptr)
#endif
/* Lockout interrupts while the thread is being suspended. */
TX_DISABLE
#ifndef TX_NO_TIMER
/* Determine if this is the current thread. */
if (thread_ptr == current_thread)
{
/* Yes, current thread is suspending - reset time slice for current thread. */
_tx_timer_time_slice = thread_ptr -> tx_thread_new_time_slice;
}
#endif
/* 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;
/* Determine if we are in a thread context. */
if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0))
{
/* Yes, we are in a thread context. */
/* Determine if the current thread is also the suspending thread. */
if (current_thread == thread_ptr)
{
/* Now determine if the preempt disable flag is non-zero. */
if (_tx_thread_preempt_disable != ((UINT) 0))
{
/* Current thread cannot suspend when the preempt disable flag is non-zero,
return an error. */
status = TX_SUSPEND_ERROR;
}
}
}
/* Determine if the status is still successful. */
if (status == TX_SUCCESS)
{
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Increment the thread's suspend count. */
thread_ptr -> tx_thread_performance_suspend_count++;
/* Increment the total number of thread suspensions. */
_tx_thread_performance_suspend_count++;
#endif
/* Set the state to suspended. */
thread_ptr -> tx_thread_state = TX_SUSPENDED;
/* Thread state change. */
TX_THREAD_STATE_CHANGE(thread_ptr, TX_SUSPENDED)
/* Log the thread status change. */
TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, thread_ptr -> tx_thread_state)
#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_SUSPEND, thread_ptr, ((ULONG) thread_ptr -> tx_thread_state), TX_POINTER_TO_ULONG_CONVERT(&priority), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS)
#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
/* Pickup priority of thread. */
priority = thread_ptr -> tx_thread_priority;
/* Pickup the previous and next ready thread pointers. */
ready_next = thread_ptr -> tx_thread_ready_next;
ready_previous = thread_ptr -> tx_thread_ready_previous;
/* Determine if there are other threads at this priority that are
ready. */
if (ready_next != thread_ptr)
{
/* Yes, there are other threads at this priority ready. */
/* Just remove this thread from the priority list. */
ready_next -> tx_thread_ready_previous = ready_previous;
ready_previous -> tx_thread_ready_next = ready_next;
/* Determine if this is the head of the priority list. */
if (_tx_thread_priority_list[priority] == thread_ptr)
{
/* Update the head pointer of this priority list. */
_tx_thread_priority_list[priority] = ready_next;
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
#if TX_MAX_PRIORITIES > 32
/* Calculate the index into the bit map array. */
map_index = priority/((UINT) 32);
#endif
/* Check for a thread preempted that had preemption threshold set. */
if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
{
/* 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 preempt 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
}
}
else
{
/* This is the only thread at this priority ready to run. Set the head
pointer to NULL. */
_tx_thread_priority_list[priority] = TX_NULL;
#if TX_MAX_PRIORITIES > 32
/* Calculate the index into the bit map array. */
map_index = priority/((UINT) 32);
#endif
/* Clear this priority bit in the ready priority bit map. */
TX_MOD32_BIT_SET(priority, priority_bit)
_tx_thread_priority_maps[MAP_INDEX] = _tx_thread_priority_maps[MAP_INDEX] & (~(priority_bit));
#if TX_MAX_PRIORITIES > 32
/* Determine if there are any other bits set in this priority map. */
if (_tx_thread_priority_maps[MAP_INDEX] == ((ULONG) 0))
{
/* No, clear the active bit to signify this priority map has nothing set. */
TX_DIV32_BIT_SET(priority, priority_bit)
_tx_thread_priority_map_active = _tx_thread_priority_map_active & (~(priority_bit));
}
#endif
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
/* Check for a thread preempted that had preemption-threshold set. */
if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
{
/* 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
#if TX_MAX_PRIORITIES > 32
/* Calculate the index to find the next highest priority thread ready for execution. */
priority_map = _tx_thread_priority_map_active;
/* Determine if there is anything. */
if (priority_map != ((ULONG) 0))
{
/* 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 working variable for the priority map. */
priority_map = _tx_thread_priority_maps[MAP_INDEX];
/* Make a quick check for no other threads ready for execution. */
if (priority_map == ((ULONG) 0))
{
/* Nothing else is ready. Set highest priority and execute thread
accordingly. */
_tx_thread_highest_priority = ((UINT) TX_MAX_PRIORITIES);
_tx_thread_execute_ptr = TX_NULL;
#ifndef TX_MISRA_ENABLE
#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
suspend 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, set the "next thread pointer" to the new value of the
next thread to execute. This can be used by the trace analysis tool to keep
track of next thread execution. */
entry_ptr -> tx_trace_buffer_entry_information_field_4 = 0;
}
}
#endif
/* Restore interrupts. */
TX_RESTORE
/* 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. */
TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
if (combined_flags == ((ULONG) 0))
{
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Yes, increment the return to idle return count. */
_tx_thread_performance_idle_return_count++;
#endif
/* Preemption is needed - return to the system! */
_tx_thread_system_return();
}
/* Return to caller. */
return(TX_SUCCESS);
#endif
}
else
{
/* Calculate the lowest bit set in the priority map. */
TX_LOWEST_SET_BIT_CALCULATE(priority_map, priority_bit)
/* Setup the next highest priority variable. */
_tx_thread_highest_priority = base_priority + priority_bit;
}
}
/* Determine if this thread is the thread designated to execute. */
if (thread_ptr == _tx_thread_execute_ptr)
{
/* Pickup the highest priority thread to execute. */
_tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
#ifndef TX_DISABLE_PREEMPTION_THRESHOLD
/* Determine if a previous thread with preemption-threshold was preempted. */
#if TX_MAX_PRIORITIES > 32
if (_tx_thread_preempted_map_active != ((ULONG) 0))
#else
if (_tx_thread_preempted_maps[MAP_INDEX] != ((ULONG) 0))
#endif
{
/* Yes, there was a thread preempted when it was using preemption-threshold. */
#ifndef TX_NOT_INTERRUPTABLE
/* Disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Interrupts are enabled briefly here to keep the interrupt
lockout time deterministic. */
/* Disable interrupts again. */
TX_DISABLE
/* Decrement the preemption disable variable. */
_tx_thread_preempt_disable--;
#endif
/* Calculate the thread with preemption threshold set that
was interrupted by a thread above the preemption level. */
#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)
/* Setup the highest priority preempted thread. */
priority = base_priority + priority_bit;
/* Determine if the next highest priority thread is above the highest priority threshold value. */
if (_tx_thread_highest_priority >= (_tx_thread_priority_list[priority] -> tx_thread_preempt_threshold))
{
/* Thread not allowed to execute until earlier preempted thread finishes or lowers its
preemption-threshold. */
_tx_thread_execute_ptr = _tx_thread_priority_list[priority];
#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
suspend 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, set the "next thread pointer" to the new value of the
next thread to execute. This can be used by the trace analysis tool to keep
track of next thread execution. */
#ifdef TX_MISRA_ENABLE
entry_ptr -> tx_trace_buffer_entry_info_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
#else
entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
#endif
}
}
#endif
/* Clear the corresponding bit in the preempted map, since the preemption has been restored. */
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 preempt 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
#ifndef TX_MISRA_ENABLE
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Is the execute pointer different? */
if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
{
/* Move to next entry. */
_tx_thread_performance__execute_log_index++;
/* Check for wrap condition. */
if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
{
/* Set the index to the beginning. */
_tx_thread_performance__execute_log_index = ((UINT) 0);
}
/* Log the new execute pointer. */
_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_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
suspend 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, set the "next thread pointer" to the new value of the
next thread to execute. This can be used by the trace analysis tool to keep
track of next thread execution. */
entry_ptr -> tx_trace_buffer_entry_information_field_4 = 0;
}
}
#endif
/* Restore interrupts. */
TX_RESTORE
/* 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. */
TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
if (combined_flags == ((ULONG) 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
/* Preemption is needed - return to the system! */
_tx_thread_system_return();
}
/* Return to caller. */
return(TX_SUCCESS);
#endif
}
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Is the execute pointer different? */
if (_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] != _tx_thread_execute_ptr)
{
/* Move to next entry. */
_tx_thread_performance__execute_log_index++;
/* Check for wrap condition. */
if (_tx_thread_performance__execute_log_index >= TX_THREAD_EXECUTE_LOG_SIZE)
{
/* Set the index to the beginning. */
_tx_thread_performance__execute_log_index = ((UINT) 0);
}
/* Log the new execute pointer. */
_tx_thread_performance_execute_log[_tx_thread_performance__execute_log_index] = _tx_thread_execute_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
suspend 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, set the "next thread pointer" to the new value of the
next thread to execute. This can be used by the trace analysis tool to keep
track of next thread execution. */
#ifdef TX_MISRA_ENABLE
entry_ptr -> tx_trace_buffer_entry_info_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
#else
entry_ptr -> tx_trace_buffer_entry_information_field_4 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr);
#endif
}
}
#endif
/* Restore interrupts. */
TX_RESTORE
/* Determine if a preemption condition is present. */
if (current_thread != _tx_thread_execute_ptr)
{
#ifdef TX_ENABLE_STACK_CHECKING
/* Pickup the next execute pointer. */
thread_ptr = _tx_thread_execute_ptr;
/* Check this thread's stack. */
TX_THREAD_STACK_CHECK(thread_ptr)
#endif
/* 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. */
TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
if (combined_flags == ((ULONG) 0))
{
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Determine if an idle system return is present. */
if (_tx_thread_execute_ptr == 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
/* Preemption is needed - return to the system! */
_tx_thread_system_return();
}
}
/* Disable interrupts. */
TX_DISABLE
/* Return success. */
status = TX_SUCCESS;
}
}
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
/* Return completion status. */
return(status);
#endif
}

View 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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_system_preempt_check PORTABLE C */
/* 6.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 */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_system_preempt_check(VOID)
{
ULONG combined_flags;
TX_THREAD *current_thread;
TX_THREAD *thread_ptr;
/* Combine the system state and preempt disable flags into one for comparison. */
TX_THREAD_SYSTEM_RETURN_CHECK(combined_flags)
/* Determine if we are in a system state (ISR or Initialization) or internal preemption is disabled. */
if (combined_flags == ((ULONG) 0))
{
/* No, at thread execution level so continue checking for preemption. */
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(current_thread)
/* Pickup the next execute pointer. */
thread_ptr = _tx_thread_execute_ptr;
/* Determine if preemption should take place. */
if (current_thread != thread_ptr)
{
#ifdef TX_ENABLE_STACK_CHECKING
/* 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 (thread_ptr == 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
/* Return to the system so the higher priority thread can be scheduled. */
_tx_thread_system_return();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
/**************************************************************************/
/* */
/* 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_terminate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function handles application thread terminate requests. Once */
/* a thread is terminated, it cannot be executed again unless it is */
/* deleted and recreated. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread to suspend */
/* */
/* OUTPUT */
/* */
/* status Return completion status */
/* */
/* CALLS */
/* */
/* _tx_timer_system_deactivate Timer deactivate function */
/* _tx_thread_system_suspend Actual thread suspension */
/* _tx_thread_system_ni_suspend Non-interruptable suspend */
/* thread */
/* _tx_thread_system_preempt_check Check for preemption */
/* Suspend Cleanup Routine Suspension cleanup function */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_terminate(TX_THREAD *thread_ptr)
{
TX_INTERRUPT_SAVE_AREA
VOID (*suspend_cleanup)(struct TX_THREAD_STRUCT *suspend_thread_ptr, ULONG suspension_sequence);
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
VOID (*entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id);
#endif
UINT status;
ULONG suspension_sequence;
/* Default to successful completion. */
status = TX_SUCCESS;
/* Lockout interrupts while the thread is being terminated. */
TX_DISABLE
/* Deactivate thread timer, if active. */
_tx_timer_system_deactivate(&thread_ptr -> tx_thread_timer);
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_TERMINATE, thread_ptr, thread_ptr -> tx_thread_state, TX_POINTER_TO_ULONG_CONVERT(&suspend_cleanup), 0, TX_TRACE_THREAD_EVENTS)
/* Log this kernel call. */
TX_EL_THREAD_TERMINATE_INSERT
/* Is the thread already terminated? */
if (thread_ptr -> tx_thread_state == TX_TERMINATED)
{
/* Restore interrupts. */
TX_RESTORE
/* Return success since thread is already terminated. */
status = TX_SUCCESS;
}
/* Check the specified thread's current status. */
else if (thread_ptr -> tx_thread_state != TX_COMPLETED)
{
/* Disable preemption. */
_tx_thread_preempt_disable++;
#ifndef TX_DISABLE_NOTIFY_CALLBACKS
/* Pickup the entry/exit application callback routine. */
entry_exit_notify = thread_ptr -> tx_thread_entry_exit_notify;
#endif
/* Check to see if the thread is currently ready. */
if (thread_ptr -> tx_thread_state == TX_READY)
{
/* Set the state to terminated. */
thread_ptr -> tx_thread_state = TX_TERMINATED;
/* Thread state change. */
TX_THREAD_STATE_CHANGE(thread_ptr, TX_TERMINATED)
#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
/* Call actual non-interruptable thread suspension routine. */
_tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
#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);
/* Disable preemption. */
_tx_thread_preempt_disable++;
/* Since the thread is currently ready, we don't need to
worry about calling the suspend cleanup routine! */
/* Restore interrupts. */
TX_RESTORE
/* Perform any additional activities for tool or user purpose. */
TX_THREAD_TERMINATED_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);
/* Disable interrupts. */
TX_DISABLE
#endif
}
else
{
/* Change the state to terminated. */
thread_ptr -> tx_thread_state = TX_TERMINATED;
/* Thread state change. */
TX_THREAD_STATE_CHANGE(thread_ptr, TX_TERMINATED)
/* Set the suspending flag. This prevents the thread from being
resumed before the cleanup routine is executed. */
thread_ptr -> tx_thread_suspending = TX_TRUE;
/* Pickup the cleanup routine address. */
suspend_cleanup = thread_ptr -> tx_thread_suspend_cleanup;
#ifndef TX_NOT_INTERRUPTABLE
/* Pickup the suspension sequence number that is used later to verify that the
cleanup is still necessary. */
suspension_sequence = thread_ptr -> tx_thread_suspension_sequence;
#else
/* When not interruptable is selected, the suspension sequence is not used - just set to 0. */
suspension_sequence = ((ULONG) 0);
#endif
#ifndef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
/* Call any cleanup routines. */
if (suspend_cleanup != TX_NULL)
{
/* Yes, there is a function to call. */
(suspend_cleanup)(thread_ptr, suspension_sequence);
}
#ifndef TX_NOT_INTERRUPTABLE
/* Disable interrupts. */
TX_DISABLE
#endif
/* Clear the suspending flag. */
thread_ptr -> tx_thread_suspending = TX_FALSE;
#ifndef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
/* Perform any additional activities for tool or user purpose. */
TX_THREAD_TERMINATED_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
#ifndef TX_NOT_INTERRUPTABLE
/* Disable interrupts. */
TX_DISABLE
#endif
}
#ifndef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
/* 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 initialization. */
(_tx_thread_mutex_release)(thread_ptr);
}
#ifndef TX_NOT_INTERRUPTABLE
/* Disable interrupts. */
TX_DISABLE
#endif
/* Enable preemption. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
}
else
{
/* Restore interrupts. */
TX_RESTORE
}
/* Check for preemption. */
_tx_thread_system_preempt_check();
/* Return completion status. */
return(status);
}

View File

@@ -0,0 +1,190 @@
/**************************************************************************/
/* */
/* 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
#ifndef TX_NO_TIMER
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
#include "tx_trace.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_time_slice PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function moves the currently executing thread to the end of */
/* the threads ready at the same priority level as a result of a */
/* time-slice interrupt. If no other thread of the same priority is */
/* ready, this function simply returns. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_timer_interrupt Timer interrupt handling */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Scott Larson Modified comment(s), and */
/* opt out of function when */
/* TX_NO_TIMER is defined, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_time_slice(VOID)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *thread_ptr;
#ifdef TX_ENABLE_STACK_CHECKING
TX_THREAD *next_thread_ptr;
#endif
#ifdef TX_ENABLE_EVENT_TRACE
ULONG system_state;
UINT preempt_disable;
#endif
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(thread_ptr)
#ifdef TX_ENABLE_STACK_CHECKING
/* Check this thread's stack. */
TX_THREAD_STACK_CHECK(thread_ptr)
/* Set the next thread pointer to NULL. */
next_thread_ptr = TX_NULL;
#endif
/* Lockout interrupts while the time-slice is evaluated. */
TX_DISABLE
/* Clear the expired time-slice flag. */
_tx_timer_expired_time_slice = TX_FALSE;
/* Make sure the thread pointer is valid. */
if (thread_ptr != TX_NULL)
{
/* Make sure the thread is still active, i.e. not suspended. */
if (thread_ptr -> tx_thread_state == TX_READY)
{
/* Setup a fresh time-slice for the thread. */
thread_ptr -> tx_thread_time_slice = thread_ptr -> tx_thread_new_time_slice;
/* Reset the actual time-slice variable. */
_tx_timer_time_slice = thread_ptr -> tx_thread_time_slice;
/* Determine if there is another thread at the same priority and preemption-threshold
is not set. Preemption-threshold overrides time-slicing. */
if (thread_ptr -> tx_thread_ready_next != thread_ptr)
{
/* Check to see if preemption-threshold is not being used. */
if (thread_ptr -> tx_thread_priority == thread_ptr -> tx_thread_preempt_threshold)
{
/* Preemption-threshold is not being used by this thread. */
/* There is another thread at this priority, make it the highest at
this priority level. */
_tx_thread_priority_list[thread_ptr -> tx_thread_priority] = thread_ptr -> tx_thread_ready_next;
/* Designate the highest priority thread as the one to execute. Don't use this
thread's priority as an index just in case a higher priority thread is now
ready! */
_tx_thread_execute_ptr = _tx_thread_priority_list[_tx_thread_highest_priority];
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Increment the thread's time-slice counter. */
thread_ptr -> tx_thread_performance_time_slice_count++;
/* Increment the total number of thread time-slice operations. */
_tx_thread_performance_time_slice_count++;
#endif
#ifdef TX_ENABLE_STACK_CHECKING
/* Pickup the next execute pointer. */
next_thread_ptr = _tx_thread_execute_ptr;
#endif
}
}
}
}
#ifdef TX_ENABLE_EVENT_TRACE
/* Pickup the volatile information. */
system_state = TX_THREAD_GET_SYSTEM_STATE();
preempt_disable = _tx_thread_preempt_disable;
/* Insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIME_SLICE, _tx_thread_execute_ptr, system_state, preempt_disable, TX_POINTER_TO_ULONG_CONVERT(&thread_ptr), TX_TRACE_INTERNAL_EVENTS)
#endif
/* Restore previous interrupt posture. */
TX_RESTORE
#ifdef TX_ENABLE_STACK_CHECKING
/* Determine if there is a next thread pointer to perform stack checking on. */
if (next_thread_ptr != TX_NULL)
{
/* Yes, check this thread's stack. */
TX_THREAD_STACK_CHECK(next_thread_ptr)
}
#endif
}
#endif

View File

@@ -0,0 +1,119 @@
/**************************************************************************/
/* */
/* 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_time_slice_change PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes thread time slice change requests. The */
/* previous time slice is returned to the caller. If the new request */
/* is made for an executing thread, it is also placed in the actual */
/* time-slice countdown variable. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread */
/* new_time_slice New time slice */
/* old_time_slice Old time slice */
/* */
/* OUTPUT */
/* */
/* status Service return status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_time_slice_change(TX_THREAD *thread_ptr, ULONG new_time_slice, ULONG *old_time_slice)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *current_thread;
/* 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_TIME_SLICE_CHANGE, thread_ptr, new_time_slice, thread_ptr -> tx_thread_new_time_slice, 0, TX_TRACE_THREAD_EVENTS)
/* Log this kernel call. */
TX_EL_THREAD_TIME_SLICE_CHANGE_INSERT
/* Return the old time slice. */
*old_time_slice = thread_ptr -> tx_thread_new_time_slice;
/* Setup the new time-slice. */
thread_ptr -> tx_thread_time_slice = new_time_slice;
thread_ptr -> tx_thread_new_time_slice = new_time_slice;
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(current_thread)
/* Determine if this thread is the currently executing thread. */
if (thread_ptr == current_thread)
{
/* Yes, update the time-slice countdown variable. */
_tx_timer_time_slice = new_time_slice;
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,167 @@
/**************************************************************************/
/* */
/* 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"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_timeout PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function handles thread timeout processing. Timeouts occur in */
/* two flavors, namely the thread sleep timeout and all other service */
/* call timeouts. Thread sleep timeouts are processed locally, while */
/* the others are processed by the appropriate suspension clean-up */
/* service. */
/* */
/* INPUT */
/* */
/* timeout_input Contains the thread pointer */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* Suspension Cleanup Functions */
/* _tx_thread_system_resume Resume thread */
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
/* */
/* CALLED BY */
/* */
/* _tx_timer_expiration_process Timer expiration function */
/* _tx_timer_thread_entry Timer thread function */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_timeout(ULONG timeout_input)
{
TX_INTERRUPT_SAVE_AREA
TX_THREAD *thread_ptr;
VOID (*suspend_cleanup)(struct TX_THREAD_STRUCT *suspend_thread_ptr, ULONG suspension_sequence);
ULONG suspension_sequence;
/* Pickup the thread pointer. */
TX_THREAD_TIMEOUT_POINTER_SETUP(thread_ptr)
/* Disable interrupts. */
TX_DISABLE
/* Determine how the thread is currently suspended. */
if (thread_ptr -> tx_thread_state == TX_SLEEP)
{
#ifdef TX_NOT_INTERRUPTABLE
/* Resume the thread! */
_tx_thread_system_ni_resume(thread_ptr);
/* Restore interrupts. */
TX_RESTORE
#else
/* Increment the disable preemption flag. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Lift the suspension on the sleeping thread. */
_tx_thread_system_resume(thread_ptr);
#endif
}
else
{
/* Process all other suspension timeouts. */
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Increment the total number of thread timeouts. */
_tx_thread_performance_timeout_count++;
/* Increment the number of timeouts for this thread. */
thread_ptr -> tx_thread_performance_timeout_count++;
#endif
/* Pickup the cleanup routine address. */
suspend_cleanup = thread_ptr -> tx_thread_suspend_cleanup;
#ifndef TX_NOT_INTERRUPTABLE
/* Pickup the suspension sequence number that is used later to verify that the
cleanup is still necessary. */
suspension_sequence = thread_ptr -> tx_thread_suspension_sequence;
#else
/* When not interruptable is selected, the suspension sequence is not used - just set to 0. */
suspension_sequence = ((ULONG) 0);
#endif
#ifndef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
/* Call any cleanup routines. */
if (suspend_cleanup != TX_NULL)
{
/* Yes, there is a function to call. */
(suspend_cleanup)(thread_ptr, suspension_sequence);
}
#ifdef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#endif
}
}

View File

@@ -0,0 +1,247 @@
/**************************************************************************/
/* */
/* 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_wait_abort PORTABLE C */
/* 6.2.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function aborts the wait condition that the specified thread */
/* is in - regardless of what object the thread is waiting on - and */
/* returns a TX_WAIT_ABORTED status to the specified thread. */
/* */
/* INPUT */
/* */
/* thread_ptr Thread to abort the wait on */
/* */
/* OUTPUT */
/* */
/* status Return completion status */
/* */
/* CALLS */
/* */
/* Suspension Cleanup Functions */
/* _tx_thread_system_resume */
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
/* */
/* CALLED BY */
/* */
/* Application code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 03-08-2023 Scott Larson Check if thread is coming out */
/* of suspension elsewhere, */
/* resulting in version 6.2.1 */
/* */
/**************************************************************************/
UINT _tx_thread_wait_abort(TX_THREAD *thread_ptr)
{
TX_INTERRUPT_SAVE_AREA
VOID (*suspend_cleanup)(struct TX_THREAD_STRUCT *suspend_thread_ptr, ULONG suspension_sequence);
UINT status;
ULONG suspension_sequence;
/* Disable interrupts. */
TX_DISABLE
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_WAIT_ABORT, thread_ptr, thread_ptr -> tx_thread_state, 0, 0, TX_TRACE_THREAD_EVENTS)
/* Log this kernel call. */
TX_EL_THREAD_WAIT_ABORT_INSERT
/* Determine if the thread is currently suspended. */
if (thread_ptr -> tx_thread_state < TX_SLEEP)
{
/* Thread is either ready, completed, terminated, or in a pure
suspension condition. */
/* Restore interrupts. */
TX_RESTORE
/* Just return with an error message to indicate that
nothing was done. */
status = TX_WAIT_ABORT_ERROR;
}
else
{
/* Check for a sleep condition. */
if (thread_ptr -> tx_thread_state == TX_SLEEP)
{
/* Set the state to terminated. */
thread_ptr -> tx_thread_state = TX_SUSPENDED;
/* Set the TX_WAIT_ABORTED status in the thread that is
sleeping. */
thread_ptr -> tx_thread_suspend_status = TX_WAIT_ABORTED;
/* Make sure there isn't a suspend cleanup routine. */
thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
#ifndef TX_NOT_INTERRUPTABLE
/* Increment the disable preemption flag. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
#endif
}
else if(thread_ptr -> tx_thread_suspend_cleanup == TX_NULL)
{
/* Thread is coming out of suspension elsewhere. */
#ifndef TX_NOT_INTERRUPTABLE
/* Increment the disable preemption flag. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
#endif
}
else
{
/* Process all other suspension timeouts. */
/* Set the state to suspended. */
thread_ptr -> tx_thread_state = TX_SUSPENDED;
/* Pickup the cleanup routine address. */
suspend_cleanup = thread_ptr -> tx_thread_suspend_cleanup;
#ifndef TX_NOT_INTERRUPTABLE
/* Pickup the suspension sequence number that is used later to verify that the
cleanup is still necessary. */
suspension_sequence = thread_ptr -> tx_thread_suspension_sequence;
#else
/* When not interruptable is selected, the suspension sequence is not used - just set to 0. */
suspension_sequence = ((ULONG) 0);
#endif
/* Set the TX_WAIT_ABORTED status in the thread that was
suspended. */
thread_ptr -> tx_thread_suspend_status = TX_WAIT_ABORTED;
#ifndef TX_NOT_INTERRUPTABLE
/* Increment the disable preemption flag. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
#endif
/* Call cleanup routine. */
(suspend_cleanup)(thread_ptr, suspension_sequence);
}
/* If the abort of the thread wait was successful, if so resume the thread. */
if (thread_ptr -> tx_thread_suspend_status == TX_WAIT_ABORTED)
{
#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO
/* Increment the total number of thread wait aborts. */
_tx_thread_performance_wait_abort_count++;
/* Increment this thread's wait abort count. */
thread_ptr -> tx_thread_performance_wait_abort_count++;
#endif
#ifdef TX_NOT_INTERRUPTABLE
/* Resume the thread! */
_tx_thread_system_ni_resume(thread_ptr);
/* Restore interrupts. */
TX_RESTORE
#else
/* Lift the suspension on the previously waiting thread. */
_tx_thread_system_resume(thread_ptr);
#endif
/* Return a successful status. */
status = TX_SUCCESS;
}
else
{
#ifdef TX_NOT_INTERRUPTABLE
/* Restore interrupts. */
TX_RESTORE
#else
/* Disable interrupts. */
TX_DISABLE
/* Decrement the disable preemption flag. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
#endif
/* Return with an error message to indicate that
nothing was done. */
status = TX_WAIT_ABORT_ERROR;
}
}
/* Return completion status. */
return(status);
}

View File

@@ -0,0 +1,104 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_time_get PORTABLE C */
/* 6.1.3 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function retrieves the internal, free-running, system clock */
/* and returns it to the caller. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* _tx_timer_system_clock Returns the system clock value */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* 12-31-2020 Andres Mlinar Modified comment(s), */
/* resulting in version 6.1.3 */
/* */
/**************************************************************************/
ULONG _tx_time_get(VOID)
{
TX_INTERRUPT_SAVE_AREA
#ifdef TX_ENABLE_EVENT_TRACE
ULONG another_temp_time = ((ULONG) 0);
#endif
ULONG temp_time;
/* Disable interrupts. */
TX_DISABLE
/* Pickup the system clock time. */
temp_time = _tx_timer_system_clock;
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIME_GET, TX_ULONG_TO_POINTER_CONVERT(temp_time), TX_POINTER_TO_ULONG_CONVERT(&another_temp_time), 0, 0, TX_TRACE_TIME_EVENTS)
/* Log this kernel call. */
TX_EL_TIME_GET_INSERT
/* Restore interrupts. */
TX_RESTORE
/* Return the time. */
return(temp_time);
}

View File

@@ -0,0 +1,94 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_time_set PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function modifies the internal, free-running, system clock */
/* as specified by the caller. */
/* */
/* INPUT */
/* */
/* new_time New time value */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_time_set(ULONG new_time)
{
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_TIME_SET, TX_ULONG_TO_POINTER_CONVERT(new_time), 0, 0, 0, TX_TRACE_TIME_EVENTS)
/* Log this kernel call. */
TX_EL_TIME_SET_INSERT
/* Set the system clock time. */
_tx_timer_system_clock = new_time;
/* Restore interrupts. */
TX_RESTORE
}

View File

@@ -0,0 +1,137 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#ifdef TX_ENABLE_EVENT_TRACE
#include "tx_trace.h"
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_activate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function activates the specified application timer. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Always returns success */
/* */
/* CALLS */
/* */
/* _tx_timer_system_activate Actual timer activation function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_timer_activate(TX_TIMER *timer_ptr)
{
TX_INTERRUPT_SAVE_AREA
UINT status;
/* 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_TIMER_ACTIVATE, timer_ptr, 0, 0, 0, TX_TRACE_TIMER_EVENTS)
#endif
#ifdef TX_ENABLE_EVENT_LOGGING
/* Log this kernel call. */
TX_EL_TIMER_ACTIVATE_INSERT
#endif
/* Check for an already active timer. */
if (timer_ptr -> tx_timer_internal.tx_timer_internal_list_head != TX_NULL)
{
/* Timer is already active, return an error. */
status = TX_ACTIVATE_ERROR;
}
/* Check for a timer with a zero expiration. */
else if (timer_ptr -> tx_timer_internal.tx_timer_internal_remaining_ticks == ((ULONG) 0))
{
/* Timer is being activated with a zero expiration. */
status = TX_ACTIVATE_ERROR;
}
else
{
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total activations counter. */
_tx_timer_performance_activate_count++;
/* Increment the number of activations on this timer. */
timer_ptr -> tx_timer_performance_activate_count++;
#endif
/* Call actual activation function. */
_tx_timer_system_activate(&(timer_ptr -> tx_timer_internal));
/* Return a successful status. */
status = TX_SUCCESS;
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return(status);
}

View 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_change PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function modifies an application timer as specified by the */
/* input. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* initial_ticks Initial expiration ticks */
/* reschedule_ticks Reschedule ticks */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Successful completion status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG reschedule_ticks)
{
TX_INTERRUPT_SAVE_AREA
/* Disable interrupts to put the timer on the created list. */
TX_DISABLE
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_CHANGE, timer_ptr, initial_ticks, reschedule_ticks, 0, TX_TRACE_TIMER_EVENTS)
/* Log this kernel call. */
TX_EL_TIMER_CHANGE_INSERT
/* Determine if the timer is active. */
if (timer_ptr -> tx_timer_internal.tx_timer_internal_list_head == TX_NULL)
{
/* Setup the new expiration fields. */
timer_ptr -> tx_timer_internal.tx_timer_internal_remaining_ticks = initial_ticks;
timer_ptr -> tx_timer_internal.tx_timer_internal_re_initialize_ticks = reschedule_ticks;
}
/* Restore interrupts. */
TX_RESTORE
/* Return TX_SUCCESS. */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,169 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_create PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function creates an application timer from the specified */
/* input. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* name_ptr Pointer to timer name */
/* expiration_function Application expiration function */
/* initial_ticks Initial expiration ticks */
/* reschedule_ticks Reschedule ticks */
/* auto_activate Automatic activation flag */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Successful completion status */
/* */
/* CALLS */
/* */
/* _tx_timer_system_activate Timer activation function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_timer_create(TX_TIMER *timer_ptr, CHAR *name_ptr,
VOID (*expiration_function)(ULONG id), ULONG expiration_input,
ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate)
{
TX_INTERRUPT_SAVE_AREA
TX_TIMER *next_timer;
TX_TIMER *previous_timer;
/* Initialize timer control block to all zeros. */
TX_MEMSET(timer_ptr, 0, (sizeof(TX_TIMER)));
/* Setup the basic timer fields. */
timer_ptr -> tx_timer_name = name_ptr;
timer_ptr -> tx_timer_internal.tx_timer_internal_remaining_ticks = initial_ticks;
timer_ptr -> tx_timer_internal.tx_timer_internal_re_initialize_ticks = reschedule_ticks;
timer_ptr -> tx_timer_internal.tx_timer_internal_timeout_function = expiration_function;
timer_ptr -> tx_timer_internal.tx_timer_internal_timeout_param = expiration_input;
/* Disable interrupts to put the timer on the created list. */
TX_DISABLE
/* Setup the timer ID to make it valid. */
timer_ptr -> tx_timer_id = TX_TIMER_ID;
/* Place the timer on the list of created application timers. First,
check for an empty list. */
if (_tx_timer_created_count == TX_EMPTY)
{
/* The created timer list is empty. Add timer to empty list. */
_tx_timer_created_ptr = timer_ptr;
timer_ptr -> tx_timer_created_next = timer_ptr;
timer_ptr -> tx_timer_created_previous = timer_ptr;
}
else
{
/* This list is not NULL, add to the end of the list. */
next_timer = _tx_timer_created_ptr;
previous_timer = next_timer -> tx_timer_created_previous;
/* Place the new timer in the list. */
next_timer -> tx_timer_created_previous = timer_ptr;
previous_timer -> tx_timer_created_next = timer_ptr;
/* Setup this timer's created links. */
timer_ptr -> tx_timer_created_previous = previous_timer;
timer_ptr -> tx_timer_created_next = next_timer;
}
/* Increment the number of created timers. */
_tx_timer_created_count++;
/* Optional timer create extended processing. */
TX_TIMER_CREATE_EXTENSION(timer_ptr)
/* If trace is enabled, register this object. */
TX_TRACE_OBJECT_REGISTER(TX_TRACE_OBJECT_TYPE_TIMER, timer_ptr, name_ptr, initial_ticks, reschedule_ticks)
/* If trace is enabled, insert this call in the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_CREATE, timer_ptr, initial_ticks, reschedule_ticks, auto_activate, TX_TRACE_TIMER_EVENTS)
/* Log this kernel call. */
TX_EL_TIMER_CREATE_INSERT
/* Determine if this timer needs to be activated. */
if (auto_activate == TX_AUTO_ACTIVATE)
{
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total activations counter. */
_tx_timer_performance_activate_count++;
/* Increment the number of activations on this timer. */
timer_ptr -> tx_timer_performance_activate_count++;
#endif
/* Call actual activation function. */
_tx_timer_system_activate(&(timer_ptr -> tx_timer_internal));
}
/* Restore interrupts. */
TX_RESTORE
/* Return TX_SUCCESS. */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,252 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_deactivate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function deactivates the specified application timer. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Always returns success */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_timer_deactivate(TX_TIMER *timer_ptr)
{
TX_INTERRUPT_SAVE_AREA
TX_TIMER_INTERNAL *internal_ptr;
TX_TIMER_INTERNAL **list_head;
TX_TIMER_INTERNAL *next_timer;
TX_TIMER_INTERNAL *previous_timer;
ULONG ticks_left;
UINT active_timer_list;
/* Setup internal timer pointer. */
internal_ptr = &(timer_ptr -> tx_timer_internal);
/* Disable interrupts while the remaining time before expiration is
calculated. */
TX_DISABLE
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total deactivations counter. */
_tx_timer_performance_deactivate_count++;
/* Increment the number of deactivations on this timer. */
timer_ptr -> tx_timer_performance_deactivate_count++;
#endif
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_DEACTIVATE, timer_ptr, TX_POINTER_TO_ULONG_CONVERT(&ticks_left), 0, 0, TX_TRACE_TIMER_EVENTS)
/* Log this kernel call. */
TX_EL_TIMER_DEACTIVATE_INSERT
/* Pickup the list head. */
list_head = internal_ptr -> tx_timer_internal_list_head;
/* Is the timer active? */
if (list_head != TX_NULL)
{
/* Default the active timer list flag to false. */
active_timer_list = TX_FALSE;
/* Determine if the head pointer is within the timer expiration list. */
if (TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(list_head) >= TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(_tx_timer_list_start))
{
/* Now check to make sure the list head is before the end of the list. */
if (TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(list_head) < TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(_tx_timer_list_end))
{
/* Set the active timer list flag to true. */
active_timer_list = TX_TRUE;
}
}
/* Determine if the timer is on active timer list. */
if (active_timer_list == TX_TRUE)
{
/* This timer is active and has not yet expired. */
/* Calculate the amount of time that has elapsed since the timer
was activated. */
/* Is this timer's entry after the current timer pointer? */
if (TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(list_head) >= TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(_tx_timer_current_ptr))
{
/* Calculate ticks left to expiration - just the difference between this
timer's entry and the current timer pointer. */
ticks_left = (ULONG) (TX_TIMER_POINTER_DIF(list_head,_tx_timer_current_ptr)) + ((ULONG) 1);
}
else
{
/* Calculate the ticks left with a wrapped list condition. */
ticks_left = (ULONG) (TX_TIMER_POINTER_DIF(list_head,_tx_timer_list_start));
ticks_left = ticks_left + (ULONG) ((TX_TIMER_POINTER_DIF(_tx_timer_list_end, _tx_timer_current_ptr)) + ((ULONG) 1));
}
/* Adjust the remaining ticks accordingly. */
if (internal_ptr -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Subtract off the last full pass through the timer list and add the
time left. */
internal_ptr -> tx_timer_internal_remaining_ticks =
(internal_ptr -> tx_timer_internal_remaining_ticks - TX_TIMER_ENTRIES) + ticks_left;
}
else
{
/* Just put the ticks left into the timer's remaining ticks. */
internal_ptr -> tx_timer_internal_remaining_ticks = ticks_left;
}
}
else
{
/* Determine if this is timer has just expired. */
if (_tx_timer_expired_timer_ptr != internal_ptr)
{
/* No, it hasn't expired. Now check for remaining time greater than the list
size. */
if (internal_ptr -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Adjust the remaining ticks. */
internal_ptr -> tx_timer_internal_remaining_ticks =
internal_ptr -> tx_timer_internal_remaining_ticks - TX_TIMER_ENTRIES;
}
else
{
/* Set the remaining time to the reactivation time. */
internal_ptr -> tx_timer_internal_remaining_ticks = internal_ptr -> tx_timer_internal_re_initialize_ticks;
}
}
else
{
/* Set the remaining time to the reactivation time. */
internal_ptr -> tx_timer_internal_remaining_ticks = internal_ptr -> tx_timer_internal_re_initialize_ticks;
}
}
/* Pickup the next timer. */
next_timer = internal_ptr -> tx_timer_internal_active_next;
/* See if this is the only timer in the list. */
if (internal_ptr == next_timer)
{
/* Yes, the only timer on the list. */
/* Determine if the head pointer needs to be updated. */
if (*(list_head) == internal_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 = internal_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) == internal_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. */
internal_ptr -> tx_timer_internal_list_head = TX_NULL;
}
/* Restore interrupts to previous posture. */
TX_RESTORE
/* Return TX_SUCCESS. */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,144 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_delete PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function deletes the specified application timer. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Successful completion status */
/* */
/* CALLS */
/* */
/* _tx_timer_system_deactivate Timer deactivation function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_timer_delete(TX_TIMER *timer_ptr)
{
TX_INTERRUPT_SAVE_AREA
TX_TIMER *next_timer;
TX_TIMER *previous_timer;
/* Disable interrupts to remove the timer from the created list. */
TX_DISABLE
/* Determine if the timer needs to be deactivated. */
if (timer_ptr -> tx_timer_internal.tx_timer_internal_list_head != TX_NULL)
{
/* Yes, deactivate the timer before it is deleted. */
_tx_timer_system_deactivate(&(timer_ptr -> tx_timer_internal));
}
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_DELETE, timer_ptr, 0, 0, 0, TX_TRACE_TIMER_EVENTS)
/* Optional timer delete extended processing. */
TX_TIMER_DELETE_EXTENSION(timer_ptr)
/* If trace is enabled, unregister this object. */
TX_TRACE_OBJECT_UNREGISTER(timer_ptr)
/* Log this kernel call. */
TX_EL_TIMER_DELETE_INSERT
/* Clear the timer ID to make it invalid. */
timer_ptr -> tx_timer_id = TX_CLEAR_ID;
/* Decrement the number of created timers. */
_tx_timer_created_count--;
/* See if the timer is the only one on the list. */
if (_tx_timer_created_count == TX_EMPTY)
{
/* Only created timer, just set the created list to NULL. */
_tx_timer_created_ptr = TX_NULL;
}
else
{
/* Link-up the neighbors. */
next_timer = timer_ptr -> tx_timer_created_next;
previous_timer = timer_ptr -> tx_timer_created_previous;
next_timer -> tx_timer_created_previous = previous_timer;
previous_timer -> tx_timer_created_next = next_timer;
/* See if we have to update the created list head pointer. */
if (_tx_timer_created_ptr == timer_ptr)
{
/* Yes, move the head pointer to the next link. */
_tx_timer_created_ptr = next_timer;
}
}
/* Execute Port-Specific completion processing. If needed, it is typically defined in tx_port.h. */
TX_TIMER_DELETE_PORT_COMPLETION(timer_ptr)
/* Restore interrupts. */
TX_RESTORE
/* Return TX_SUCCESS. */
return(TX_SUCCESS);
}

View 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#ifndef TX_NO_TIMER
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_expiration_process PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes thread and application timer expirations. */
/* It is called from the _tx_timer_interrupt handler and either */
/* processes the timer expiration in the ISR or defers to the system */
/* timer thread. The actual processing is determined during */
/* compilation. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_system_resume Thread resume processing */
/* _tx_thread_system_ni_resume Non-interruptable resume thread */
/* _tx_timer_system_activate Timer reactivate processing */
/* Timer Expiration Function */
/* */
/* CALLED BY */
/* */
/* _tx_timer_interrupt Timer interrupt handler */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Scott Larson Modified comment(s), and */
/* opt out of function when */
/* TX_NO_TIMER is defined, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_timer_expiration_process(VOID)
{
TX_INTERRUPT_SAVE_AREA
#ifdef TX_TIMER_PROCESS_IN_ISR
TX_TIMER_INTERNAL *expired_timers;
TX_TIMER_INTERNAL *reactivate_timer;
TX_TIMER_INTERNAL *next_timer;
TX_TIMER_INTERNAL *previous_timer;
#ifdef TX_REACTIVATE_INLINE
TX_TIMER_INTERNAL **timer_list; /* Timer list pointer */
UINT expiration_time; /* Value used for pointer offset*/
ULONG delta;
#endif
TX_TIMER_INTERNAL *current_timer;
VOID (*timeout_function)(ULONG id);
ULONG timeout_param = ((ULONG) 0);
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
TX_TIMER *timer_ptr;
#endif
#endif
#ifndef TX_TIMER_PROCESS_IN_ISR
/* Don't process in the ISR, wakeup the system timer thread to process the
timer expiration. */
/* Disable interrupts. */
TX_DISABLE
#ifdef TX_NOT_INTERRUPTABLE
/* Resume the thread! */
_tx_thread_system_ni_resume(&_tx_timer_thread);
/* Restore interrupts. */
TX_RESTORE
#else
/* Increment the preempt disable flag. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Call the system resume function to activate the timer thread. */
_tx_thread_system_resume(&_tx_timer_thread);
#endif
#else
/* Process the timer expiration directly in the ISR. This increases the interrupt
processing, however, it eliminates the need for a system timer thread and associated
resources. */
/* Disable interrupts. */
TX_DISABLE
/* Determine if the timer processing is already active. This needs to be checked outside
of the processing loop because it remains set throughout nested timer interrupt conditions. */
if (_tx_timer_processing_active == TX_FALSE)
{
/* Timer processing is not nested. */
/* Determine if the timer expiration has already been cleared. */
if (_tx_timer_expired != ((UINT) 0))
{
/* Proceed with timer processing. */
/* Set the timer interrupt processing active flag. */
_tx_timer_processing_active = TX_TRUE;
/* Now go into an infinite loop to process timer expirations. */
do
{
/* First, move the current list pointer and clear the timer
expired value. This allows the interrupt handling portion
to continue looking for timer expirations. */
/* Save the current timer expiration list pointer. */
expired_timers = *_tx_timer_current_ptr;
/* Modify the head pointer in the first timer in the list, if there
is one! */
if (expired_timers != TX_NULL)
{
expired_timers -> tx_timer_internal_list_head = &expired_timers;
}
/* Set the current list pointer to NULL. */
*_tx_timer_current_ptr = TX_NULL;
/* Move the current pointer up one timer entry wrap if we get to
the end of the list. */
_tx_timer_current_ptr = TX_TIMER_POINTER_ADD(_tx_timer_current_ptr, 1);
if (_tx_timer_current_ptr == _tx_timer_list_end)
{
_tx_timer_current_ptr = _tx_timer_list_start;
}
/* Clear the expired flag. */
_tx_timer_expired = TX_FALSE;
/* Restore interrupts temporarily. */
TX_RESTORE
/* Disable interrupts again. */
TX_DISABLE
/* Next, process the expiration of the associated timers at this
time slot. */
while (expired_timers != TX_NULL)
{
/* Something is on the list. Remove it and process the expiration. */
current_timer = expired_timers;
/* Pickup the next timer. */
next_timer = expired_timers -> tx_timer_internal_active_next;
/* Set the reactivate timer to NULL. */
reactivate_timer = TX_NULL;
/* Determine if this is the only timer. */
if (current_timer == next_timer)
{
/* Yes, this is the only timer in the list. */
/* Set the head pointer to NULL. */
expired_timers = TX_NULL;
}
else
{
/* No, not the only expired timer. */
/* Remove this timer from the expired list. */
previous_timer = current_timer -> tx_timer_internal_active_previous;
next_timer -> tx_timer_internal_active_previous = previous_timer;
previous_timer -> tx_timer_internal_active_next = next_timer;
/* Modify the next timer's list head to point at the current list head. */
next_timer -> tx_timer_internal_list_head = &expired_timers;
/* Set the list head pointer. */
expired_timers = next_timer;
}
/* In any case, the timer is now off of the expired list. */
/* Determine if the timer has expired or if it is just a really
big timer that needs to be placed in the list again. */
if (current_timer -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Timer is bigger than the timer entries and must be
rescheduled. */
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total expiration adjustments counter. */
_tx_timer_performance__expiration_adjust_count++;
/* Determine if this is an application timer. */
if (current_timer -> tx_timer_internal_timeout_function != &_tx_thread_timeout)
{
/* Derive the application timer pointer. */
/* Pickup the application timer pointer. */
TX_USER_TIMER_POINTER_GET(current_timer, timer_ptr)
/* Increment the number of expiration adjustments on this timer. */
if (timer_ptr -> tx_timer_id == TX_TIMER_ID)
{
timer_ptr -> tx_timer_performance__expiration_adjust_count++;
}
}
#endif
/* Decrement the remaining ticks of the timer. */
current_timer -> tx_timer_internal_remaining_ticks =
current_timer -> tx_timer_internal_remaining_ticks - TX_TIMER_ENTRIES;
/* Set the timeout function to NULL in order to bypass the
expiration. */
timeout_function = TX_NULL;
/* Make the timer appear that it is still active while interrupts
are enabled. This will permit proper processing of a timer
deactivate from an ISR. */
current_timer -> tx_timer_internal_list_head = &reactivate_timer;
current_timer -> tx_timer_internal_active_next = current_timer;
/* Setup the temporary timer list head pointer. */
reactivate_timer = current_timer;
}
else
{
/* Timer did expire. */
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total expirations counter. */
_tx_timer_performance_expiration_count++;
/* Determine if this is an application timer. */
if (current_timer -> tx_timer_internal_timeout_function != &_tx_thread_timeout)
{
/* Derive the application timer pointer. */
/* Pickup the application timer pointer. */
TX_USER_TIMER_POINTER_GET(current_timer, timer_ptr)
/* Increment the number of expirations on this timer. */
if (timer_ptr -> tx_timer_id == TX_TIMER_ID)
{
timer_ptr -> tx_timer_performance_expiration_count++;
}
}
#endif
/* Copy the calling function and ID into local variables before interrupts
are re-enabled. */
timeout_function = current_timer -> tx_timer_internal_timeout_function;
timeout_param = current_timer -> tx_timer_internal_timeout_param;
/* Copy the reinitialize ticks into the remaining ticks. */
current_timer -> tx_timer_internal_remaining_ticks = current_timer -> tx_timer_internal_re_initialize_ticks;
/* Determine if the timer should be reactivated. */
if (current_timer -> tx_timer_internal_remaining_ticks != ((ULONG) 0))
{
/* Make the timer appear that it is still active while processing
the expiration routine and with interrupts enabled. This will
permit proper processing of a timer deactivate from both the
expiration routine and an ISR. */
current_timer -> tx_timer_internal_list_head = &reactivate_timer;
current_timer -> tx_timer_internal_active_next = current_timer;
/* Setup the temporary timer list head pointer. */
reactivate_timer = current_timer;
}
else
{
/* Set the list pointer of this timer to NULL. This is used to indicate
the timer is no longer active. */
current_timer -> tx_timer_internal_list_head = TX_NULL;
}
}
/* Set pointer to indicate the expired timer that is currently being processed. */
_tx_timer_expired_timer_ptr = current_timer;
/* Restore interrupts for timer expiration call. */
TX_RESTORE
/* Call the timer-expiration function, if non-NULL. */
if (timeout_function != TX_NULL)
{
(timeout_function) (timeout_param);
}
/* Lockout interrupts again. */
TX_DISABLE
/* Clear expired timer pointer. */
_tx_timer_expired_timer_ptr = TX_NULL;
/* Determine if the timer needs to be reactivated. */
if (reactivate_timer == current_timer)
{
/* Reactivate the timer. */
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Determine if this timer expired. */
if (timeout_function != TX_NULL)
{
/* Increment the total reactivations counter. */
_tx_timer_performance_reactivate_count++;
/* Determine if this is an application timer. */
if (current_timer -> tx_timer_internal_timeout_function != &_tx_thread_timeout)
{
/* Derive the application timer pointer. */
/* Pickup the application timer pointer. */
TX_USER_TIMER_POINTER_GET(current_timer, timer_ptr)
/* Increment the number of expirations on this timer. */
if (timer_ptr -> tx_timer_id == TX_TIMER_ID)
{
timer_ptr -> tx_timer_performance_reactivate_count++;
}
}
}
#endif
#ifdef TX_REACTIVATE_INLINE
/* Calculate the amount of time remaining for the timer. */
if (current_timer -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Set expiration time to the maximum number of entries. */
expiration_time = TX_TIMER_ENTRIES - ((UINT) 1);
}
else
{
/* Timer value fits in the timer entries. */
/* Set the expiration time. */
expiration_time = ((UINT) current_timer -> tx_timer_internal_remaining_ticks) - ((UINT) 1);
}
/* At this point, we are ready to put the timer back on one of
the timer lists. */
/* Calculate the proper place for the timer. */
timer_list = TX_TIMER_POINTER_ADD(_tx_timer_current_ptr, expiration_time);
if (TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(timer_list) >= TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(_tx_timer_list_end))
{
/* Wrap from the beginning of the list. */
delta = TX_TIMER_POINTER_DIF(timer_list, _tx_timer_list_end);
timer_list = TX_TIMER_POINTER_ADD(_tx_timer_list_start, delta);
}
/* Now put the timer on this list. */
if ((*timer_list) == TX_NULL)
{
/* This list is NULL, just put the new timer on it. */
/* Setup the links in this timer. */
current_timer -> tx_timer_internal_active_next = current_timer;
current_timer -> tx_timer_internal_active_previous = current_timer;
/* Setup the list head pointer. */
*timer_list = current_timer;
}
else
{
/* This list is not NULL, add current timer to the end. */
next_timer = *timer_list;
previous_timer = next_timer -> tx_timer_internal_active_previous;
previous_timer -> tx_timer_internal_active_next = current_timer;
next_timer -> tx_timer_internal_active_previous = current_timer;
current_timer -> tx_timer_internal_active_next = next_timer;
current_timer -> tx_timer_internal_active_previous = previous_timer;
}
/* Setup list head pointer. */
current_timer -> tx_timer_internal_list_head = timer_list;
#else
/* Reactivate through the timer activate function. */
/* Clear the list head for the timer activate call. */
current_timer -> tx_timer_internal_list_head = TX_NULL;
/* Activate the current timer. */
_tx_timer_system_activate(current_timer);
#endif
}
}
} while (_tx_timer_expired != TX_FALSE);
/* Clear the timer interrupt processing active flag. */
_tx_timer_processing_active = TX_FALSE;
}
}
/* Restore interrupts. */
TX_RESTORE
#endif
}
#endif

View File

@@ -0,0 +1,250 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_trace.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_info_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function retrieves information from the specified timer. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* name Destination for the timer name */
/* active Destination for active flag */
/* remaining_ticks Destination for remaining ticks */
/* before expiration */
/* reschedule_ticks Destination for reschedule ticks */
/* next_timer Destination for next timer on the */
/* created list */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _tx_timer_info_get(TX_TIMER *timer_ptr, CHAR **name, UINT *active, ULONG *remaining_ticks,
ULONG *reschedule_ticks, TX_TIMER **next_timer)
{
TX_INTERRUPT_SAVE_AREA
TX_TIMER_INTERNAL *internal_ptr;
TX_TIMER_INTERNAL **list_head;
ULONG ticks_left;
UINT timer_active;
UINT active_timer_list;
/* Disable interrupts. */
TX_DISABLE
/* If trace is enabled, insert this event into the trace buffer. */
TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_INFO_GET, timer_ptr, TX_POINTER_TO_ULONG_CONVERT(&ticks_left), 0, 0, TX_TRACE_TIMER_EVENTS)
/* Log this kernel call. */
TX_EL_TIMER_INFO_GET_INSERT
/* Retrieve the name of the timer. */
if (name != TX_NULL)
{
*name = timer_ptr -> tx_timer_name;
}
/* Pickup address of internal timer structure. */
internal_ptr = &(timer_ptr -> tx_timer_internal);
/* Retrieve all the pertinent information and return it in the supplied
destinations. */
/* Default active to false. */
timer_active = TX_FALSE;
/* Default the ticks left to the remaining ticks. */
ticks_left = internal_ptr -> tx_timer_internal_remaining_ticks;
/* Determine if the timer is still active. */
if (internal_ptr -> tx_timer_internal_list_head != TX_NULL)
{
/* Indicate this timer is active. */
timer_active = TX_TRUE;
/* Default the active timer list flag to false. */
active_timer_list = TX_FALSE;
/* Determine if the timer is still active. */
if (internal_ptr -> tx_timer_internal_list_head >= _tx_timer_list_start)
{
/* Determine if the list head is before the end of the list. */
if (internal_ptr -> tx_timer_internal_list_head < _tx_timer_list_end)
{
/* This timer is active and has not yet expired. */
active_timer_list = TX_TRUE;
}
}
/* Determine if the timer is on the active timer list. */
if (active_timer_list == TX_TRUE)
{
/* Calculate the amount of time that has elapsed since the timer
was activated. */
/* Setup the list head pointer. */
list_head = internal_ptr -> tx_timer_internal_list_head;
/* Is this timer's entry after the current timer pointer? */
if (internal_ptr -> tx_timer_internal_list_head >= _tx_timer_current_ptr)
{
/* Calculate ticks left to expiration - just the difference between this
timer's entry and the current timer pointer. */
ticks_left = ((TX_TIMER_POINTER_DIF(list_head, _tx_timer_current_ptr)) + ((ULONG) 1));
}
else
{
/* Calculate the ticks left with a wrapped list condition. */
ticks_left = ((TX_TIMER_POINTER_DIF(list_head, _tx_timer_list_start)));
ticks_left = ticks_left + ((TX_TIMER_POINTER_DIF(_tx_timer_list_end, _tx_timer_current_ptr)) + ((ULONG) 1));
}
/* Adjust the remaining ticks accordingly. */
if (internal_ptr -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Subtract off the last full pass through the timer list and add the
time left. */
ticks_left = (internal_ptr -> tx_timer_internal_remaining_ticks - TX_TIMER_ENTRIES) + ticks_left;
}
}
else
{
/* The timer is not on the actual timer list so it must either be being processed
or on a temporary list to be processed. */
/* Check to see if this timer is the timer currently being processed. */
if (_tx_timer_expired_timer_ptr == internal_ptr)
{
/* Timer dispatch routine is executing, waiting to execute, or just finishing. No more remaining ticks for this expiration. */
ticks_left = ((ULONG) 0);
}
else
{
/* Timer is not the one being processed, which means it must be on the temporary expiration list
waiting to be processed. */
/* Calculate the remaining ticks for a timer in the process of expiring. */
if (ticks_left > TX_TIMER_ENTRIES)
{
/* Calculate the number of ticks remaining. */
ticks_left = internal_ptr -> tx_timer_internal_remaining_ticks - TX_TIMER_ENTRIES;
}
else
{
/* Timer dispatch routine is waiting to execute, no more remaining ticks for this expiration. */
ticks_left = ((ULONG) 0);
}
}
}
}
/* Setup return values for an inactive timer. */
if (active != TX_NULL)
{
/* Setup the timer active indication. */
*active = timer_active;
}
if (remaining_ticks != TX_NULL)
{
/* Setup the default remaining ticks value. */
*remaining_ticks = ticks_left;
}
/* Pickup the reschedule ticks value. */
if (reschedule_ticks != TX_NULL)
{
*reschedule_ticks = internal_ptr -> tx_timer_internal_re_initialize_ticks;
}
/* Pickup the next created application timer. */
if (next_timer != TX_NULL)
{
*next_timer = timer_ptr -> tx_timer_created_next;
}
/* Restore interrupts. */
TX_RESTORE
/* Return completion status. */
return(TX_SUCCESS);
}

View File

@@ -0,0 +1,306 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/* Check for the TX_NO_TIMER option. When defined, do not define all of the
timer component global variables. */
#ifndef TX_NO_TIMER
/* Define the system clock value that is continually incremented by the
periodic timer interrupt processing. */
volatile ULONG _tx_timer_system_clock;
/* Define the time-slice expiration flag. This is used to indicate that a time-slice
has happened. */
UINT _tx_timer_expired_time_slice;
/* Define the thread and application timer entry list. This list provides a direct access
method for insertion of times less than TX_TIMER_ENTRIES. */
TX_TIMER_INTERNAL *_tx_timer_list[TX_TIMER_ENTRIES];
/* Define the boundary pointers to the list. These are setup to easily manage
wrapping the list. */
TX_TIMER_INTERNAL **_tx_timer_list_start;
TX_TIMER_INTERNAL **_tx_timer_list_end;
/* Define the current timer pointer in the list. This pointer is moved sequentially
through the timer list by the timer interrupt handler. */
TX_TIMER_INTERNAL **_tx_timer_current_ptr;
/* Define the timer expiration flag. This is used to indicate that a timer
has expired. */
UINT _tx_timer_expired;
/* Define the created timer list head pointer. */
TX_TIMER *_tx_timer_created_ptr;
/* Define the created timer count. */
ULONG _tx_timer_created_count;
/* Define the pointer to the timer that has expired and is being processed. */
TX_TIMER_INTERNAL *_tx_timer_expired_timer_ptr;
#ifndef TX_TIMER_PROCESS_IN_ISR
/* Define the timer thread's control block. */
TX_THREAD _tx_timer_thread;
/* Define the variable that holds the timer thread's starting stack address. */
VOID *_tx_timer_stack_start;
/* Define the variable that holds the timer thread's stack size. */
ULONG _tx_timer_stack_size;
/* Define the variable that holds the timer thread's priority. */
UINT _tx_timer_priority;
/* Define the system timer thread's stack. The default size is defined
in tx_port.h. */
ULONG _tx_timer_thread_stack_area[(((UINT) TX_TIMER_THREAD_STACK_SIZE)+((sizeof(ULONG))- ((UINT) 1)))/(sizeof(ULONG))];
#else
/* Define the busy flag that will prevent nested timer ISR processing. */
UINT _tx_timer_processing_active;
#endif
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Define the total number of timer activations. */
ULONG _tx_timer_performance_activate_count;
/* Define the total number of timer reactivations. */
ULONG _tx_timer_performance_reactivate_count;
/* Define the total number of timer deactivations. */
ULONG _tx_timer_performance_deactivate_count;
/* Define the total number of timer expirations. */
ULONG _tx_timer_performance_expiration_count;
/* Define the total number of timer expiration adjustments. These are required
if the expiration time is greater than the size of the timer list. In such
cases, the timer is placed at the end of the list and then reactivated
as many times as necessary to finally achieve the resulting timeout. */
ULONG _tx_timer_performance__expiration_adjust_count;
#endif
#endif
/* Define the current time slice value. If non-zero, a time-slice is active.
Otherwise, the time_slice is not active. */
ULONG _tx_timer_time_slice;
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_initialize PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function initializes the various control data structures for */
/* the clock control component. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_thread_create Create the system timer thread */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_high_level High level initialization */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_timer_initialize(VOID)
{
#ifndef TX_NO_TIMER
#ifndef TX_TIMER_PROCESS_IN_ISR
UINT status;
#endif
#ifndef TX_DISABLE_REDUNDANT_CLEARING
/* Initialize the system clock to 0. */
_tx_timer_system_clock = ((ULONG) 0);
/* Initialize the time-slice value to 0 to make sure it is disabled. */
_tx_timer_time_slice = ((ULONG) 0);
/* Clear the expired flags. */
_tx_timer_expired_time_slice = TX_FALSE;
_tx_timer_expired = TX_FALSE;
/* Set the currently expired timer being processed pointer to NULL. */
_tx_timer_expired_timer_ptr = TX_NULL;
/* Initialize the thread and application timer management control structures. */
/* First, initialize the timer list. */
TX_MEMSET(&_tx_timer_list[0], 0, (sizeof(_tx_timer_list)));
#endif
/* Initialize all of the list pointers. */
_tx_timer_list_start = &_tx_timer_list[0];
_tx_timer_current_ptr = &_tx_timer_list[0];
/* Set the timer list end pointer to one past the actual timer list. This is done
to make the timer interrupt handling in assembly language a little easier. */
_tx_timer_list_end = &_tx_timer_list[TX_TIMER_ENTRIES-((ULONG) 1)];
_tx_timer_list_end = TX_TIMER_POINTER_ADD(_tx_timer_list_end, ((ULONG) 1));
#ifndef TX_TIMER_PROCESS_IN_ISR
/* Setup the variables associated with the system timer thread's stack and
priority. */
_tx_timer_stack_start = (VOID *) &_tx_timer_thread_stack_area[0];
_tx_timer_stack_size = ((ULONG) TX_TIMER_THREAD_STACK_SIZE);
_tx_timer_priority = ((UINT) TX_TIMER_THREAD_PRIORITY);
/* Create the system timer thread. This thread processes all of the timer
expirations and reschedules. Its stack and priority are defined in the
low-level initialization component. */
do
{
/* Create the system timer thread. */
status = _tx_thread_create(&_tx_timer_thread,
TX_CONST_CHAR_TO_CHAR_POINTER_CONVERT("System Timer Thread"),
_tx_timer_thread_entry,
((ULONG) TX_TIMER_ID),
_tx_timer_stack_start, _tx_timer_stack_size,
_tx_timer_priority, _tx_timer_priority, TX_NO_TIME_SLICE, TX_DONT_START);
#ifdef TX_SAFETY_CRITICAL
/* Check return from thread create - if an error is detected throw an exception. */
if (status != TX_SUCCESS)
{
/* Raise safety critical exception. */
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, status);
}
#endif
/* Define timer initialize extension. */
TX_TIMER_INITIALIZE_EXTENSION(status)
} while (status != TX_SUCCESS);
#else
/* Clear the timer interrupt processing active flag. */
_tx_timer_processing_active = TX_FALSE;
#endif
#ifndef TX_DISABLE_REDUNDANT_CLEARING
/* Initialize the head pointer of the created application timer list. */
_tx_timer_created_ptr = TX_NULL;
/* Set the created count to zero. */
_tx_timer_created_count = TX_EMPTY;
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Initialize timer performance counters. */
_tx_timer_performance_activate_count = ((ULONG) 0);
_tx_timer_performance_reactivate_count = ((ULONG) 0);
_tx_timer_performance_deactivate_count = ((ULONG) 0);
_tx_timer_performance_expiration_count = ((ULONG) 0);
_tx_timer_performance__expiration_adjust_count = ((ULONG) 0);
#endif
#endif
#endif
}

View 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#ifndef TX_NO_TIMER
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_system_activate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function places the specified internal timer in the proper */
/* place in the timer expiration list. If the timer is already active */
/* this function does nothing. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Always returns success */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_system_suspend Thread suspend function */
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
/* _tx_timer_thread_entry Timer thread processing */
/* _tx_timer_activate Application timer activate */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Scott Larson Modified comment(s), and */
/* opt out of function when */
/* TX_NO_TIMER is defined, */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_timer_system_activate(TX_TIMER_INTERNAL *timer_ptr)
{
TX_TIMER_INTERNAL **timer_list;
TX_TIMER_INTERNAL *next_timer;
TX_TIMER_INTERNAL *previous_timer;
ULONG delta;
ULONG remaining_ticks;
ULONG expiration_time;
/* Pickup the remaining ticks. */
remaining_ticks = timer_ptr -> tx_timer_internal_remaining_ticks;
/* Determine if there is a timer to activate. */
if (remaining_ticks != ((ULONG) 0))
{
/* Determine if the timer is set to wait forever. */
if (remaining_ticks != TX_WAIT_FOREVER)
{
/* Valid timer activate request. */
/* Determine if the timer still needs activation. */
if (timer_ptr -> tx_timer_internal_list_head == TX_NULL)
{
/* Activate the timer. */
/* Calculate the amount of time remaining for the timer. */
if (remaining_ticks > TX_TIMER_ENTRIES)
{
/* Set expiration time to the maximum number of entries. */
expiration_time = TX_TIMER_ENTRIES - ((ULONG) 1);
}
else
{
/* Timer value fits in the timer entries. */
/* Set the expiration time. */
expiration_time = (remaining_ticks - ((ULONG) 1));
}
/* At this point, we are ready to put the timer on one of
the timer lists. */
/* Calculate the proper place for the timer. */
timer_list = TX_TIMER_POINTER_ADD(_tx_timer_current_ptr, expiration_time);
if (TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(timer_list) >= TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(_tx_timer_list_end))
{
/* Wrap from the beginning of the list. */
delta = TX_TIMER_POINTER_DIF(timer_list, _tx_timer_list_end);
timer_list = TX_TIMER_POINTER_ADD(_tx_timer_list_start, delta);
}
/* Now put the timer on this list. */
if ((*timer_list) == TX_NULL)
{
/* This list is NULL, just put the new timer on it. */
/* Setup the links in this timer. */
timer_ptr -> tx_timer_internal_active_next = timer_ptr;
timer_ptr -> tx_timer_internal_active_previous = timer_ptr;
/* Setup the list head pointer. */
*timer_list = timer_ptr;
}
else
{
/* This list is not NULL, add current timer to the end. */
next_timer = *timer_list;
previous_timer = next_timer -> tx_timer_internal_active_previous;
previous_timer -> tx_timer_internal_active_next = timer_ptr;
next_timer -> tx_timer_internal_active_previous = timer_ptr;
timer_ptr -> tx_timer_internal_active_next = next_timer;
timer_ptr -> tx_timer_internal_active_previous = previous_timer;
}
/* Setup list head pointer. */
timer_ptr -> tx_timer_internal_list_head = timer_list;
}
}
}
}
#endif

View File

@@ -0,0 +1,134 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_system_deactivate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function deactivates, or removes the timer from the active */
/* timer expiration list. If the timer is already deactivated, this */
/* function just returns. */
/* */
/* INPUT */
/* */
/* timer_ptr Pointer to timer control block */
/* */
/* OUTPUT */
/* */
/* TX_SUCCESS Always returns success */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_thread_system_resume Thread resume function */
/* _tx_timer_thread_entry Timer thread processing */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
VOID _tx_timer_system_deactivate(TX_TIMER_INTERNAL *timer_ptr)
{
TX_TIMER_INTERNAL **list_head;
TX_TIMER_INTERNAL *next_timer;
TX_TIMER_INTERNAL *previous_timer;
/* Pickup the list head pointer. */
list_head = timer_ptr -> tx_timer_internal_list_head;
/* Determine if the timer still needs deactivation. */
if (list_head != TX_NULL)
{
/* Deactivate the timer. */
/* 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;
}
}

View File

@@ -0,0 +1,482 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_thread_entry PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function manages thread and application timer expirations. */
/* Actually, from this thread's point of view, there is no difference. */
/* */
/* INPUT */
/* */
/* timer_thread_input Used just for verification */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* Timer Expiration Function */
/* _tx_thread_system_suspend Thread suspension */
/* _tx_thread_system_ni_suspend Non-interruptable suspend thread */
/* _tx_timer_system_activate Timer reactivate processing */
/* */
/* CALLED BY */
/* */
/* ThreadX Scheduler */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
#ifndef TX_TIMER_PROCESS_IN_ISR
VOID _tx_timer_thread_entry(ULONG timer_thread_input)
{
TX_INTERRUPT_SAVE_AREA
TX_TIMER_INTERNAL *expired_timers;
TX_TIMER_INTERNAL *reactivate_timer;
TX_TIMER_INTERNAL *next_timer;
TX_TIMER_INTERNAL *previous_timer;
TX_TIMER_INTERNAL *current_timer;
VOID (*timeout_function)(ULONG id);
ULONG timeout_param = ((ULONG) 0);
TX_THREAD *thread_ptr;
#ifdef TX_REACTIVATE_INLINE
TX_TIMER_INTERNAL **timer_list; /* Timer list pointer */
UINT expiration_time; /* Value used for pointer offset*/
ULONG delta;
#endif
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
TX_TIMER *timer_ptr;
#endif
/* Make sure the timer input is correct. This also gets rid of the
silly compiler warnings. */
if (timer_thread_input == TX_TIMER_ID)
{
/* Yes, valid thread entry, proceed... */
/* Now go into an infinite loop to process timer expirations. */
while (TX_LOOP_FOREVER)
{
/* First, move the current list pointer and clear the timer
expired value. This allows the interrupt handling portion
to continue looking for timer expirations. */
TX_DISABLE
/* Save the current timer expiration list pointer. */
expired_timers = *_tx_timer_current_ptr;
/* Modify the head pointer in the first timer in the list, if there
is one! */
if (expired_timers != TX_NULL)
{
expired_timers -> tx_timer_internal_list_head = &expired_timers;
}
/* Set the current list pointer to NULL. */
*_tx_timer_current_ptr = TX_NULL;
/* Move the current pointer up one timer entry wrap if we get to
the end of the list. */
_tx_timer_current_ptr = TX_TIMER_POINTER_ADD(_tx_timer_current_ptr, 1);
if (_tx_timer_current_ptr == _tx_timer_list_end)
{
_tx_timer_current_ptr = _tx_timer_list_start;
}
/* Clear the expired flag. */
_tx_timer_expired = TX_FALSE;
/* Restore interrupts temporarily. */
TX_RESTORE
/* Disable interrupts again. */
TX_DISABLE
/* Next, process the expiration of the associated timers at this
time slot. */
while (expired_timers != TX_NULL)
{
/* Something is on the list. Remove it and process the expiration. */
current_timer = expired_timers;
/* Pickup the next timer. */
next_timer = expired_timers -> tx_timer_internal_active_next;
/* Set the reactivate_timer to NULL. */
reactivate_timer = TX_NULL;
/* Determine if this is the only timer. */
if (current_timer == next_timer)
{
/* Yes, this is the only timer in the list. */
/* Set the head pointer to NULL. */
expired_timers = TX_NULL;
}
else
{
/* No, not the only expired timer. */
/* Remove this timer from the expired list. */
previous_timer = current_timer -> tx_timer_internal_active_previous;
next_timer -> tx_timer_internal_active_previous = previous_timer;
previous_timer -> tx_timer_internal_active_next = next_timer;
/* Modify the next timer's list head to point at the current list head. */
next_timer -> tx_timer_internal_list_head = &expired_timers;
/* Set the list head pointer. */
expired_timers = next_timer;
}
/* In any case, the timer is now off of the expired list. */
/* Determine if the timer has expired or if it is just a really
big timer that needs to be placed in the list again. */
if (current_timer -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Timer is bigger than the timer entries and must be
rescheduled. */
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total expiration adjustments counter. */
_tx_timer_performance__expiration_adjust_count++;
/* Determine if this is an application timer. */
if (current_timer -> tx_timer_internal_timeout_function != &_tx_thread_timeout)
{
/* Derive the application timer pointer. */
/* Pickup the application timer pointer. */
TX_USER_TIMER_POINTER_GET(current_timer, timer_ptr)
/* Increment the number of expiration adjustments on this timer. */
if (timer_ptr -> tx_timer_id == TX_TIMER_ID)
{
timer_ptr -> tx_timer_performance__expiration_adjust_count++;
}
}
#endif
/* Decrement the remaining ticks of the timer. */
current_timer -> tx_timer_internal_remaining_ticks =
current_timer -> tx_timer_internal_remaining_ticks - TX_TIMER_ENTRIES;
/* Set the timeout function to NULL in order to bypass the
expiration. */
timeout_function = TX_NULL;
/* Make the timer appear that it is still active while interrupts
are enabled. This will permit proper processing of a timer
deactivate from an ISR. */
current_timer -> tx_timer_internal_list_head = &reactivate_timer;
current_timer -> tx_timer_internal_active_next = current_timer;
/* Setup the temporary timer list head pointer. */
reactivate_timer = current_timer;
}
else
{
/* Timer did expire. */
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Increment the total expirations counter. */
_tx_timer_performance_expiration_count++;
/* Determine if this is an application timer. */
if (current_timer -> tx_timer_internal_timeout_function != &_tx_thread_timeout)
{
/* Derive the application timer pointer. */
/* Pickup the application timer pointer. */
TX_USER_TIMER_POINTER_GET(current_timer, timer_ptr)
/* Increment the number of expirations on this timer. */
if (timer_ptr -> tx_timer_id == TX_TIMER_ID)
{
timer_ptr -> tx_timer_performance_expiration_count++;
}
}
#endif
/* Copy the calling function and ID into local variables before interrupts
are re-enabled. */
timeout_function = current_timer -> tx_timer_internal_timeout_function;
timeout_param = current_timer -> tx_timer_internal_timeout_param;
/* Copy the reinitialize ticks into the remaining ticks. */
current_timer -> tx_timer_internal_remaining_ticks = current_timer -> tx_timer_internal_re_initialize_ticks;
/* Determine if the timer should be reactivated. */
if (current_timer -> tx_timer_internal_remaining_ticks != ((ULONG) 0))
{
/* Make the timer appear that it is still active while processing
the expiration routine and with interrupts enabled. This will
permit proper processing of a timer deactivate from both the
expiration routine and an ISR. */
current_timer -> tx_timer_internal_list_head = &reactivate_timer;
current_timer -> tx_timer_internal_active_next = current_timer;
/* Setup the temporary timer list head pointer. */
reactivate_timer = current_timer;
}
else
{
/* Set the list pointer of this timer to NULL. This is used to indicate
the timer is no longer active. */
current_timer -> tx_timer_internal_list_head = TX_NULL;
}
}
/* Set pointer to indicate the expired timer that is currently being processed. */
_tx_timer_expired_timer_ptr = current_timer;
/* Restore interrupts for timer expiration call. */
TX_RESTORE
/* Call the timer-expiration function, if non-NULL. */
if (timeout_function != TX_NULL)
{
(timeout_function) (timeout_param);
}
/* Lockout interrupts again. */
TX_DISABLE
/* Clear expired timer pointer. */
_tx_timer_expired_timer_ptr = TX_NULL;
/* Determine if the timer needs to be reactivated. */
if (reactivate_timer == current_timer)
{
/* Reactivate the timer. */
#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO
/* Determine if this timer expired. */
if (timeout_function != TX_NULL)
{
/* Increment the total reactivations counter. */
_tx_timer_performance_reactivate_count++;
/* Determine if this is an application timer. */
if (current_timer -> tx_timer_internal_timeout_function != &_tx_thread_timeout)
{
/* Derive the application timer pointer. */
/* Pickup the application timer pointer. */
TX_USER_TIMER_POINTER_GET(current_timer, timer_ptr)
/* Increment the number of expirations on this timer. */
if (timer_ptr -> tx_timer_id == TX_TIMER_ID)
{
timer_ptr -> tx_timer_performance_reactivate_count++;
}
}
}
#endif
#ifdef TX_REACTIVATE_INLINE
/* Calculate the amount of time remaining for the timer. */
if (current_timer -> tx_timer_internal_remaining_ticks > TX_TIMER_ENTRIES)
{
/* Set expiration time to the maximum number of entries. */
expiration_time = TX_TIMER_ENTRIES - ((UINT) 1);
}
else
{
/* Timer value fits in the timer entries. */
/* Set the expiration time. */
expiration_time = ((UINT) current_timer -> tx_timer_internal_remaining_ticks) - ((UINT) 1);
}
/* At this point, we are ready to put the timer back on one of
the timer lists. */
/* Calculate the proper place for the timer. */
timer_list = TX_TIMER_POINTER_ADD(_tx_timer_current_ptr, expiration_time);
if (TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(timer_list) >= TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(_tx_timer_list_end))
{
/* Wrap from the beginning of the list. */
delta = TX_TIMER_POINTER_DIF(timer_list, _tx_timer_list_end);
timer_list = TX_TIMER_POINTER_ADD(_tx_timer_list_start, delta);
}
/* Now put the timer on this list. */
if ((*timer_list) == TX_NULL)
{
/* This list is NULL, just put the new timer on it. */
/* Setup the links in this timer. */
current_timer -> tx_timer_internal_active_next = current_timer;
current_timer -> tx_timer_internal_active_previous = current_timer;
/* Setup the list head pointer. */
*timer_list = current_timer;
}
else
{
/* This list is not NULL, add current timer to the end. */
next_timer = *timer_list;
previous_timer = next_timer -> tx_timer_internal_active_previous;
previous_timer -> tx_timer_internal_active_next = current_timer;
next_timer -> tx_timer_internal_active_previous = current_timer;
current_timer -> tx_timer_internal_active_next = next_timer;
current_timer -> tx_timer_internal_active_previous = previous_timer;
}
/* Setup list head pointer. */
current_timer -> tx_timer_internal_list_head = timer_list;
#else
/* Reactivate through the timer activate function. */
/* Clear the list head for the timer activate call. */
current_timer -> tx_timer_internal_list_head = TX_NULL;
/* Activate the current timer. */
_tx_timer_system_activate(current_timer);
#endif
}
/* Restore interrupts. */
TX_RESTORE
/* Lockout interrupts again. */
TX_DISABLE
}
/* Finally, suspend this thread and wait for the next expiration. */
/* Determine if another expiration took place while we were in this
thread. If so, process another expiration. */
if (_tx_timer_expired == TX_FALSE)
{
/* Otherwise, no timer expiration, so suspend the thread. */
/* Build pointer to the timer thread. */
thread_ptr = &_tx_timer_thread;
/* Set the status to suspending, in order to indicate the
suspension is in progress. */
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;
/* Increment the preempt disable count prior to suspending. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Call actual thread suspension routine. */
_tx_thread_system_suspend(thread_ptr);
#endif
}
else
{
/* Restore interrupts. */
TX_RESTORE
}
}
}
#ifdef TX_SAFETY_CRITICAL
/* If we ever get here, raise safety critical exception. */
TX_SAFETY_CRITICAL_EXCEPTION(__FILE__, __LINE__, 0);
#endif
}
#endif

View File

@@ -0,0 +1,162 @@
/**************************************************************************/
/* */
/* 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_timer.h"
#include "tx_block_pool.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txe_block_allocate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the allocate block memory */
/* function call. */
/* */
/* INPUT */
/* */
/* pool_ptr Pointer to pool control block */
/* block_ptr Pointer to place allocated block */
/* pointer */
/* wait_option Suspension option */
/* */
/* OUTPUT */
/* */
/* TX_POOL_ERROR Invalid pool pointer */
/* TX_PTR_ERROR Invalid destination pointer */
/* TX_WAIT_ERROR Invalid wait option */
/* status Actual Completion status */
/* */
/* CALLS */
/* */
/* _tx_block_allocate Actual block allocate function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _txe_block_allocate(TX_BLOCK_POOL *pool_ptr, VOID **block_ptr, ULONG wait_option)
{
UINT status;
#ifndef TX_TIMER_PROCESS_IN_ISR
TX_THREAD *current_thread;
#endif
/* Default status to success. */
status = TX_SUCCESS;
/* Check for an invalid pool pointer. */
if (pool_ptr == TX_NULL)
{
/* Pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Check for an invalid pool pointer. */
else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID)
{
/* Pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Check for an invalid destination for return pointer. */
else if (block_ptr == TX_NULL)
{
/* Null destination pointer, return appropriate error. */
status = TX_PTR_ERROR;
}
else
{
/* Check for a wait option error. Only threads are allowed any form of
suspension. */
if (wait_option != TX_NO_WAIT)
{
/* Is the call from an ISR or Initialization? */
if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
{
/* A non-thread is trying to suspend, return appropriate error code. */
status = TX_WAIT_ERROR;
}
#ifndef TX_TIMER_PROCESS_IN_ISR
else
{
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(current_thread)
/* Is the current thread the timer thread? */
if (current_thread == &_tx_timer_thread)
{
/* A non-thread is trying to suspend, return appropriate error code. */
status = TX_WAIT_ERROR;
}
}
#endif
}
}
/* Determine if everything is okay. */
if (status == TX_SUCCESS)
{
/* Call actual block allocate function. */
status = _tx_block_allocate(pool_ptr, block_ptr, wait_option);
}
/* Return completion status. */
return(status);
}

View 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 */
/** */
/** Block Pool */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_initialize.h"
#include "tx_thread.h"
#include "tx_timer.h"
#include "tx_block_pool.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txe_block_pool_create PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the create block memory pool */
/* function call. */
/* */
/* 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 */
/* pool_control_block_size Size of block pool control block */
/* */
/* OUTPUT */
/* */
/* TX_POOL_ERROR Invalid pool pointer */
/* TX_PTR_ERROR Invalid starting address */
/* TX_SIZE_ERROR Invalid pool size */
/* TX_CALLER_ERROR Invalid caller of pool */
/* status Actual completion status */
/* */
/* CALLS */
/* */
/* _tx_block_pool_create Actual block pool create function */
/* _tx_thread_system_preempt_check Check for preemption */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _txe_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size,
VOID *pool_start, ULONG pool_size, UINT pool_control_block_size)
{
TX_INTERRUPT_SAVE_AREA
UINT status;
ULONG i;
TX_BLOCK_POOL *next_pool;
#ifndef TX_TIMER_PROCESS_IN_ISR
TX_THREAD *thread_ptr;
#endif
/* Default status to success. */
status = TX_SUCCESS;
/* Check for an invalid pool pointer. */
if (pool_ptr == TX_NULL)
{
/* Pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Check for invalid control block size. */
else if (pool_control_block_size != (sizeof(TX_BLOCK_POOL)))
{
/* Pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
else
{
/* Disable interrupts. */
TX_DISABLE
/* Increment the preempt disable flag. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Next see if it is already in the created list. */
next_pool = _tx_block_pool_created_ptr;
for (i = ((ULONG) 0); i < _tx_block_pool_created_count; i++)
{
/* Determine if this block pool matches the pool in the list. */
if (pool_ptr == next_pool)
{
break;
}
else
{
/* Move to the next pool. */
next_pool = next_pool -> tx_block_pool_created_next;
}
}
/* Disable interrupts. */
TX_DISABLE
/* Decrement the preempt disable flag. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
/* Check for preemption. */
_tx_thread_system_preempt_check();
/* At this point, check to see if there is a duplicate pool. */
if (pool_ptr == next_pool)
{
/* Pool is already created, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Check for an invalid starting address. */
else if (pool_start == TX_NULL)
{
/* Null starting address pointer, return appropriate error. */
status = TX_PTR_ERROR;
}
else
{
/* Check for invalid pool size. */
if ((((block_size/(sizeof(void *)))*(sizeof(void *))) + (sizeof(void *))) >
((pool_size/(sizeof(void *)))*(sizeof(void *))))
{
/* Not enough memory for one block, return appropriate error. */
status = TX_SIZE_ERROR;
}
else
{
#ifndef TX_TIMER_PROCESS_IN_ISR
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(thread_ptr)
/* Check for invalid caller of this function. First check for a calling thread. */
if (thread_ptr == &_tx_timer_thread)
{
/* Invalid caller of this function, return appropriate error code. */
status = TX_CALLER_ERROR;
}
#endif
/* Check for interrupt call. */
if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
{
/* Now, make sure the call is from an interrupt and not initialization. */
if (TX_THREAD_GET_SYSTEM_STATE() < TX_INITIALIZE_IN_PROGRESS)
{
/* Invalid caller of this function, return appropriate error code. */
status = TX_CALLER_ERROR;
}
}
}
}
}
/* Determine if everything is okay. */
if (status == TX_SUCCESS)
{
/* Call actual block pool create function. */
status = _tx_block_pool_create(pool_ptr, name_ptr, block_size, pool_start, pool_size);
}
/* Return completion status. */
return(status);
}

View File

@@ -0,0 +1,148 @@
/**************************************************************************/
/* */
/* 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_timer.h"
#include "tx_block_pool.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txe_block_pool_delete PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the delete block pool memory */
/* function call. */
/* */
/* INPUT */
/* */
/* pool_ptr Pointer to pool control block */
/* */
/* OUTPUT */
/* */
/* TX_POOL_ERROR Invalid memory block pool pointer */
/* TX_CALLER_ERROR Invalid caller of this function */
/* status Actual delete function status */
/* */
/* CALLS */
/* */
/* _tx_block_pool_delete Actual block pool delete function */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _txe_block_pool_delete(TX_BLOCK_POOL *pool_ptr)
{
UINT status;
#ifndef TX_TIMER_PROCESS_IN_ISR
TX_THREAD *thread_ptr;
#endif
#ifndef TX_TIMER_PROCESS_IN_ISR
/* Default status to success. */
status = TX_SUCCESS;
#endif
/* Check for an invalid pool pointer. */
if (pool_ptr == TX_NULL)
{
/* Pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Now check the pool ID. */
else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID)
{
/* Pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Check for invalid caller of this function. */
/* Is the call from an ISR or initialization? */
else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0))
{
/* Invalid caller of this function, return appropriate error code. */
status = TX_CALLER_ERROR;
}
else
{
#ifndef TX_TIMER_PROCESS_IN_ISR
/* Pickup thread pointer. */
TX_THREAD_GET_CURRENT(thread_ptr)
/* Is the call from the system timer thread? */
if (thread_ptr == &_tx_timer_thread)
{
/* Invalid caller of this function, return appropriate error code. */
status = TX_CALLER_ERROR;
}
/* Determine if everything is okay. */
if (status == TX_SUCCESS)
{
#endif
/* Call actual block pool delete function. */
status = _tx_block_pool_delete(pool_ptr);
#ifndef TX_TIMER_PROCESS_IN_ISR
}
#endif
}
/* Return completion status. */
return(status);
}

View 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 */
/** */
/** Block Memory */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_block_pool.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _txe_block_pool_info_get PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function checks for errors in the block pool information get */
/* service. */
/* */
/* 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 */
/* */
/* TX_POOL_ERROR Invalid block pool pointer */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _tx_block_pool_info_get Actual block pool info get service*/
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 William E. Lamie Initial Version 6.0 */
/* 09-30-2020 Yuxin Zhou Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _txe_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)
{
UINT status;
/* Check for an invalid block pool pointer. */
if (pool_ptr == TX_NULL)
{
/* Block pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
/* Now check the pool ID. */
else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID)
{
/* Block pool pointer is invalid, return appropriate error code. */
status = TX_POOL_ERROR;
}
else
{
/* Otherwise, call the actual block pool information get service. */
status = _tx_block_pool_info_get(pool_ptr, name, available_blocks,
total_blocks, first_suspended, suspended_count, next_pool);
}
/* Return completion status. */
return(status);
}

Some files were not shown because too many files have changed in this diff Show More