From 688f56aefcae7a045f02a843b6175d1b31636584 Mon Sep 17 00:00:00 2001 From: Dev10-sys Date: Thu, 22 Oct 2026 14:43:24 +0530 Subject: [PATCH] Added opt-in pointer callback mode and pointer creation APIs (#771, #772) Support passing full pointer-width context arguments to thread and timer callbacks on 64-bit architectures without truncation, while maintaining full backward compatibility for existing 32-bit ULONG callbacks. - Added tx_thread_create_ptr and tx_timer_create_ptr APIs for direct pointer context callbacks. - Added pointer entry and timeout fields in thread and timer control blocks with automatic dispatch in shell entry and timer threads. - Added TX_ENABLE_POINTER_CALLBACKS configuration option to allow transparent pointer passing with standard create APIs. - Preserved existing ULONG callback signatures across all ports and module manager interfaces. - Added regression tests covering 64-bit pointer argument transmission, error detection paths, and backward compatibility in both standard and SMP builds. Signed-off-by: Dev10-sys --- common/inc/tx_api.h | 50 +++ common/src/tx_thread_create.c | 112 ++++++- common/src/tx_thread_shell_entry.c | 11 +- common/src/tx_timer_create.c | 94 +++++- common/src/tx_timer_expiration_process.c | 20 +- common/src/tx_timer_thread_entry.c | 20 +- common/src/txe_thread_create.c | 141 ++++++++- common/src/txe_timer_create.c | 118 +++++++- common_smp/inc/tx_api.h | 50 +++ common_smp/src/tx_thread_create.c | 107 ++++++- common_smp/src/tx_thread_shell_entry.c | 11 +- common_smp/src/tx_timer_create.c | 94 +++++- common_smp/src/tx_timer_expiration_process.c | 20 +- common_smp/src/tx_timer_thread_entry.c | 18 +- common_smp/src/txe_thread_create.c | 141 ++++++++- common_smp/src/txe_timer_create.c | 114 ++++++- test/smp/cmake/regression/CMakeLists.txt | 1 + .../threadx_pointer_callback_test.c | 284 ++++++++++++++++++ test/tx/cmake/regression/CMakeLists.txt | 3 +- .../threadx_pointer_callback_test.c | 284 ++++++++++++++++++ 20 files changed, 1637 insertions(+), 56 deletions(-) create mode 100644 test/smp/regression/threadx_pointer_callback_test.c create mode 100644 test/tx/regression/threadx_pointer_callback_test.c diff --git a/common/inc/tx_api.h b/common/inc/tx_api.h index ed1f82918..b0d3d0e15 100644 --- a/common/inc/tx_api.h +++ b/common/inc/tx_api.h @@ -346,6 +346,8 @@ typedef struct TX_TIMER_INTERNAL_STRUCT /* Define the timeout function and timeout function parameter. */ VOID (*tx_timer_internal_timeout_function)(ULONG id); ULONG tx_timer_internal_timeout_param; + VOID (*tx_timer_internal_timeout_function_ptr)(VOID *id); + VOID *tx_timer_internal_timeout_param_ptr; /* Define the next and previous internal link pointers for active @@ -467,6 +469,8 @@ typedef struct TX_THREAD_STRUCT /* Define the thread's entry point and input parameter. */ VOID (*tx_thread_entry)(ULONG id); ULONG tx_thread_entry_parameter; + VOID (*tx_thread_entry_ptr)(VOID *id); + VOID *tx_thread_entry_parameter_ptr; /* Define the thread's timer block. This is used for thread sleep and timeout requests. */ @@ -1140,7 +1144,12 @@ UINT _tx_trace_interrupt_control(UINT new_posture); #define tx_semaphore_put _tx_semaphore_put #define tx_semaphore_put_notify _tx_semaphore_put_notify +#define tx_thread_create_ptr _tx_thread_create_ptr +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_thread_create _tx_thread_create_ptr +#else #define tx_thread_create _tx_thread_create +#endif #define tx_thread_delete _tx_thread_delete #define tx_thread_entry_exit_notify _tx_thread_entry_exit_notify #define tx_thread_identify _tx_thread_identify @@ -1163,7 +1172,12 @@ UINT _tx_trace_interrupt_control(UINT new_posture); #define tx_time_set _tx_time_set #define tx_timer_activate _tx_timer_activate #define tx_timer_change _tx_timer_change +#define tx_timer_create_ptr _tx_timer_create_ptr +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_timer_create _tx_timer_create_ptr +#else #define tx_timer_create _tx_timer_create +#endif #define tx_timer_deactivate _tx_timer_deactivate #define tx_timer_delete _tx_timer_delete #define tx_timer_info_get _tx_timer_info_get @@ -1263,7 +1277,12 @@ UINT _tx_trace_interrupt_control(UINT new_posture); #define tx_semaphore_put _txr_semaphore_put #define tx_semaphore_put_notify _txr_semaphore_put_notify +#define tx_thread_create_ptr(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#else #define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txr_thread_create((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#endif #define tx_thread_delete _txr_thread_delete #define tx_thread_entry_exit_notify _txr_thread_entry_exit_notify #define tx_thread_identify _tx_thread_identify @@ -1286,7 +1305,12 @@ UINT _tx_trace_interrupt_control(UINT new_posture); #define tx_time_set _tx_time_set #define tx_timer_activate _txr_timer_activate #define tx_timer_change _txr_timer_change +#define tx_timer_create_ptr(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_timer_create(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#else #define tx_timer_create(t,n,e,i,c,r,a) _txr_timer_create((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#endif #define tx_timer_deactivate _txr_timer_deactivate #define tx_timer_delete _txr_timer_delete #define tx_timer_info_get _txr_timer_info_get @@ -1374,7 +1398,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_semaphore_put _txe_semaphore_put #define tx_semaphore_put_notify _txe_semaphore_put_notify +#define tx_thread_create_ptr(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#else #define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#endif #define tx_thread_delete _txe_thread_delete #define tx_thread_entry_exit_notify _txe_thread_entry_exit_notify #define tx_thread_identify _tx_thread_identify @@ -1397,7 +1426,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_time_set _tx_time_set #define tx_timer_activate _txe_timer_activate #define tx_timer_change _txe_timer_change +#define tx_timer_create_ptr(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_timer_create(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#else #define tx_timer_create(t,n,e,i,c,r,a) _txe_timer_create((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#endif #define tx_timer_deactivate _txe_timer_deactivate #define tx_timer_delete _txe_timer_delete #define tx_timer_info_get _txe_timer_info_get @@ -1704,6 +1738,11 @@ UINT _tx_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_pt VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start); +UINT _tx_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *entry_input), VOID *entry_input, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start); UINT _tx_thread_delete(TX_THREAD *thread_ptr); UINT _tx_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type)); TX_THREAD *_tx_thread_identify(VOID); @@ -1741,6 +1780,11 @@ UINT _txe_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_p VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start, UINT thread_control_block_size); +UINT _txe_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *entry_input), VOID *entry_input, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start, UINT thread_control_block_size); UINT _txe_thread_delete(TX_THREAD *thread_ptr); UINT _txe_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type)); UINT _txe_thread_info_get(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR **name, UINT *state, ULONG *run_count, @@ -1788,6 +1832,9 @@ UINT _tx_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG res UINT _tx_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*expiration_function)(ULONG input), ULONG expiration_input, ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate); +UINT _tx_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *input), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate); UINT _tx_timer_deactivate(TX_TIMER *timer_ptr); UINT _tx_timer_delete(TX_TIMER *timer_ptr); UINT _tx_timer_info_get(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR **name, UINT *active, ULONG *remaining_ticks, @@ -1809,6 +1856,9 @@ UINT _txe_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG re UINT _txe_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*expiration_function)(ULONG input), ULONG expiration_input, ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size); +UINT _txe_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *input), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size); UINT _txe_timer_deactivate(TX_TIMER *timer_ptr); UINT _txe_timer_delete(TX_TIMER *timer_ptr); UINT _txe_timer_info_get(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR **name, UINT *active, ULONG *remaining_ticks, diff --git a/common/src/tx_thread_create.c b/common/src/tx_thread_create.c index 256e2f17b..fe6a0cb2b 100644 --- a/common/src/tx_thread_create.c +++ b/common/src/tx_thread_create.c @@ -77,10 +77,18 @@ /* Application Code */ /* _tx_timer_initialize Create system timer thread */ /* */ +static UINT _tx_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start); + /**************************************************************************/ -UINT _tx_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST 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) +static UINT _tx_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start) { TX_INTERRUPT_SAVE_AREA @@ -164,9 +172,11 @@ ULONG stack_fill_value; #endif /* 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_name = name_ptr; + thread_ptr -> tx_thread_entry = entry_function; + thread_ptr -> tx_thread_entry_parameter = entry_input; + thread_ptr -> tx_thread_entry_ptr = entry_function_ptr; + thread_ptr -> tx_thread_entry_parameter_ptr = entry_input_ptr; thread_ptr -> tx_thread_stack_start = stack_start; thread_ptr -> tx_thread_stack_size = stack_size; thread_ptr -> tx_thread_priority = priority; @@ -384,3 +394,93 @@ ULONG stack_fill_value; return(TX_SUCCESS); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_create PORTABLE C */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a thread with ULONG input parameter. */ +/* */ +/* 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 */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* */ +/* OUTPUT */ +/* */ +/* return status Thread create return status */ +/* */ +/**************************************************************************/ +UINT _tx_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST 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) +{ + return(_tx_thread_create_initial(thread_ptr, name_ptr, + entry_function, entry_input, + TX_NULL, TX_NULL, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_create_ptr PORTABLE C */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a thread with pointer context input. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name Pointer to thread name string */ +/* entry_function Entry function of the thread */ +/* entry_input Pointer input value to thread */ +/* stack_start Pointer to start of stack */ +/* stack_size Stack size in bytes */ +/* priority Priority of thread */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* */ +/* OUTPUT */ +/* */ +/* return status Thread create return status */ +/* */ +/**************************************************************************/ +UINT _tx_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *id), VOID *entry_input, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start) +{ + return(_tx_thread_create_initial(thread_ptr, name_ptr, + TX_NULL, 0, + entry_function, entry_input, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start)); +} + diff --git a/common/src/tx_thread_shell_entry.c b/common/src/tx_thread_shell_entry.c index 2a16a00b6..93fa61316 100644 --- a/common/src/tx_thread_shell_entry.c +++ b/common/src/tx_thread_shell_entry.c @@ -105,7 +105,16 @@ VOID (*entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type); #endif /* Call current thread's entry function. */ - (thread_ptr -> tx_thread_entry) (thread_ptr -> tx_thread_entry_parameter); + if (thread_ptr -> tx_thread_entry_ptr != TX_NULL) + { + + (thread_ptr -> tx_thread_entry_ptr)(thread_ptr -> tx_thread_entry_parameter_ptr); + } + else + { + + (thread_ptr -> tx_thread_entry)(thread_ptr -> tx_thread_entry_parameter); + } /* Suspend thread with a "completed" state. */ diff --git a/common/src/tx_timer_create.c b/common/src/tx_timer_create.c index 15eb866f7..b5a02bc5b 100644 --- a/common/src/tx_timer_create.c +++ b/common/src/tx_timer_create.c @@ -68,10 +68,16 @@ /* */ /* Application Code */ /* */ +static UINT _tx_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate); + /**************************************************************************/ -UINT _tx_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, - VOID (*expiration_function)(ULONG id), ULONG expiration_input, - ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) +static UINT _tx_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) { TX_INTERRUPT_SAVE_AREA @@ -89,6 +95,8 @@ TX_TIMER *previous_timer; 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; + timer_ptr -> tx_timer_internal.tx_timer_internal_timeout_function_ptr = expiration_function_ptr; + timer_ptr -> tx_timer_internal.tx_timer_internal_timeout_param_ptr = expiration_input_ptr; /* Disable interrupts to put the timer on the created list. */ TX_DISABLE @@ -161,3 +169,83 @@ TX_TIMER *previous_timer; return(TX_SUCCESS); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an application timer with ULONG input. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input 32-bit input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Successful completion status */ +/* */ +/**************************************************************************/ +UINT _tx_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) +{ + return(_tx_timer_create_initial(timer_ptr, name_ptr, + expiration_function, expiration_input, + TX_NULL, TX_NULL, + initial_ticks, reschedule_ticks, auto_activate)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_create_ptr PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an application timer with pointer context. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input Pointer input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Successful completion status */ +/* */ +/**************************************************************************/ +UINT _tx_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *id), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) +{ + return(_tx_timer_create_initial(timer_ptr, name_ptr, + TX_NULL, 0, + expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate)); +} + diff --git a/common/src/tx_timer_expiration_process.c b/common/src/tx_timer_expiration_process.c index 33923a937..2b1ae46c3 100644 --- a/common/src/tx_timer_expiration_process.c +++ b/common/src/tx_timer_expiration_process.c @@ -88,6 +88,8 @@ ULONG delta; TX_TIMER_INTERNAL *current_timer; VOID (*timeout_function)(ULONG id); ULONG timeout_param = ((ULONG) 0); +VOID (*timeout_function_ptr)(VOID *id); +VOID *timeout_param_ptr = TX_NULL; #ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO TX_TIMER *timer_ptr; #endif @@ -264,7 +266,8 @@ TX_TIMER *timer_ptr; /* Set the timeout function to NULL in order to bypass the expiration. */ - timeout_function = TX_NULL; + timeout_function = TX_NULL; + timeout_function_ptr = TX_NULL; /* Make the timer appear that it is still active while interrupts are enabled. This will permit proper processing of a timer @@ -305,8 +308,10 @@ TX_TIMER *timer_ptr; /* 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; + timeout_function = current_timer -> tx_timer_internal_timeout_function; + timeout_param = current_timer -> tx_timer_internal_timeout_param; + timeout_function_ptr = current_timer -> tx_timer_internal_timeout_function_ptr; + timeout_param_ptr = current_timer -> tx_timer_internal_timeout_param_ptr; /* Copy the reinitialize ticks into the remaining ticks. */ current_timer -> tx_timer_internal_remaining_ticks = current_timer -> tx_timer_internal_re_initialize_ticks; @@ -341,7 +346,12 @@ TX_TIMER *timer_ptr; TX_RESTORE /* Call the timer-expiration function, if non-NULL. */ - if (timeout_function != TX_NULL) + if (timeout_function_ptr != TX_NULL) + { + + (timeout_function_ptr) (timeout_param_ptr); + } + else if (timeout_function != TX_NULL) { (timeout_function) (timeout_param); @@ -362,7 +372,7 @@ TX_TIMER *timer_ptr; #ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO /* Determine if this timer expired. */ - if (timeout_function != TX_NULL) + if ((timeout_function != TX_NULL) || (timeout_function_ptr != TX_NULL)) { /* Increment the total reactivations counter. */ diff --git a/common/src/tx_timer_thread_entry.c b/common/src/tx_timer_thread_entry.c index 971a0703f..82f7c397b 100644 --- a/common/src/tx_timer_thread_entry.c +++ b/common/src/tx_timer_thread_entry.c @@ -78,6 +78,8 @@ TX_TIMER_INTERNAL *previous_timer; TX_TIMER_INTERNAL *current_timer; VOID (*timeout_function)(ULONG id); ULONG timeout_param = ((ULONG) 0); +VOID (*timeout_function_ptr)(VOID *id); +VOID *timeout_param_ptr = TX_NULL; TX_THREAD *thread_ptr; #ifdef TX_REACTIVATE_INLINE TX_TIMER_INTERNAL **timer_list; /* Timer list pointer */ @@ -216,7 +218,8 @@ TX_TIMER *timer_ptr; /* Set the timeout function to NULL in order to bypass the expiration. */ - timeout_function = TX_NULL; + timeout_function = TX_NULL; + timeout_function_ptr = TX_NULL; /* Make the timer appear that it is still active while interrupts are enabled. This will permit proper processing of a timer @@ -257,8 +260,10 @@ TX_TIMER *timer_ptr; /* 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; + timeout_function = current_timer -> tx_timer_internal_timeout_function; + timeout_param = current_timer -> tx_timer_internal_timeout_param; + timeout_function_ptr = current_timer -> tx_timer_internal_timeout_function_ptr; + timeout_param_ptr = current_timer -> tx_timer_internal_timeout_param_ptr; /* Copy the reinitialize ticks into the remaining ticks. */ current_timer -> tx_timer_internal_remaining_ticks = current_timer -> tx_timer_internal_re_initialize_ticks; @@ -293,7 +298,12 @@ TX_TIMER *timer_ptr; TX_RESTORE /* Call the timer-expiration function, if non-NULL. */ - if (timeout_function != TX_NULL) + if (timeout_function_ptr != TX_NULL) + { + + (timeout_function_ptr) (timeout_param_ptr); + } + else if (timeout_function != TX_NULL) { (timeout_function) (timeout_param); @@ -314,7 +324,7 @@ TX_TIMER *timer_ptr; #ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO /* Determine if this timer expired. */ - if (timeout_function != TX_NULL) + if ((timeout_function != TX_NULL) || (timeout_function_ptr != TX_NULL)) { /* Increment the total reactivations counter. */ diff --git a/common/src/txe_thread_create.c b/common/src/txe_thread_create.c index cc5033b29..8b2ac00c0 100644 --- a/common/src/txe_thread_create.c +++ b/common/src/txe_thread_create.c @@ -80,9 +80,17 @@ /* */ /* Application Code */ /* */ +static UINT _txe_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start, UINT thread_control_block_size); + /**************************************************************************/ -UINT _txe_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, +static UINT _txe_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start, UINT thread_control_block_size) @@ -221,7 +229,7 @@ TX_THREAD *current_thread; } /* Check for invalid thread entry point. */ - else if (entry_function == TX_NULL) + else if ((entry_function == TX_NULL) && (entry_function_ptr == TX_NULL)) { /* Invalid stack or entry point, return appropriate error code. */ @@ -296,12 +304,135 @@ TX_THREAD *current_thread; { /* Call actual thread create function. */ - status = _tx_thread_create(thread_ptr, name_ptr, entry_function, entry_input, - stack_start, stack_size, priority, preempt_threshold, - time_slice, auto_start); + if (entry_function_ptr != TX_NULL) + { + status = _tx_thread_create_ptr(thread_ptr, name_ptr, + entry_function_ptr, entry_input_ptr, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start); + } + else + { + status = _tx_thread_create(thread_ptr, name_ptr, + entry_function, entry_input, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start); + } } /* Return completion status. */ return(status); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_create PORTABLE C */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread create function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name_ptr Pointer to thread name string */ +/* entry_function Entry function of the thread */ +/* entry_input 32-bit input value to thread */ +/* stack_start Pointer to start of stack */ +/* stack_size Stack size in bytes */ +/* priority Priority of thread (0-31) */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* thread_control_block_size Size of thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_PTR_ERROR Invalid stack or function ptr */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_PRIORITY_ERROR Invalid thread priority */ +/* TX_THRESH_ERROR Invalid preemption threshold */ +/* TX_START_ERROR Invalid start selection */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST 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, UINT thread_control_block_size) +{ + return(_txe_thread_create_initial(thread_ptr, name_ptr, + entry_function, entry_input, + TX_NULL, TX_NULL, + stack_start, stack_size, + priority, preempt_threshold, + time_slice, auto_start, + thread_control_block_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_create_ptr PORTABLE C */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in pointer context thread create. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name_ptr Pointer to thread name string */ +/* entry_function Entry function of the thread */ +/* entry_input Pointer input value to thread */ +/* stack_start Pointer to start of stack */ +/* stack_size Stack size in bytes */ +/* priority Priority of thread */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* thread_control_block_size Size of thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_PTR_ERROR Invalid stack or function ptr */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_PRIORITY_ERROR Invalid thread priority */ +/* TX_THRESH_ERROR Invalid preemption threshold */ +/* TX_START_ERROR Invalid start selection */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *id), VOID *entry_input, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start, UINT thread_control_block_size) +{ + return(_txe_thread_create_initial(thread_ptr, name_ptr, + TX_NULL, 0, + entry_function, entry_input, + stack_start, stack_size, + priority, preempt_threshold, + time_slice, auto_start, + thread_control_block_size)); +} + diff --git a/common/src/txe_timer_create.c b/common/src/txe_timer_create.c index 8c481bde8..9e911e2ee 100644 --- a/common/src/txe_timer_create.c +++ b/common/src/txe_timer_create.c @@ -75,10 +75,16 @@ /* */ /* Application Code */ /* */ +static UINT _txe_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size); + /**************************************************************************/ -UINT _txe_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, - VOID (*expiration_function)(ULONG id), ULONG expiration_input, - ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) +static UINT _txe_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) { TX_INTERRUPT_SAVE_AREA @@ -223,11 +229,113 @@ TX_THREAD *thread_ptr; { /* Call actual application timer create function. */ - status = _tx_timer_create(timer_ptr, name_ptr, expiration_function, expiration_input, - initial_ticks, reschedule_ticks, auto_activate); + if (expiration_function_ptr != TX_NULL) + { + status = _tx_timer_create_ptr(timer_ptr, name_ptr, + expiration_function_ptr, expiration_input_ptr, + initial_ticks, reschedule_ticks, auto_activate); + } + else + { + status = _tx_timer_create(timer_ptr, name_ptr, + expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate); + } } /* Return completion status. */ return(status); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in timer create with ULONG input. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input 32-bit input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* timer_control_block_size Size of timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid timer pointer */ +/* TX_TICK_ERROR Invalid initial ticks */ +/* TX_ACTIVATE_ERROR Invalid auto-activate option */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) +{ + return(_txe_timer_create_initial(timer_ptr, name_ptr, + expiration_function, expiration_input, + TX_NULL, TX_NULL, + initial_ticks, reschedule_ticks, auto_activate, + timer_control_block_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_create_ptr PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in timer create with pointer input. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input Pointer input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* timer_control_block_size Size of timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid timer pointer */ +/* TX_TICK_ERROR Invalid initial ticks */ +/* TX_ACTIVATE_ERROR Invalid auto-activate option */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *id), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) +{ + return(_txe_timer_create_initial(timer_ptr, name_ptr, + TX_NULL, 0, + expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate, + timer_control_block_size)); +} + diff --git a/common_smp/inc/tx_api.h b/common_smp/inc/tx_api.h index 77bd6218b..3774b7a3f 100644 --- a/common_smp/inc/tx_api.h +++ b/common_smp/inc/tx_api.h @@ -363,6 +363,8 @@ typedef struct TX_TIMER_INTERNAL_STRUCT /* Define the timeout function and timeout function parameter. */ VOID (*tx_timer_internal_timeout_function)(ULONG id); ULONG tx_timer_internal_timeout_param; + VOID (*tx_timer_internal_timeout_function_ptr)(VOID *id); + VOID *tx_timer_internal_timeout_param_ptr; /* Define the next and previous internal link pointers for active @@ -499,6 +501,8 @@ typedef struct TX_THREAD_STRUCT /* Define the thread's entry point and input parameter. */ VOID (*tx_thread_entry)(ULONG id); ULONG tx_thread_entry_parameter; + VOID (*tx_thread_entry_ptr)(VOID *id); + VOID *tx_thread_entry_parameter_ptr; /* Define the thread's timer block. This is used for thread sleep and timeout requests. */ @@ -1236,7 +1240,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_semaphore_put _tx_semaphore_put #define tx_semaphore_put_notify _tx_semaphore_put_notify +#define tx_thread_create_ptr _tx_thread_create_ptr +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_thread_create _tx_thread_create_ptr +#else #define tx_thread_create _tx_thread_create +#endif #define tx_thread_delete _tx_thread_delete #define tx_thread_entry_exit_notify _tx_thread_entry_exit_notify #define tx_thread_identify _tx_thread_identify @@ -1265,7 +1274,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_time_set _tx_time_set #define tx_timer_activate _tx_timer_activate #define tx_timer_change _tx_timer_change +#define tx_timer_create_ptr _tx_timer_create_ptr +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_timer_create _tx_timer_create_ptr +#else #define tx_timer_create _tx_timer_create +#endif #define tx_timer_deactivate _tx_timer_deactivate #define tx_timer_delete _tx_timer_delete #define tx_timer_info_get _tx_timer_info_get @@ -1364,7 +1378,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_semaphore_put _txr_semaphore_put #define tx_semaphore_put_notify _txr_semaphore_put_notify +#define tx_thread_create_ptr(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#else #define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txr_thread_create((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#endif #define tx_thread_delete _txr_thread_delete #define tx_thread_entry_exit_notify _txr_thread_entry_exit_notify #define tx_thread_identify _tx_thread_identify @@ -1393,7 +1412,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_time_set _tx_time_set #define tx_timer_activate _txr_timer_activate #define tx_timer_change _txr_timer_change +#define tx_timer_create_ptr(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_timer_create(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#else #define tx_timer_create(t,n,e,i,c,r,a) _txr_timer_create((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#endif #define tx_timer_deactivate _txr_timer_deactivate #define tx_timer_delete _txr_timer_delete #define tx_timer_info_get _txr_timer_info_get @@ -1481,7 +1505,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_semaphore_put _txe_semaphore_put #define tx_semaphore_put_notify _txe_semaphore_put_notify +#define tx_thread_create_ptr(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create_ptr((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#else #define tx_thread_create(t,n,e,i,s,l,p,r,c,a) _txe_thread_create((t),(n),(e),(i),(s),(l),(p),(r),(c),(a),(sizeof(TX_THREAD))) +#endif #define tx_thread_delete _txe_thread_delete #define tx_thread_entry_exit_notify _txe_thread_entry_exit_notify #define tx_thread_identify _tx_thread_identify @@ -1510,7 +1539,12 @@ UINT _tx_el_interrupt_control(UINT new_posture); #define tx_time_set _tx_time_set #define tx_timer_activate _txe_timer_activate #define tx_timer_change _txe_timer_change +#define tx_timer_create_ptr(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#ifdef TX_ENABLE_POINTER_CALLBACKS +#define tx_timer_create(t,n,e,i,c,r,a) _txe_timer_create_ptr((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#else #define tx_timer_create(t,n,e,i,c,r,a) _txe_timer_create((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#endif #define tx_timer_deactivate _txe_timer_deactivate #define tx_timer_delete _txe_timer_delete #define tx_timer_info_get _txe_timer_info_get @@ -1747,6 +1781,11 @@ UINT _tx_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_pt VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start); +UINT _tx_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *entry_input), VOID *entry_input, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start); UINT _tx_thread_delete(TX_THREAD *thread_ptr); UINT _tx_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type)); TX_THREAD *_tx_thread_identify(VOID); @@ -1784,6 +1823,11 @@ UINT _txe_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_p VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start, UINT thread_control_block_size); +UINT _txe_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *entry_input), VOID *entry_input, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start, UINT thread_control_block_size); UINT _txe_thread_delete(TX_THREAD *thread_ptr); UINT _txe_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type)); UINT _txe_thread_info_get(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR **name, UINT *state, ULONG *run_count, @@ -1809,6 +1853,9 @@ UINT _tx_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG res UINT _tx_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*expiration_function)(ULONG input), ULONG expiration_input, ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate); +UINT _tx_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *input), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate); UINT _tx_timer_deactivate(TX_TIMER *timer_ptr); UINT _tx_timer_delete(TX_TIMER *timer_ptr); UINT _tx_timer_info_get(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR **name, UINT *active, ULONG *remaining_ticks, @@ -1830,6 +1877,9 @@ UINT _txe_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG re UINT _txe_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*expiration_function)(ULONG input), ULONG expiration_input, ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size); +UINT _txe_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *input), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size); UINT _txe_timer_deactivate(TX_TIMER *timer_ptr); UINT _txe_timer_delete(TX_TIMER *timer_ptr); UINT _txe_timer_info_get(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR **name, UINT *active, ULONG *remaining_ticks, diff --git a/common_smp/src/tx_thread_create.c b/common_smp/src/tx_thread_create.c index 3b158f475..a4eb9e31b 100644 --- a/common_smp/src/tx_thread_create.c +++ b/common_smp/src/tx_thread_create.c @@ -78,11 +78,18 @@ /* Application Code */ /* _tx_timer_initialize Create system timer thread */ /* */ +static UINT _tx_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start); + /**************************************************************************/ -UINT _tx_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST 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) +static UINT _tx_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start) { TX_INTERRUPT_SAVE_AREA @@ -165,6 +172,8 @@ ULONG stack_fill_value; 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_entry_ptr = entry_function_ptr; + thread_ptr -> tx_thread_entry_parameter_ptr = entry_input_ptr; thread_ptr -> tx_thread_stack_start = stack_start; thread_ptr -> tx_thread_stack_size = stack_size; thread_ptr -> tx_thread_priority = priority; @@ -402,3 +411,93 @@ ULONG stack_fill_value; return(TX_SUCCESS); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_create PORTABLE SMP */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a thread with ULONG input parameter. */ +/* */ +/* 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 */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* */ +/* OUTPUT */ +/* */ +/* return status Thread create return status */ +/* */ +/**************************************************************************/ +UINT _tx_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST 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) +{ + return(_tx_thread_create_initial(thread_ptr, name_ptr, + entry_function, entry_input, + TX_NULL, TX_NULL, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_create_ptr PORTABLE SMP */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a thread with pointer context input. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name Pointer to thread name string */ +/* entry_function Entry function of the thread */ +/* entry_input Pointer input value to thread */ +/* stack_start Pointer to start of stack */ +/* stack_size Stack size in bytes */ +/* priority Priority of thread */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* */ +/* OUTPUT */ +/* */ +/* return status Thread create return status */ +/* */ +/**************************************************************************/ +UINT _tx_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *id), VOID *entry_input, + VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start) +{ + return(_tx_thread_create_initial(thread_ptr, name_ptr, + TX_NULL, 0, + entry_function, entry_input, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start)); +} + diff --git a/common_smp/src/tx_thread_shell_entry.c b/common_smp/src/tx_thread_shell_entry.c index 2a16a00b6..93fa61316 100644 --- a/common_smp/src/tx_thread_shell_entry.c +++ b/common_smp/src/tx_thread_shell_entry.c @@ -105,7 +105,16 @@ VOID (*entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type); #endif /* Call current thread's entry function. */ - (thread_ptr -> tx_thread_entry) (thread_ptr -> tx_thread_entry_parameter); + if (thread_ptr -> tx_thread_entry_ptr != TX_NULL) + { + + (thread_ptr -> tx_thread_entry_ptr)(thread_ptr -> tx_thread_entry_parameter_ptr); + } + else + { + + (thread_ptr -> tx_thread_entry)(thread_ptr -> tx_thread_entry_parameter); + } /* Suspend thread with a "completed" state. */ diff --git a/common_smp/src/tx_timer_create.c b/common_smp/src/tx_timer_create.c index 81af4c9b7..0bf352de1 100644 --- a/common_smp/src/tx_timer_create.c +++ b/common_smp/src/tx_timer_create.c @@ -69,10 +69,16 @@ /* */ /* Application Code */ /* */ +static UINT _tx_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate); + /**************************************************************************/ -UINT _tx_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, - VOID (*expiration_function)(ULONG id), ULONG expiration_input, - ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) +static UINT _tx_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) { TX_INTERRUPT_SAVE_AREA @@ -90,6 +96,8 @@ TX_TIMER *previous_timer; 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; + timer_ptr -> tx_timer_internal.tx_timer_internal_timeout_function_ptr = expiration_function_ptr; + timer_ptr -> tx_timer_internal.tx_timer_internal_timeout_param_ptr = expiration_input_ptr; #ifdef TX_THREAD_SMP_ONLY_CORE_0_DEFAULT @@ -168,3 +176,83 @@ TX_TIMER *previous_timer; return(TX_SUCCESS); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_create PORTABLE SMP */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an application timer with ULONG input. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input 32-bit input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Successful completion status */ +/* */ +/**************************************************************************/ +UINT _tx_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) +{ + return(_tx_timer_create_initial(timer_ptr, name_ptr, + expiration_function, expiration_input, + TX_NULL, TX_NULL, + initial_ticks, reschedule_ticks, auto_activate)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_create_ptr PORTABLE SMP */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an application timer with pointer context. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input Pointer input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Successful completion status */ +/* */ +/**************************************************************************/ +UINT _tx_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *id), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate) +{ + return(_tx_timer_create_initial(timer_ptr, name_ptr, + TX_NULL, 0, + expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate)); +} + diff --git a/common_smp/src/tx_timer_expiration_process.c b/common_smp/src/tx_timer_expiration_process.c index f54e982d8..7bca4b4e6 100644 --- a/common_smp/src/tx_timer_expiration_process.c +++ b/common_smp/src/tx_timer_expiration_process.c @@ -87,6 +87,8 @@ ULONG delta; TX_TIMER_INTERNAL *current_timer; VOID (*timeout_function)(ULONG id); ULONG timeout_param = ((ULONG) 0); +VOID (*timeout_function_ptr)(VOID *id); +VOID *timeout_param_ptr = TX_NULL; #ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO TX_TIMER *timer_ptr; #endif @@ -263,7 +265,8 @@ TX_TIMER *timer_ptr; /* Set the timeout function to NULL in order to bypass the expiration. */ - timeout_function = TX_NULL; + timeout_function = TX_NULL; + timeout_function_ptr = TX_NULL; /* Make the timer appear that it is still active while interrupts are enabled. This will permit proper processing of a timer @@ -304,8 +307,10 @@ TX_TIMER *timer_ptr; /* 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; + timeout_function = current_timer -> tx_timer_internal_timeout_function; + timeout_param = current_timer -> tx_timer_internal_timeout_param; + timeout_function_ptr = current_timer -> tx_timer_internal_timeout_function_ptr; + timeout_param_ptr = current_timer -> tx_timer_internal_timeout_param_ptr; /* Copy the reinitialize ticks into the remaining ticks. */ current_timer -> tx_timer_internal_remaining_ticks = current_timer -> tx_timer_internal_re_initialize_ticks; @@ -340,7 +345,12 @@ TX_TIMER *timer_ptr; TX_RESTORE /* Call the timer-expiration function, if non-NULL. */ - if (timeout_function != TX_NULL) + if (timeout_function_ptr != TX_NULL) + { + + (timeout_function_ptr) (timeout_param_ptr); + } + else if (timeout_function != TX_NULL) { (timeout_function) (timeout_param); @@ -361,7 +371,7 @@ TX_TIMER *timer_ptr; #ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO /* Determine if this timer expired. */ - if (timeout_function != TX_NULL) + if ((timeout_function != TX_NULL) || (timeout_function_ptr != TX_NULL)) { /* Increment the total reactivations counter. */ diff --git a/common_smp/src/tx_timer_thread_entry.c b/common_smp/src/tx_timer_thread_entry.c index 51b165b23..274ddb438 100644 --- a/common_smp/src/tx_timer_thread_entry.c +++ b/common_smp/src/tx_timer_thread_entry.c @@ -80,6 +80,8 @@ TX_TIMER_INTERNAL *previous_timer; TX_TIMER_INTERNAL *current_timer; VOID (*timeout_function)(ULONG id); ULONG timeout_param = ((ULONG) 0); +VOID (*timeout_function_ptr)(VOID *id); +VOID *timeout_param_ptr = TX_NULL; TX_THREAD *thread_ptr; #ifdef TX_REACTIVATE_INLINE TX_TIMER_INTERNAL **timer_list; /* Timer list pointer */ @@ -257,7 +259,8 @@ UINT status; /* Set the timeout function to NULL in order to bypass the expiration. */ - timeout_function = TX_NULL; + timeout_function = TX_NULL; + timeout_function_ptr = TX_NULL; /* Make the timer appear that it is still active while interrupts are enabled. This will permit proper processing of a timer @@ -298,8 +301,10 @@ UINT status; /* 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; + timeout_function = current_timer -> tx_timer_internal_timeout_function; + timeout_param = current_timer -> tx_timer_internal_timeout_param; + timeout_function_ptr = current_timer -> tx_timer_internal_timeout_function_ptr; + timeout_param_ptr = current_timer -> tx_timer_internal_timeout_param_ptr; /* Copy the reinitialize ticks into the remaining ticks. */ current_timer -> tx_timer_internal_remaining_ticks = current_timer -> tx_timer_internal_re_initialize_ticks; @@ -337,7 +342,12 @@ UINT status; #endif /* Call the timer-expiration function, if non-NULL. */ - if (timeout_function != TX_NULL) + if (timeout_function_ptr != TX_NULL) + { + + (timeout_function_ptr) (timeout_param_ptr); + } + else if (timeout_function != TX_NULL) { (timeout_function) (timeout_param); diff --git a/common_smp/src/txe_thread_create.c b/common_smp/src/txe_thread_create.c index cc5033b29..422daa23c 100644 --- a/common_smp/src/txe_thread_create.c +++ b/common_smp/src/txe_thread_create.c @@ -80,9 +80,17 @@ /* */ /* Application Code */ /* */ +static UINT _txe_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start, UINT thread_control_block_size); + /**************************************************************************/ -UINT _txe_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, +static UINT _txe_thread_create_initial(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*entry_function)(ULONG id), ULONG entry_input, + VOID (*entry_function_ptr)(VOID *id), VOID *entry_input_ptr, VOID *stack_start, ULONG stack_size, UINT priority, UINT preempt_threshold, ULONG time_slice, UINT auto_start, UINT thread_control_block_size) @@ -221,7 +229,7 @@ TX_THREAD *current_thread; } /* Check for invalid thread entry point. */ - else if (entry_function == TX_NULL) + else if ((entry_function == TX_NULL) && (entry_function_ptr == TX_NULL)) { /* Invalid stack or entry point, return appropriate error code. */ @@ -296,12 +304,135 @@ TX_THREAD *current_thread; { /* Call actual thread create function. */ - status = _tx_thread_create(thread_ptr, name_ptr, entry_function, entry_input, - stack_start, stack_size, priority, preempt_threshold, - time_slice, auto_start); + if (entry_function_ptr != TX_NULL) + { + status = _tx_thread_create_ptr(thread_ptr, name_ptr, + entry_function_ptr, entry_input_ptr, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start); + } + else + { + status = _tx_thread_create(thread_ptr, name_ptr, + entry_function, entry_input, + stack_start, stack_size, priority, preempt_threshold, + time_slice, auto_start); + } } /* Return completion status. */ return(status); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_create PORTABLE SMP */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread create function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name_ptr Pointer to thread name string */ +/* entry_function Entry function of the thread */ +/* entry_input 32-bit input value to thread */ +/* stack_start Pointer to start of stack */ +/* stack_size Stack size in bytes */ +/* priority Priority of thread (0-31) */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* thread_control_block_size Size of thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_PTR_ERROR Invalid stack or function ptr */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_PRIORITY_ERROR Invalid thread priority */ +/* TX_THRESH_ERROR Invalid preemption threshold */ +/* TX_START_ERROR Invalid start selection */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_thread_create(TX_THREAD *thread_ptr, TX_NAME_CONST 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, UINT thread_control_block_size) +{ + return(_txe_thread_create_initial(thread_ptr, name_ptr, + entry_function, entry_input, + TX_NULL, TX_NULL, + stack_start, stack_size, + priority, preempt_threshold, + time_slice, auto_start, + thread_control_block_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_create_ptr PORTABLE SMP */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in pointer context thread create. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name_ptr Pointer to thread name string */ +/* entry_function Entry function of the thread */ +/* entry_input Pointer input value to thread */ +/* stack_start Pointer to start of stack */ +/* stack_size Stack size in bytes */ +/* priority Priority of thread */ +/* preempt_threshold Preemption threshold */ +/* time_slice Thread time-slice value */ +/* auto_start Automatic start selection */ +/* thread_control_block_size Size of thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_PTR_ERROR Invalid stack or function ptr */ +/* TX_SIZE_ERROR Invalid stack size */ +/* TX_PRIORITY_ERROR Invalid thread priority */ +/* TX_THRESH_ERROR Invalid preemption threshold */ +/* TX_START_ERROR Invalid start selection */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_thread_create_ptr(TX_THREAD *thread_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*entry_function)(VOID *id), VOID *entry_input, + VOID *stack_start, ULONG stack_size, + UINT priority, UINT preempt_threshold, + ULONG time_slice, UINT auto_start, UINT thread_control_block_size) +{ + return(_txe_thread_create_initial(thread_ptr, name_ptr, + TX_NULL, 0, + entry_function, entry_input, + stack_start, stack_size, + priority, preempt_threshold, + time_slice, auto_start, + thread_control_block_size)); +} + diff --git a/common_smp/src/txe_timer_create.c b/common_smp/src/txe_timer_create.c index 8c481bde8..0ea098dc3 100644 --- a/common_smp/src/txe_timer_create.c +++ b/common_smp/src/txe_timer_create.c @@ -75,9 +75,15 @@ /* */ /* Application Code */ /* */ +static UINT _txe_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size); + /**************************************************************************/ -UINT _txe_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, +static UINT _txe_timer_create_initial(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, VOID (*expiration_function)(ULONG id), ULONG expiration_input, + VOID (*expiration_function_ptr)(VOID *id), VOID *expiration_input_ptr, ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) { @@ -223,11 +229,113 @@ TX_THREAD *thread_ptr; { /* Call actual application timer create function. */ - status = _tx_timer_create(timer_ptr, name_ptr, expiration_function, expiration_input, - initial_ticks, reschedule_ticks, auto_activate); + if (expiration_function_ptr != TX_NULL) + { + status = _tx_timer_create_ptr(timer_ptr, name_ptr, + expiration_function_ptr, expiration_input_ptr, + initial_ticks, reschedule_ticks, auto_activate); + } + else + { + status = _tx_timer_create(timer_ptr, name_ptr, + expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate); + } } /* Return completion status. */ return(status); } + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_create PORTABLE SMP */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the timer create function call. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input 32-bit input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* timer_control_block_size Size of timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid timer pointer */ +/* TX_TICK_ERROR Invalid initial ticks */ +/* TX_ACTIVATE_ERROR Invalid auto-activate option */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_timer_create(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(ULONG id), ULONG expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) +{ + return(_txe_timer_create_initial(timer_ptr, name_ptr, + expiration_function, expiration_input, + TX_NULL, TX_NULL, + initial_ticks, reschedule_ticks, auto_activate, + timer_control_block_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_create_ptr PORTABLE SMP */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in timer create with pointer input. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control blk */ +/* name_ptr Pointer to timer name */ +/* expiration_function Function to call on expiration*/ +/* expiration_input Pointer input value for timer */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* auto_activate Automatic activation flag */ +/* timer_control_block_size Size of timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid timer pointer */ +/* TX_TICK_ERROR Invalid initial ticks */ +/* TX_ACTIVATE_ERROR Invalid auto-activate option */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/**************************************************************************/ +UINT _txe_timer_create_ptr(TX_TIMER *timer_ptr, TX_NAME_CONST CHAR *name_ptr, + VOID (*expiration_function)(VOID *id), VOID *expiration_input, + ULONG initial_ticks, ULONG reschedule_ticks, UINT auto_activate, UINT timer_control_block_size) +{ + return(_txe_timer_create_initial(timer_ptr, name_ptr, + TX_NULL, 0, + expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate, + timer_control_block_size)); +} + diff --git a/test/smp/cmake/regression/CMakeLists.txt b/test/smp/cmake/regression/CMakeLists.txt index cdf0c5859..ad270c12f 100644 --- a/test/smp/cmake/regression/CMakeLists.txt +++ b/test/smp/cmake/regression/CMakeLists.txt @@ -132,6 +132,7 @@ set(regression_test_cases ${SOURCE_DIR}/threadx_timer_simple_test.c ${SOURCE_DIR}/threadx_trace_basic_test.c ${SOURCE_DIR}/threadx_trace_entry_update_test.c + ${SOURCE_DIR}/threadx_pointer_callback_test.c ${SOURCE_DIR}/threadx_initialize_kernel_setup_test.c) add_custom_command( diff --git a/test/smp/regression/threadx_pointer_callback_test.c b/test/smp/regression/threadx_pointer_callback_test.c new file mode 100644 index 000000000..0726f5219 --- /dev/null +++ b/test/smp/regression/threadx_pointer_callback_test.c @@ -0,0 +1,284 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * Copyright (c) 2026-present Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * SPDX-License-Identifier: MIT + **************************************************************************/ + +#include +#include +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + +/* Define test control globals for standalone execution. */ +#ifndef CTEST +void test_control_return(UINT status); +#else +extern void test_control_return(UINT status); +#endif + +static unsigned long error = 0; + +static TX_THREAD thread_0; +static TX_THREAD thread_ptr_test; +static TX_THREAD thread_ulong_test; + +static TX_TIMER timer_ptr_test; +static TX_TIMER timer_ulong_test; + +static void *received_thread_ptr_ctx = TX_NULL; +static void *received_timer_ptr_ctx = TX_NULL; +static ULONG received_thread_ulong_ctx = 0; +static ULONG received_timer_ulong_ctx = 0; + +static volatile UINT thread_ptr_executed = 0; +static volatile UINT thread_ulong_executed = 0; +static volatile UINT timer_ptr_executed = 0; +static volatile UINT timer_ulong_executed = 0; + +#if (defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) || (defined(__riscv_xlen) && (__riscv_xlen == 64)) || defined(__LP64__) || defined(_LP64)) +#define TEST_PTR_VAL_1 ((VOID *)(ALIGN_TYPE) 0x123456789ABCDEF0ULL) +#define TEST_PTR_VAL_2 ((VOID *)(ALIGN_TYPE) 0xDEADBEEFCAFEBABEULL) +#else +#define TEST_PTR_VAL_1 ((VOID *)(ALIGN_TYPE) 0x12345678UL) +#define TEST_PTR_VAL_2 ((VOID *)(ALIGN_TYPE) 0xDEADBEEFUL) +#endif +#define TEST_ULONG_VAL_1 ((ULONG) 0x55AA1234UL) +#define TEST_ULONG_VAL_2 ((ULONG) 0x99887766UL) + +static void thread_ptr_entry(VOID *entry_input) +{ + received_thread_ptr_ctx = entry_input; + thread_ptr_executed = 1; + while (1) + { + tx_thread_sleep(100); + } +} + +static void thread_ulong_entry(ULONG entry_input) +{ + received_thread_ulong_ctx = entry_input; + thread_ulong_executed = 1; + while (1) + { + tx_thread_sleep(100); + } +} + +static void timer_ptr_expiration(VOID *expiration_input) +{ + received_timer_ptr_ctx = expiration_input; + timer_ptr_executed = 1; +} + +static void timer_ulong_expiration(ULONG expiration_input) +{ + received_timer_ulong_ctx = expiration_input; + timer_ulong_executed = 1; +} + +static void thread_0_entry(ULONG thread_input) +{ + UINT status; + VOID *expected_thread_ptr = TEST_PTR_VAL_1; + VOID *expected_timer_ptr = TEST_PTR_VAL_2; + + TX_PARAMETER_NOT_USED(thread_input); + + printf("Running Pointer Callback Regression Test............................ "); + + /* Resume pointer thread and standard thread. */ + tx_thread_resume(&thread_ptr_test); + tx_thread_resume(&thread_ulong_test); + + /* Sleep to allow threads and timers to execute. */ + tx_thread_sleep(5); + + /* Verify pointer thread context reception without 32-bit truncation. */ + if (thread_ptr_executed != 1) + { + error++; + } + if (received_thread_ptr_ctx != expected_thread_ptr) + { + error++; + } + + /* Verify standard ULONG thread context reception. */ + if (thread_ulong_executed != 1) + { + error++; + } + if (received_thread_ulong_ctx != TEST_ULONG_VAL_1) + { + error++; + } + + /* Verify pointer timer context reception without 32-bit truncation. */ + if (timer_ptr_executed != 1) + { + error++; + } + if (received_timer_ptr_ctx != expected_timer_ptr) + { + error++; + } + + /* Verify standard ULONG timer context reception. */ + if (timer_ulong_executed != 1) + { + error++; + } + if (received_timer_ulong_ctx != TEST_ULONG_VAL_2) + { + error++; + } + +#ifndef TX_DISABLE_ERROR_CHECKING + TX_THREAD dummy_thread; + TX_TIMER dummy_timer; + CHAR dummy_stack[1024]; + + dummy_thread.tx_thread_id = 0; + dummy_timer.tx_timer_id = 0; + + /* Test error checking paths for pointer thread create. */ + status = tx_thread_create_ptr(TX_NULL, "bad", thread_ptr_entry, expected_thread_ptr, + dummy_stack, sizeof(dummy_stack), 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_THREAD_ERROR) + { + error++; + } + + status = tx_thread_create_ptr(&dummy_thread, "bad", TX_NULL, expected_thread_ptr, + dummy_stack, sizeof(dummy_stack), 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_PTR_ERROR) + { + error++; + } + + status = tx_thread_create_ptr(&dummy_thread, "bad", thread_ptr_entry, expected_thread_ptr, + TX_NULL, sizeof(dummy_stack), 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_PTR_ERROR) + { + error++; + } + + status = tx_thread_create_ptr(&dummy_thread, "bad", thread_ptr_entry, expected_thread_ptr, + dummy_stack, 0, 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_SIZE_ERROR) + { + error++; + } + + /* Test error checking paths for pointer timer create. */ + status = tx_timer_create_ptr(TX_NULL, "bad", timer_ptr_expiration, expected_timer_ptr, + 1, 0, TX_NO_ACTIVATE); + if (status != TX_TIMER_ERROR) + { + error++; + } + + status = tx_timer_create_ptr(&dummy_timer, "bad", timer_ptr_expiration, expected_timer_ptr, + 0, 0, TX_NO_ACTIVATE); + if (status != TX_TICK_ERROR) + { + error++; + } + + status = tx_timer_create_ptr(&dummy_timer, "bad", timer_ptr_expiration, expected_timer_ptr, + 1, 0, 0xFF); + if (status != TX_ACTIVATE_ERROR) + { + error++; + } +#endif + + /* Clean up created objects. */ + tx_timer_deactivate(&timer_ptr_test); + tx_timer_delete(&timer_ptr_test); + tx_timer_deactivate(&timer_ulong_test); + tx_timer_delete(&timer_ulong_test); + + tx_thread_terminate(&thread_ptr_test); + tx_thread_delete(&thread_ptr_test); + tx_thread_terminate(&thread_ulong_test); + tx_thread_delete(&thread_ulong_test); + + if (error) + { + printf("ERROR!\n"); + test_control_return(1); + } + else + { + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void threadx_pointer_callback_application_define(void *first_unused_memory) +#endif +{ + UINT status; + CHAR *pointer = (CHAR *) first_unused_memory; + + /* Create primary test thread. */ + status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, 2048, + 10, 10, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer += 2048; + + /* Create pointer callback thread. */ + status += tx_thread_create_ptr(&thread_ptr_test, "ptr thread", thread_ptr_entry, TEST_PTR_VAL_1, + pointer, 2048, + 12, 12, TX_NO_TIME_SLICE, TX_DONT_START); + pointer += 2048; + + /* Create standard ULONG callback thread. */ + status += tx_thread_create(&thread_ulong_test, "ulong thread", thread_ulong_entry, TEST_ULONG_VAL_1, + pointer, 2048, + 12, 12, TX_NO_TIME_SLICE, TX_DONT_START); + pointer += 2048; + + /* Create pointer timer. */ + status += tx_timer_create_ptr(&timer_ptr_test, "ptr timer", timer_ptr_expiration, TEST_PTR_VAL_2, + 2, 0, TX_AUTO_ACTIVATE); + + /* Create standard ULONG timer. */ + status += tx_timer_create(&timer_ulong_test, "ulong timer", timer_ulong_expiration, TEST_ULONG_VAL_2, + 2, 0, TX_AUTO_ACTIVATE); + + if (status != TX_SUCCESS) + { + printf("Running Pointer Callback Regression Test............................ INITIALIZATION ERROR!\n"); + test_control_return(1); + } +} + +#ifndef CTEST +void test_control_return(UINT status) +{ + exit((int) status); +} + +int main(void) +{ + tx_kernel_enter(); + return 0; +} + +void tx_application_define(void *first_unused_memory) +{ + threadx_pointer_callback_application_define(first_unused_memory); +} +#endif diff --git a/test/tx/cmake/regression/CMakeLists.txt b/test/tx/cmake/regression/CMakeLists.txt index 6b94a8576..e4259f556 100644 --- a/test/tx/cmake/regression/CMakeLists.txt +++ b/test/tx/cmake/regression/CMakeLists.txt @@ -113,7 +113,8 @@ set(regression_test_cases ${SOURCE_DIR}/threadx_timer_simple_test.c ${SOURCE_DIR}/threadx_trace_basic_test.c ${SOURCE_DIR}/threadx_trace_entry_update_test.c - ${SOURCE_DIR}/threadx_initialize_kernel_setup_test.c) + ${SOURCE_DIR}/threadx_initialize_kernel_setup_test.c + ${SOURCE_DIR}/threadx_pointer_callback_test.c) add_custom_command( OUTPUT ${GENERATED_LOW_LEVEL_SOURCE} diff --git a/test/tx/regression/threadx_pointer_callback_test.c b/test/tx/regression/threadx_pointer_callback_test.c new file mode 100644 index 000000000..0726f5219 --- /dev/null +++ b/test/tx/regression/threadx_pointer_callback_test.c @@ -0,0 +1,284 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * Copyright (c) 2026-present Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * SPDX-License-Identifier: MIT + **************************************************************************/ + +#include +#include +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + +/* Define test control globals for standalone execution. */ +#ifndef CTEST +void test_control_return(UINT status); +#else +extern void test_control_return(UINT status); +#endif + +static unsigned long error = 0; + +static TX_THREAD thread_0; +static TX_THREAD thread_ptr_test; +static TX_THREAD thread_ulong_test; + +static TX_TIMER timer_ptr_test; +static TX_TIMER timer_ulong_test; + +static void *received_thread_ptr_ctx = TX_NULL; +static void *received_timer_ptr_ctx = TX_NULL; +static ULONG received_thread_ulong_ctx = 0; +static ULONG received_timer_ulong_ctx = 0; + +static volatile UINT thread_ptr_executed = 0; +static volatile UINT thread_ulong_executed = 0; +static volatile UINT timer_ptr_executed = 0; +static volatile UINT timer_ulong_executed = 0; + +#if (defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) || (defined(__riscv_xlen) && (__riscv_xlen == 64)) || defined(__LP64__) || defined(_LP64)) +#define TEST_PTR_VAL_1 ((VOID *)(ALIGN_TYPE) 0x123456789ABCDEF0ULL) +#define TEST_PTR_VAL_2 ((VOID *)(ALIGN_TYPE) 0xDEADBEEFCAFEBABEULL) +#else +#define TEST_PTR_VAL_1 ((VOID *)(ALIGN_TYPE) 0x12345678UL) +#define TEST_PTR_VAL_2 ((VOID *)(ALIGN_TYPE) 0xDEADBEEFUL) +#endif +#define TEST_ULONG_VAL_1 ((ULONG) 0x55AA1234UL) +#define TEST_ULONG_VAL_2 ((ULONG) 0x99887766UL) + +static void thread_ptr_entry(VOID *entry_input) +{ + received_thread_ptr_ctx = entry_input; + thread_ptr_executed = 1; + while (1) + { + tx_thread_sleep(100); + } +} + +static void thread_ulong_entry(ULONG entry_input) +{ + received_thread_ulong_ctx = entry_input; + thread_ulong_executed = 1; + while (1) + { + tx_thread_sleep(100); + } +} + +static void timer_ptr_expiration(VOID *expiration_input) +{ + received_timer_ptr_ctx = expiration_input; + timer_ptr_executed = 1; +} + +static void timer_ulong_expiration(ULONG expiration_input) +{ + received_timer_ulong_ctx = expiration_input; + timer_ulong_executed = 1; +} + +static void thread_0_entry(ULONG thread_input) +{ + UINT status; + VOID *expected_thread_ptr = TEST_PTR_VAL_1; + VOID *expected_timer_ptr = TEST_PTR_VAL_2; + + TX_PARAMETER_NOT_USED(thread_input); + + printf("Running Pointer Callback Regression Test............................ "); + + /* Resume pointer thread and standard thread. */ + tx_thread_resume(&thread_ptr_test); + tx_thread_resume(&thread_ulong_test); + + /* Sleep to allow threads and timers to execute. */ + tx_thread_sleep(5); + + /* Verify pointer thread context reception without 32-bit truncation. */ + if (thread_ptr_executed != 1) + { + error++; + } + if (received_thread_ptr_ctx != expected_thread_ptr) + { + error++; + } + + /* Verify standard ULONG thread context reception. */ + if (thread_ulong_executed != 1) + { + error++; + } + if (received_thread_ulong_ctx != TEST_ULONG_VAL_1) + { + error++; + } + + /* Verify pointer timer context reception without 32-bit truncation. */ + if (timer_ptr_executed != 1) + { + error++; + } + if (received_timer_ptr_ctx != expected_timer_ptr) + { + error++; + } + + /* Verify standard ULONG timer context reception. */ + if (timer_ulong_executed != 1) + { + error++; + } + if (received_timer_ulong_ctx != TEST_ULONG_VAL_2) + { + error++; + } + +#ifndef TX_DISABLE_ERROR_CHECKING + TX_THREAD dummy_thread; + TX_TIMER dummy_timer; + CHAR dummy_stack[1024]; + + dummy_thread.tx_thread_id = 0; + dummy_timer.tx_timer_id = 0; + + /* Test error checking paths for pointer thread create. */ + status = tx_thread_create_ptr(TX_NULL, "bad", thread_ptr_entry, expected_thread_ptr, + dummy_stack, sizeof(dummy_stack), 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_THREAD_ERROR) + { + error++; + } + + status = tx_thread_create_ptr(&dummy_thread, "bad", TX_NULL, expected_thread_ptr, + dummy_stack, sizeof(dummy_stack), 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_PTR_ERROR) + { + error++; + } + + status = tx_thread_create_ptr(&dummy_thread, "bad", thread_ptr_entry, expected_thread_ptr, + TX_NULL, sizeof(dummy_stack), 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_PTR_ERROR) + { + error++; + } + + status = tx_thread_create_ptr(&dummy_thread, "bad", thread_ptr_entry, expected_thread_ptr, + dummy_stack, 0, 16, 16, TX_NO_TIME_SLICE, TX_DONT_START); + if (status != TX_SIZE_ERROR) + { + error++; + } + + /* Test error checking paths for pointer timer create. */ + status = tx_timer_create_ptr(TX_NULL, "bad", timer_ptr_expiration, expected_timer_ptr, + 1, 0, TX_NO_ACTIVATE); + if (status != TX_TIMER_ERROR) + { + error++; + } + + status = tx_timer_create_ptr(&dummy_timer, "bad", timer_ptr_expiration, expected_timer_ptr, + 0, 0, TX_NO_ACTIVATE); + if (status != TX_TICK_ERROR) + { + error++; + } + + status = tx_timer_create_ptr(&dummy_timer, "bad", timer_ptr_expiration, expected_timer_ptr, + 1, 0, 0xFF); + if (status != TX_ACTIVATE_ERROR) + { + error++; + } +#endif + + /* Clean up created objects. */ + tx_timer_deactivate(&timer_ptr_test); + tx_timer_delete(&timer_ptr_test); + tx_timer_deactivate(&timer_ulong_test); + tx_timer_delete(&timer_ulong_test); + + tx_thread_terminate(&thread_ptr_test); + tx_thread_delete(&thread_ptr_test); + tx_thread_terminate(&thread_ulong_test); + tx_thread_delete(&thread_ulong_test); + + if (error) + { + printf("ERROR!\n"); + test_control_return(1); + } + else + { + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +#ifdef CTEST +void test_application_define(void *first_unused_memory) +#else +void threadx_pointer_callback_application_define(void *first_unused_memory) +#endif +{ + UINT status; + CHAR *pointer = (CHAR *) first_unused_memory; + + /* Create primary test thread. */ + status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, 2048, + 10, 10, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer += 2048; + + /* Create pointer callback thread. */ + status += tx_thread_create_ptr(&thread_ptr_test, "ptr thread", thread_ptr_entry, TEST_PTR_VAL_1, + pointer, 2048, + 12, 12, TX_NO_TIME_SLICE, TX_DONT_START); + pointer += 2048; + + /* Create standard ULONG callback thread. */ + status += tx_thread_create(&thread_ulong_test, "ulong thread", thread_ulong_entry, TEST_ULONG_VAL_1, + pointer, 2048, + 12, 12, TX_NO_TIME_SLICE, TX_DONT_START); + pointer += 2048; + + /* Create pointer timer. */ + status += tx_timer_create_ptr(&timer_ptr_test, "ptr timer", timer_ptr_expiration, TEST_PTR_VAL_2, + 2, 0, TX_AUTO_ACTIVATE); + + /* Create standard ULONG timer. */ + status += tx_timer_create(&timer_ulong_test, "ulong timer", timer_ulong_expiration, TEST_ULONG_VAL_2, + 2, 0, TX_AUTO_ACTIVATE); + + if (status != TX_SUCCESS) + { + printf("Running Pointer Callback Regression Test............................ INITIALIZATION ERROR!\n"); + test_control_return(1); + } +} + +#ifndef CTEST +void test_control_return(UINT status) +{ + exit((int) status); +} + +int main(void) +{ + tx_kernel_enter(); + return 0; +} + +void tx_application_define(void *first_unused_memory) +{ + threadx_pointer_callback_application_define(first_unused_memory); +} +#endif