From 6d161083672e06a7e3118abc18b64eba6c90b509 Mon Sep 17 00:00:00 2001 From: iorebuild Date: Mon, 30 Jun 2025 20:12:55 +0800 Subject: [PATCH] first commit --- common/inc/tx_api.h | 2394 +++++++++++++++++ common/inc/tx_block_pool.h | 147 + common/inc/tx_byte_pool.h | 178 ++ common/inc/tx_event_flags.h | 148 + common/inc/tx_initialize.h | 112 + common/inc/tx_mutex.h | 161 ++ common/inc/tx_queue.h | 174 ++ common/inc/tx_semaphore.h | 145 + common/inc/tx_thread.h | 533 ++++ common/inc/tx_timer.h | 214 ++ common/inc/tx_trace.h | 560 ++++ common/inc/tx_user_sample.h | 317 +++ common/src/tx_block_allocate.c | 373 +++ common/src/tx_block_pool_cleanup.c | 214 ++ common/src/tx_block_pool_create.c | 214 ++ common/src/tx_block_pool_delete.c | 208 ++ common/src/tx_block_pool_info_get.c | 147 + common/src/tx_block_pool_initialize.c | 132 + .../src/tx_block_pool_performance_info_get.c | 202 ++ ...x_block_pool_performance_system_info_get.c | 174 ++ common/src/tx_block_pool_prioritize.c | 250 ++ common/src/tx_block_release.c | 205 ++ common/src/tx_byte_allocate.c | 410 +++ common/src/tx_byte_pool_cleanup.c | 213 ++ common/src/tx_byte_pool_create.c | 198 ++ common/src/tx_byte_pool_delete.c | 212 ++ common/src/tx_byte_pool_info_get.c | 147 + common/src/tx_byte_pool_initialize.c | 150 ++ .../src/tx_byte_pool_performance_info_get.c | 254 ++ ...tx_byte_pool_performance_system_info_get.c | 222 ++ common/src/tx_byte_pool_prioritize.c | 250 ++ common/src/tx_byte_pool_search.c | 353 +++ common/src/tx_byte_release.c | 377 +++ common/src/tx_event_flags_cleanup.c | 238 ++ common/src/tx_event_flags_create.c | 142 + common/src/tx_event_flags_delete.c | 208 ++ common/src/tx_event_flags_get.c | 406 +++ common/src/tx_event_flags_info_get.c | 144 + common/src/tx_event_flags_initialize.c | 133 + .../src/tx_event_flags_performance_info_get.c | 203 ++ ..._event_flags_performance_system_info_get.c | 175 ++ common/src/tx_event_flags_set.c | 624 +++++ common/src/tx_event_flags_set_notify.c | 108 + common/src/tx_initialize_high_level.c | 151 ++ common/src/tx_initialize_kernel_enter.c | 167 ++ common/src/tx_initialize_kernel_setup.c | 101 + common/src/tx_misra.c | 835 ++++++ common/src/tx_mutex_cleanup.c | 316 +++ common/src/tx_mutex_create.c | 147 + common/src/tx_mutex_delete.c | 244 ++ common/src/tx_mutex_get.c | 410 +++ common/src/tx_mutex_info_get.c | 148 + common/src/tx_mutex_initialize.c | 144 + common/src/tx_mutex_performance_info_get.c | 231 ++ .../tx_mutex_performance_system_info_get.c | 206 ++ common/src/tx_mutex_prioritize.c | 266 ++ common/src/tx_mutex_priority_change.c | 338 +++ common/src/tx_mutex_put.c | 655 +++++ common/src/tx_queue_cleanup.c | 226 ++ common/src/tx_queue_create.c | 171 ++ common/src/tx_queue_delete.c | 207 ++ common/src/tx_queue_flush.c | 206 ++ common/src/tx_queue_front_send.c | 422 +++ common/src/tx_queue_info_get.c | 146 + common/src/tx_queue_initialize.c | 141 + common/src/tx_queue_performance_info_get.c | 230 ++ .../tx_queue_performance_system_info_get.c | 206 ++ common/src/tx_queue_prioritize.c | 250 ++ common/src/tx_queue_receive.c | 487 ++++ common/src/tx_queue_send.c | 427 +++ common/src/tx_queue_send_notify.c | 108 + common/src/tx_semaphore_ceiling_put.c | 244 ++ common/src/tx_semaphore_cleanup.c | 216 ++ common/src/tx_semaphore_create.c | 143 + common/src/tx_semaphore_delete.c | 208 ++ common/src/tx_semaphore_get.c | 233 ++ common/src/tx_semaphore_info_get.c | 140 + common/src/tx_semaphore_initialize.c | 132 + .../src/tx_semaphore_performance_info_get.c | 202 ++ ...tx_semaphore_performance_system_info_get.c | 175 ++ common/src/tx_semaphore_prioritize.c | 252 ++ common/src/tx_semaphore_put.c | 223 ++ common/src/tx_semaphore_put_notify.c | 108 + common/src/tx_thread_create.c | 390 +++ common/src/tx_thread_delete.c | 167 ++ common/src/tx_thread_entry_exit_notify.c | 110 + common/src/tx_thread_identify.c | 104 + common/src/tx_thread_info_get.c | 164 ++ common/src/tx_thread_initialize.c | 455 ++++ common/src/tx_thread_performance_info_get.c | 298 ++ .../tx_thread_performance_system_info_get.c | 288 ++ common/src/tx_thread_preemption_change.c | 281 ++ common/src/tx_thread_priority_change.c | 286 ++ common/src/tx_thread_relinquish.c | 170 ++ common/src/tx_thread_reset.c | 164 ++ common/src/tx_thread_resume.c | 582 ++++ common/src/tx_thread_shell_entry.c | 202 ++ common/src/tx_thread_sleep.c | 199 ++ common/src/tx_thread_stack_analyze.c | 182 ++ common/src/tx_thread_stack_error_handler.c | 119 + common/src/tx_thread_stack_error_notify.c | 133 + common/src/tx_thread_suspend.c | 848 ++++++ common/src/tx_thread_system_preempt_check.c | 128 + common/src/tx_thread_system_resume.c | 1003 +++++++ common/src/tx_thread_system_suspend.c | 1219 +++++++++ common/src/tx_thread_terminate.c | 311 +++ common/src/tx_thread_time_slice.c | 189 ++ common/src/tx_thread_time_slice_change.c | 118 + common/src/tx_thread_timeout.c | 166 ++ common/src/tx_thread_wait_abort.c | 246 ++ common/src/tx_time_get.c | 103 + common/src/tx_time_set.c | 93 + common/src/tx_timer_activate.c | 136 + common/src/tx_timer_change.c | 104 + common/src/tx_timer_create.c | 168 ++ common/src/tx_timer_deactivate.c | 251 ++ common/src/tx_timer_delete.c | 143 + common/src/tx_timer_expiration_process.c | 482 ++++ common/src/tx_timer_info_get.c | 249 ++ common/src/tx_timer_initialize.c | 305 +++ common/src/tx_timer_performance_info_get.c | 215 ++ .../tx_timer_performance_system_info_get.c | 188 ++ common/src/tx_timer_system_activate.c | 169 ++ common/src/tx_timer_system_deactivate.c | 133 + common/src/tx_timer_thread_entry.c | 481 ++++ common/src/tx_trace_buffer_full_notify.c | 110 + common/src/tx_trace_disable.c | 104 + common/src/tx_trace_enable.c | 443 +++ common/src/tx_trace_event_filter.c | 107 + common/src/tx_trace_event_unfilter.c | 107 + common/src/tx_trace_initialize.c | 153 ++ common/src/tx_trace_interrupt_control.c | 105 + common/src/tx_trace_isr_enter_insert.c | 109 + common/src/tx_trace_isr_exit_insert.c | 109 + common/src/tx_trace_object_register.c | 301 +++ common/src/tx_trace_object_unregister.c | 132 + common/src/tx_trace_user_event_insert.c | 161 ++ common/src/txe_block_allocate.c | 161 ++ common/src/txe_block_pool_create.c | 228 ++ common/src/txe_block_pool_delete.c | 147 + common/src/txe_block_pool_info_get.c | 115 + common/src/txe_block_pool_prioritize.c | 102 + common/src/txe_block_release.c | 124 + common/src/txe_byte_allocate.c | 200 ++ common/src/txe_byte_pool_create.c | 223 ++ common/src/txe_byte_pool_delete.c | 145 + common/src/txe_byte_pool_info_get.c | 114 + common/src/txe_byte_pool_prioritize.c | 102 + common/src/txe_byte_release.c | 136 + common/src/txe_event_flags_create.c | 204 ++ common/src/txe_event_flags_delete.c | 147 + common/src/txe_event_flags_get.c | 178 ++ common/src/txe_event_flags_info_get.c | 116 + common/src/txe_event_flags_set.c | 127 + common/src/txe_event_flags_set_notify.c | 105 + common/src/txe_mutex_create.c | 222 ++ common/src/txe_mutex_delete.c | 147 + common/src/txe_mutex_get.c | 169 ++ common/src/txe_mutex_info_get.c | 115 + common/src/txe_mutex_prioritize.c | 102 + common/src/txe_mutex_put.c | 125 + common/src/txe_queue_create.c | 238 ++ common/src/txe_queue_delete.c | 143 + common/src/txe_queue_flush.c | 103 + common/src/txe_queue_front_send.c | 159 ++ common/src/txe_queue_info_get.c | 113 + common/src/txe_queue_prioritize.c | 99 + common/src/txe_queue_receive.c | 161 ++ common/src/txe_queue_send.c | 159 ++ common/src/txe_queue_send_notify.c | 104 + common/src/txe_semaphore_ceiling_put.c | 114 + common/src/txe_semaphore_create.c | 209 ++ common/src/txe_semaphore_delete.c | 144 + common/src/txe_semaphore_get.c | 149 + common/src/txe_semaphore_info_get.c | 114 + common/src/txe_semaphore_prioritize.c | 102 + common/src/txe_semaphore_put.c | 102 + common/src/txe_semaphore_put_notify.c | 105 + common/src/txe_thread_create.c | 312 +++ common/src/txe_thread_delete.c | 111 + common/src/txe_thread_entry_exit_notify.c | 105 + common/src/txe_thread_info_get.c | 118 + common/src/txe_thread_preemption_change.c | 131 + common/src/txe_thread_priority_change.c | 132 + common/src/txe_thread_relinquish.c | 93 + common/src/txe_thread_reset.c | 137 + common/src/txe_thread_resume.c | 102 + common/src/txe_thread_suspend.c | 104 + common/src/txe_thread_terminate.c | 113 + common/src/txe_thread_time_slice_change.c | 123 + common/src/txe_thread_wait_abort.c | 102 + common/src/txe_timer_activate.c | 102 + common/src/txe_timer_change.c | 125 + common/src/txe_timer_create.c | 238 ++ common/src/txe_timer_deactivate.c | 103 + common/src/txe_timer_delete.c | 144 + common/src/txe_timer_info_get.c | 111 + ports/cortex_m3/ac5/inc/tx_port.h | 728 +++++ .../ac5/src/tx_thread_context_restore.s | 88 + .../ac5/src/tx_thread_context_save.s | 90 + .../ac5/src/tx_thread_interrupt_control.s | 82 + .../ac5/src/tx_thread_interrupt_disable.s | 82 + .../ac5/src/tx_thread_interrupt_restore.s | 80 + ports/cortex_m3/ac5/src/tx_thread_schedule.s | 330 +++ .../cortex_m3/ac5/src/tx_thread_stack_build.s | 136 + .../ac5/src/tx_thread_system_return.s | 96 + ports/cortex_m3/ac5/src/tx_timer_interrupt.s | 264 ++ ports/cortex_m3/ac6/inc/tx_port.h | 728 +++++ ports/cortex_m3/ac6/src/tx_misra.S | 722 +++++ .../ac6/src/tx_thread_context_restore.S | 87 + .../ac6/src/tx_thread_context_save.S | 88 + .../ac6/src/tx_thread_interrupt_control.S | 84 + .../ac6/src/tx_thread_interrupt_disable.S | 84 + .../ac6/src/tx_thread_interrupt_restore.S | 81 + ports/cortex_m3/ac6/src/tx_thread_schedule.S | 330 +++ .../cortex_m3/ac6/src/tx_thread_stack_build.S | 138 + .../ac6/src/tx_thread_system_return.S | 98 + ports/cortex_m3/ac6/src/tx_timer_interrupt.S | 260 ++ ports/cortex_m3/ghs/inc/tx_el.h | 764 ++++++ ports/cortex_m3/ghs/inc/tx_ghs.h | 77 + ports/cortex_m3/ghs/inc/tx_port.h | 391 +++ ports/cortex_m3/ghs/src/tx_el.c | 1164 ++++++++ ports/cortex_m3/ghs/src/tx_ghs.c | 485 ++++ ports/cortex_m3/ghs/src/tx_ghse.c | 49 + .../ghs/src/tx_thread_context_restore.arm | 86 + .../ghs/src/tx_thread_context_save.arm | 84 + .../ghs/src/tx_thread_interrupt_control.arm | 74 + .../ghs/src/tx_thread_interrupt_disable.arm | 84 + .../ghs/src/tx_thread_interrupt_restore.arm | 75 + .../cortex_m3/ghs/src/tx_thread_schedule.arm | 252 ++ .../ghs/src/tx_thread_stack_build.arm | 134 + .../ghs/src/tx_thread_system_return.arm | 86 + .../cortex_m3/ghs/src/tx_timer_interrupt.arm | 242 ++ ports/cortex_m3/ghs/src/txr_ghs.c | 84 + ports/cortex_m3/gnu/inc/tx_port.h | 728 +++++ ports/cortex_m3/gnu/src/tx_misra.S | 722 +++++ .../gnu/src/tx_thread_context_restore.S | 87 + .../gnu/src/tx_thread_context_save.S | 85 + .../gnu/src/tx_thread_interrupt_control.S | 84 + .../gnu/src/tx_thread_interrupt_disable.S | 84 + .../gnu/src/tx_thread_interrupt_restore.S | 81 + ports/cortex_m3/gnu/src/tx_thread_schedule.S | 330 +++ .../cortex_m3/gnu/src/tx_thread_stack_build.S | 138 + .../gnu/src/tx_thread_system_return.S | 98 + ports/cortex_m3/gnu/src/tx_timer_interrupt.S | 260 ++ ports/cortex_m3/iar/inc/tx_port.h | 728 +++++ ports/cortex_m3/iar/src/tx_iar.c | 803 ++++++ ports/cortex_m3/iar/src/tx_misra.s | 766 ++++++ .../iar/src/tx_thread_context_restore.s | 83 + .../iar/src/tx_thread_context_save.s | 85 + .../iar/src/tx_thread_interrupt_control.s | 83 + .../iar/src/tx_thread_interrupt_disable.s | 83 + .../iar/src/tx_thread_interrupt_restore.s | 80 + ports/cortex_m3/iar/src/tx_thread_schedule.s | 323 +++ .../cortex_m3/iar/src/tx_thread_stack_build.s | 137 + .../iar/src/tx_thread_system_return.s | 97 + ports/cortex_m3/iar/src/tx_timer_interrupt.s | 262 ++ ports/cortex_m3/keil/inc/tx_port.h | 728 +++++ .../keil/src/tx_thread_context_restore.s | 90 + .../keil/src/tx_thread_context_save.s | 90 + .../keil/src/tx_thread_interrupt_control.s | 75 + .../keil/src/tx_thread_interrupt_disable.s | 74 + .../keil/src/tx_thread_interrupt_restore.s | 73 + ports/cortex_m3/keil/src/tx_thread_schedule.s | 263 ++ .../keil/src/tx_thread_stack_build.s | 132 + .../keil/src/tx_thread_system_return.s | 84 + ports/cortex_m3/keil/src/tx_timer_interrupt.s | 258 ++ 267 files changed, 61193 insertions(+) create mode 100644 common/inc/tx_api.h create mode 100644 common/inc/tx_block_pool.h create mode 100644 common/inc/tx_byte_pool.h create mode 100644 common/inc/tx_event_flags.h create mode 100644 common/inc/tx_initialize.h create mode 100644 common/inc/tx_mutex.h create mode 100644 common/inc/tx_queue.h create mode 100644 common/inc/tx_semaphore.h create mode 100644 common/inc/tx_thread.h create mode 100644 common/inc/tx_timer.h create mode 100644 common/inc/tx_trace.h create mode 100644 common/inc/tx_user_sample.h create mode 100644 common/src/tx_block_allocate.c create mode 100644 common/src/tx_block_pool_cleanup.c create mode 100644 common/src/tx_block_pool_create.c create mode 100644 common/src/tx_block_pool_delete.c create mode 100644 common/src/tx_block_pool_info_get.c create mode 100644 common/src/tx_block_pool_initialize.c create mode 100644 common/src/tx_block_pool_performance_info_get.c create mode 100644 common/src/tx_block_pool_performance_system_info_get.c create mode 100644 common/src/tx_block_pool_prioritize.c create mode 100644 common/src/tx_block_release.c create mode 100644 common/src/tx_byte_allocate.c create mode 100644 common/src/tx_byte_pool_cleanup.c create mode 100644 common/src/tx_byte_pool_create.c create mode 100644 common/src/tx_byte_pool_delete.c create mode 100644 common/src/tx_byte_pool_info_get.c create mode 100644 common/src/tx_byte_pool_initialize.c create mode 100644 common/src/tx_byte_pool_performance_info_get.c create mode 100644 common/src/tx_byte_pool_performance_system_info_get.c create mode 100644 common/src/tx_byte_pool_prioritize.c create mode 100644 common/src/tx_byte_pool_search.c create mode 100644 common/src/tx_byte_release.c create mode 100644 common/src/tx_event_flags_cleanup.c create mode 100644 common/src/tx_event_flags_create.c create mode 100644 common/src/tx_event_flags_delete.c create mode 100644 common/src/tx_event_flags_get.c create mode 100644 common/src/tx_event_flags_info_get.c create mode 100644 common/src/tx_event_flags_initialize.c create mode 100644 common/src/tx_event_flags_performance_info_get.c create mode 100644 common/src/tx_event_flags_performance_system_info_get.c create mode 100644 common/src/tx_event_flags_set.c create mode 100644 common/src/tx_event_flags_set_notify.c create mode 100644 common/src/tx_initialize_high_level.c create mode 100644 common/src/tx_initialize_kernel_enter.c create mode 100644 common/src/tx_initialize_kernel_setup.c create mode 100644 common/src/tx_misra.c create mode 100644 common/src/tx_mutex_cleanup.c create mode 100644 common/src/tx_mutex_create.c create mode 100644 common/src/tx_mutex_delete.c create mode 100644 common/src/tx_mutex_get.c create mode 100644 common/src/tx_mutex_info_get.c create mode 100644 common/src/tx_mutex_initialize.c create mode 100644 common/src/tx_mutex_performance_info_get.c create mode 100644 common/src/tx_mutex_performance_system_info_get.c create mode 100644 common/src/tx_mutex_prioritize.c create mode 100644 common/src/tx_mutex_priority_change.c create mode 100644 common/src/tx_mutex_put.c create mode 100644 common/src/tx_queue_cleanup.c create mode 100644 common/src/tx_queue_create.c create mode 100644 common/src/tx_queue_delete.c create mode 100644 common/src/tx_queue_flush.c create mode 100644 common/src/tx_queue_front_send.c create mode 100644 common/src/tx_queue_info_get.c create mode 100644 common/src/tx_queue_initialize.c create mode 100644 common/src/tx_queue_performance_info_get.c create mode 100644 common/src/tx_queue_performance_system_info_get.c create mode 100644 common/src/tx_queue_prioritize.c create mode 100644 common/src/tx_queue_receive.c create mode 100644 common/src/tx_queue_send.c create mode 100644 common/src/tx_queue_send_notify.c create mode 100644 common/src/tx_semaphore_ceiling_put.c create mode 100644 common/src/tx_semaphore_cleanup.c create mode 100644 common/src/tx_semaphore_create.c create mode 100644 common/src/tx_semaphore_delete.c create mode 100644 common/src/tx_semaphore_get.c create mode 100644 common/src/tx_semaphore_info_get.c create mode 100644 common/src/tx_semaphore_initialize.c create mode 100644 common/src/tx_semaphore_performance_info_get.c create mode 100644 common/src/tx_semaphore_performance_system_info_get.c create mode 100644 common/src/tx_semaphore_prioritize.c create mode 100644 common/src/tx_semaphore_put.c create mode 100644 common/src/tx_semaphore_put_notify.c create mode 100644 common/src/tx_thread_create.c create mode 100644 common/src/tx_thread_delete.c create mode 100644 common/src/tx_thread_entry_exit_notify.c create mode 100644 common/src/tx_thread_identify.c create mode 100644 common/src/tx_thread_info_get.c create mode 100644 common/src/tx_thread_initialize.c create mode 100644 common/src/tx_thread_performance_info_get.c create mode 100644 common/src/tx_thread_performance_system_info_get.c create mode 100644 common/src/tx_thread_preemption_change.c create mode 100644 common/src/tx_thread_priority_change.c create mode 100644 common/src/tx_thread_relinquish.c create mode 100644 common/src/tx_thread_reset.c create mode 100644 common/src/tx_thread_resume.c create mode 100644 common/src/tx_thread_shell_entry.c create mode 100644 common/src/tx_thread_sleep.c create mode 100644 common/src/tx_thread_stack_analyze.c create mode 100644 common/src/tx_thread_stack_error_handler.c create mode 100644 common/src/tx_thread_stack_error_notify.c create mode 100644 common/src/tx_thread_suspend.c create mode 100644 common/src/tx_thread_system_preempt_check.c create mode 100644 common/src/tx_thread_system_resume.c create mode 100644 common/src/tx_thread_system_suspend.c create mode 100644 common/src/tx_thread_terminate.c create mode 100644 common/src/tx_thread_time_slice.c create mode 100644 common/src/tx_thread_time_slice_change.c create mode 100644 common/src/tx_thread_timeout.c create mode 100644 common/src/tx_thread_wait_abort.c create mode 100644 common/src/tx_time_get.c create mode 100644 common/src/tx_time_set.c create mode 100644 common/src/tx_timer_activate.c create mode 100644 common/src/tx_timer_change.c create mode 100644 common/src/tx_timer_create.c create mode 100644 common/src/tx_timer_deactivate.c create mode 100644 common/src/tx_timer_delete.c create mode 100644 common/src/tx_timer_expiration_process.c create mode 100644 common/src/tx_timer_info_get.c create mode 100644 common/src/tx_timer_initialize.c create mode 100644 common/src/tx_timer_performance_info_get.c create mode 100644 common/src/tx_timer_performance_system_info_get.c create mode 100644 common/src/tx_timer_system_activate.c create mode 100644 common/src/tx_timer_system_deactivate.c create mode 100644 common/src/tx_timer_thread_entry.c create mode 100644 common/src/tx_trace_buffer_full_notify.c create mode 100644 common/src/tx_trace_disable.c create mode 100644 common/src/tx_trace_enable.c create mode 100644 common/src/tx_trace_event_filter.c create mode 100644 common/src/tx_trace_event_unfilter.c create mode 100644 common/src/tx_trace_initialize.c create mode 100644 common/src/tx_trace_interrupt_control.c create mode 100644 common/src/tx_trace_isr_enter_insert.c create mode 100644 common/src/tx_trace_isr_exit_insert.c create mode 100644 common/src/tx_trace_object_register.c create mode 100644 common/src/tx_trace_object_unregister.c create mode 100644 common/src/tx_trace_user_event_insert.c create mode 100644 common/src/txe_block_allocate.c create mode 100644 common/src/txe_block_pool_create.c create mode 100644 common/src/txe_block_pool_delete.c create mode 100644 common/src/txe_block_pool_info_get.c create mode 100644 common/src/txe_block_pool_prioritize.c create mode 100644 common/src/txe_block_release.c create mode 100644 common/src/txe_byte_allocate.c create mode 100644 common/src/txe_byte_pool_create.c create mode 100644 common/src/txe_byte_pool_delete.c create mode 100644 common/src/txe_byte_pool_info_get.c create mode 100644 common/src/txe_byte_pool_prioritize.c create mode 100644 common/src/txe_byte_release.c create mode 100644 common/src/txe_event_flags_create.c create mode 100644 common/src/txe_event_flags_delete.c create mode 100644 common/src/txe_event_flags_get.c create mode 100644 common/src/txe_event_flags_info_get.c create mode 100644 common/src/txe_event_flags_set.c create mode 100644 common/src/txe_event_flags_set_notify.c create mode 100644 common/src/txe_mutex_create.c create mode 100644 common/src/txe_mutex_delete.c create mode 100644 common/src/txe_mutex_get.c create mode 100644 common/src/txe_mutex_info_get.c create mode 100644 common/src/txe_mutex_prioritize.c create mode 100644 common/src/txe_mutex_put.c create mode 100644 common/src/txe_queue_create.c create mode 100644 common/src/txe_queue_delete.c create mode 100644 common/src/txe_queue_flush.c create mode 100644 common/src/txe_queue_front_send.c create mode 100644 common/src/txe_queue_info_get.c create mode 100644 common/src/txe_queue_prioritize.c create mode 100644 common/src/txe_queue_receive.c create mode 100644 common/src/txe_queue_send.c create mode 100644 common/src/txe_queue_send_notify.c create mode 100644 common/src/txe_semaphore_ceiling_put.c create mode 100644 common/src/txe_semaphore_create.c create mode 100644 common/src/txe_semaphore_delete.c create mode 100644 common/src/txe_semaphore_get.c create mode 100644 common/src/txe_semaphore_info_get.c create mode 100644 common/src/txe_semaphore_prioritize.c create mode 100644 common/src/txe_semaphore_put.c create mode 100644 common/src/txe_semaphore_put_notify.c create mode 100644 common/src/txe_thread_create.c create mode 100644 common/src/txe_thread_delete.c create mode 100644 common/src/txe_thread_entry_exit_notify.c create mode 100644 common/src/txe_thread_info_get.c create mode 100644 common/src/txe_thread_preemption_change.c create mode 100644 common/src/txe_thread_priority_change.c create mode 100644 common/src/txe_thread_relinquish.c create mode 100644 common/src/txe_thread_reset.c create mode 100644 common/src/txe_thread_resume.c create mode 100644 common/src/txe_thread_suspend.c create mode 100644 common/src/txe_thread_terminate.c create mode 100644 common/src/txe_thread_time_slice_change.c create mode 100644 common/src/txe_thread_wait_abort.c create mode 100644 common/src/txe_timer_activate.c create mode 100644 common/src/txe_timer_change.c create mode 100644 common/src/txe_timer_create.c create mode 100644 common/src/txe_timer_deactivate.c create mode 100644 common/src/txe_timer_delete.c create mode 100644 common/src/txe_timer_info_get.c create mode 100644 ports/cortex_m3/ac5/inc/tx_port.h create mode 100644 ports/cortex_m3/ac5/src/tx_thread_context_restore.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_context_save.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_interrupt_control.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_interrupt_disable.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_interrupt_restore.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_schedule.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_stack_build.s create mode 100644 ports/cortex_m3/ac5/src/tx_thread_system_return.s create mode 100644 ports/cortex_m3/ac5/src/tx_timer_interrupt.s create mode 100644 ports/cortex_m3/ac6/inc/tx_port.h create mode 100644 ports/cortex_m3/ac6/src/tx_misra.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_context_restore.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_context_save.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_interrupt_control.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_interrupt_disable.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_interrupt_restore.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_schedule.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_stack_build.S create mode 100644 ports/cortex_m3/ac6/src/tx_thread_system_return.S create mode 100644 ports/cortex_m3/ac6/src/tx_timer_interrupt.S create mode 100644 ports/cortex_m3/ghs/inc/tx_el.h create mode 100644 ports/cortex_m3/ghs/inc/tx_ghs.h create mode 100644 ports/cortex_m3/ghs/inc/tx_port.h create mode 100644 ports/cortex_m3/ghs/src/tx_el.c create mode 100644 ports/cortex_m3/ghs/src/tx_ghs.c create mode 100644 ports/cortex_m3/ghs/src/tx_ghse.c create mode 100644 ports/cortex_m3/ghs/src/tx_thread_context_restore.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_context_save.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_interrupt_control.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_interrupt_disable.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_interrupt_restore.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_schedule.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_stack_build.arm create mode 100644 ports/cortex_m3/ghs/src/tx_thread_system_return.arm create mode 100644 ports/cortex_m3/ghs/src/tx_timer_interrupt.arm create mode 100644 ports/cortex_m3/ghs/src/txr_ghs.c create mode 100644 ports/cortex_m3/gnu/inc/tx_port.h create mode 100644 ports/cortex_m3/gnu/src/tx_misra.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_context_restore.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_context_save.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_interrupt_control.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_interrupt_disable.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_interrupt_restore.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_schedule.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_stack_build.S create mode 100644 ports/cortex_m3/gnu/src/tx_thread_system_return.S create mode 100644 ports/cortex_m3/gnu/src/tx_timer_interrupt.S create mode 100644 ports/cortex_m3/iar/inc/tx_port.h create mode 100644 ports/cortex_m3/iar/src/tx_iar.c create mode 100644 ports/cortex_m3/iar/src/tx_misra.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_context_restore.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_context_save.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_interrupt_control.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_interrupt_disable.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_interrupt_restore.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_schedule.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_stack_build.s create mode 100644 ports/cortex_m3/iar/src/tx_thread_system_return.s create mode 100644 ports/cortex_m3/iar/src/tx_timer_interrupt.s create mode 100644 ports/cortex_m3/keil/inc/tx_port.h create mode 100644 ports/cortex_m3/keil/src/tx_thread_context_restore.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_context_save.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_interrupt_control.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_interrupt_disable.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_interrupt_restore.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_schedule.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_stack_build.s create mode 100644 ports/cortex_m3/keil/src/tx_thread_system_return.s create mode 100644 ports/cortex_m3/keil/src/tx_timer_interrupt.s diff --git a/common/inc/tx_api.h b/common/inc/tx_api.h new file mode 100644 index 0000000..3ff05f4 --- /dev/null +++ b/common/inc/tx_api.h @@ -0,0 +1,2394 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Application Interface (API) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* tx_api.h PORTABLE C */ +/* 6.4.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the basic Application Interface (API) to the */ +/* high-performance ThreadX real-time kernel. All service prototypes */ +/* and data structure definitions are defined in this file. */ +/* Please note that basic data type definitions and other architecture-*/ +/* specific information is contained in the file tx_port.h. */ +/* */ +/* 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 */ +/* updated product constants, */ +/* added new thread execution */ +/* state TX_PRIORITY_CHANGE, */ +/* added macros for casting */ +/* pointers to ALIGN_TYPE, */ +/* resulting in version 6.1 */ +/* 10-16-2020 William E. Lamie Modified comment(s), and */ +/* increased patch version, */ +/* resulting in version 6.1.1 */ +/* 11-09-2020 Yuxin Zhou Modified comment(s), and */ +/* moved TX_THREAD_GET_SYSTEM_ */ +/* STATE to tx_api.h, */ +/* resulting in version 6.1.2 */ +/* 12-31-2020 William E. Lamie Modified comment(s), and */ +/* increased patch version, */ +/* resulting in version 6.1.3 */ +/* 03-02-2021 Scott Larson Modified comment(s), and */ +/* order defines numerically, */ +/* add option to remove FileX */ +/* pointer, */ +/* resulting in version 6.1.5 */ +/* 04-02-2021 Scott Larson Modified comment(s), and */ +/* update patch number, */ +/* resulting in version 6.1.6 */ +/* 06-02-2021 Yuxin Zhou Modified comment(s), added */ +/* Execution Profile support, */ +/* resulting in version 6.1.7 */ +/* 08-02-2021 Scott Larson Modified comment(s), and */ +/* update patch number, */ +/* resulting in version 6.1.8 */ +/* 10-15-2021 Yuxin Zhou Modified comment(s), */ +/* update patch number, */ +/* resulting in version 6.1.9 */ +/* 01-31-2022 Scott Larson Modified comment(s), */ +/* add unused parameter macro, */ +/* update patch number, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Wenhui Xie Modified comment(s), */ +/* optimized the definition of */ +/* TX_TIMER_TICKS_PER_SECOND, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comment(s), */ +/* update patch number, */ +/* resulting in version 6.1.12 */ +/* 10-31-2022 Scott Larson Modified comment(s), */ +/* add extension macros, */ +/* update EPK typedef, */ +/* update version numbers, */ +/* resulting in version 6.2.0 */ +/* 03-08-2023 Tiejun Zhou Modified comment(s), */ +/* update patch number, */ +/* resulting in version 6.2.1 */ +/* 10-31-2023 Xiuwen Cai Modified comment(s), */ +/* added option for random */ +/* number stack filling, */ +/* resulting in version 6.3.0 */ +/* 12-31-2023 Tiejun Zhou Modified comment(s), */ +/* update version number, */ +/* resulting in version 6.4.0 */ +/* 03-01-2024 Tiejun Zhou Modified comment(s), */ +/* update version number, */ +/* resulting in version 6.4.1 */ +/* 02-19-2025 Frédéric Desbiens Modified comment(s), */ +/* update version number, */ +/* resulting in version 6.4.2 */ +/* */ +/**************************************************************************/ + +#ifndef TX_API_H +#define TX_API_H + + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Disable warning of parameter not used. */ +#ifndef TX_PARAMETER_NOT_USED +#define TX_PARAMETER_NOT_USED(p) ((void)(p)) +#endif /* TX_PARAMETER_NOT_USED */ + +/* Include the port-specific data type file. */ + +#include "tx_port.h" + +#if (defined(TX_EXECUTION_PROFILE_ENABLE) && !defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY)) +#include "tx_execution_profile.h" +#endif + +/* Define basic constants for the ThreadX kernel. */ + + +/* Define the major/minor version information that can be used by the application + and the ThreadX source as well. */ + +#define AZURE_RTOS_THREADX +#define THREADX_MAJOR_VERSION 6 +#define THREADX_MINOR_VERSION 4 +#define THREADX_PATCH_VERSION 2 + +/* Define the following symbol for backward compatibility */ +#define EL_PRODUCT_THREADX + + +/* API input parameters and general constants. */ + +#define TX_NO_WAIT ((ULONG) 0) +#define TX_WAIT_FOREVER ((ULONG) 0xFFFFFFFFUL) +#define TX_AND ((UINT) 2) +#define TX_AND_CLEAR ((UINT) 3) +#define TX_OR ((UINT) 0) +#define TX_OR_CLEAR ((UINT) 1) +#define TX_1_ULONG ((UINT) 1) +#define TX_2_ULONG ((UINT) 2) +#define TX_4_ULONG ((UINT) 4) +#define TX_8_ULONG ((UINT) 8) +#define TX_16_ULONG ((UINT) 16) +#define TX_NO_TIME_SLICE ((ULONG) 0) +#define TX_AUTO_START ((UINT) 1) +#define TX_DONT_START ((UINT) 0) +#define TX_AUTO_ACTIVATE ((UINT) 1) +#define TX_NO_ACTIVATE ((UINT) 0) +#define TX_TRUE ((UINT) 1) +#define TX_FALSE ((UINT) 0) +#define TX_NULL ((void *) 0) +#define TX_INHERIT ((UINT) 1) +#define TX_NO_INHERIT ((UINT) 0) +#define TX_THREAD_ENTRY ((UINT) 0) +#define TX_THREAD_EXIT ((UINT) 1) +#define TX_NO_SUSPENSIONS ((UINT) 0) +#define TX_NO_MESSAGES ((UINT) 0) +#define TX_EMPTY ((ULONG) 0) +#define TX_CLEAR_ID ((ULONG) 0) +#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) +#define TX_STACK_FILL (thread_ptr -> tx_thread_stack_fill_value) +#else +#define TX_STACK_FILL ((ULONG) 0xEFEFEFEFUL) +#endif + + +/* Thread execution state values. */ + +#define TX_READY ((UINT) 0) +#define TX_COMPLETED ((UINT) 1) +#define TX_TERMINATED ((UINT) 2) +#define TX_SUSPENDED ((UINT) 3) +#define TX_SLEEP ((UINT) 4) +#define TX_QUEUE_SUSP ((UINT) 5) +#define TX_SEMAPHORE_SUSP ((UINT) 6) +#define TX_EVENT_FLAG ((UINT) 7) +#define TX_BLOCK_MEMORY ((UINT) 8) +#define TX_BYTE_MEMORY ((UINT) 9) +#define TX_IO_DRIVER ((UINT) 10) +#define TX_FILE ((UINT) 11) +#define TX_TCP_IP ((UINT) 12) +#define TX_MUTEX_SUSP ((UINT) 13) +#define TX_PRIORITY_CHANGE ((UINT) 14) + + +/* API return values. */ + +#define TX_SUCCESS ((UINT) 0x00) +#define TX_DELETED ((UINT) 0x01) +#define TX_POOL_ERROR ((UINT) 0x02) +#define TX_PTR_ERROR ((UINT) 0x03) +#define TX_WAIT_ERROR ((UINT) 0x04) +#define TX_SIZE_ERROR ((UINT) 0x05) +#define TX_GROUP_ERROR ((UINT) 0x06) +#define TX_NO_EVENTS ((UINT) 0x07) +#define TX_OPTION_ERROR ((UINT) 0x08) +#define TX_QUEUE_ERROR ((UINT) 0x09) +#define TX_QUEUE_EMPTY ((UINT) 0x0A) +#define TX_QUEUE_FULL ((UINT) 0x0B) +#define TX_SEMAPHORE_ERROR ((UINT) 0x0C) +#define TX_NO_INSTANCE ((UINT) 0x0D) +#define TX_THREAD_ERROR ((UINT) 0x0E) +#define TX_PRIORITY_ERROR ((UINT) 0x0F) +#define TX_NO_MEMORY ((UINT) 0x10) +#define TX_START_ERROR ((UINT) 0x10) +#define TX_DELETE_ERROR ((UINT) 0x11) +#define TX_RESUME_ERROR ((UINT) 0x12) +#define TX_CALLER_ERROR ((UINT) 0x13) +#define TX_SUSPEND_ERROR ((UINT) 0x14) +#define TX_TIMER_ERROR ((UINT) 0x15) +#define TX_TICK_ERROR ((UINT) 0x16) +#define TX_ACTIVATE_ERROR ((UINT) 0x17) +#define TX_THRESH_ERROR ((UINT) 0x18) +#define TX_SUSPEND_LIFTED ((UINT) 0x19) +#define TX_WAIT_ABORTED ((UINT) 0x1A) +#define TX_WAIT_ABORT_ERROR ((UINT) 0x1B) +#define TX_MUTEX_ERROR ((UINT) 0x1C) +#define TX_NOT_AVAILABLE ((UINT) 0x1D) +#define TX_NOT_OWNED ((UINT) 0x1E) +#define TX_INHERIT_ERROR ((UINT) 0x1F) +#define TX_NOT_DONE ((UINT) 0x20) +#define TX_CEILING_EXCEEDED ((UINT) 0x21) +#define TX_INVALID_CEILING ((UINT) 0x22) +#define TX_FEATURE_NOT_ENABLED ((UINT) 0xFF) + + +#ifdef TX_64_BIT + +#ifndef TX_THREAD_EXTENSION_PTR_SET +#define TX_THREAD_EXTENSION_PTR_SET(a, b) { \ + TX_THREAD *thread_ptr; \ + thread_ptr = (TX_THREAD *) (a); \ + (thread_ptr -> tx_thread_extension_ptr) = (VOID *)(b); \ + } +#endif /* TX_THREAD_EXTENSION_PTR_SET */ + +#ifndef TX_THREAD_EXTENSION_PTR_GET +#define TX_THREAD_EXTENSION_PTR_GET(a, b, c) { \ + TX_PARAMETER_NOT_USED(c); \ + TX_THREAD *thread_ptr; \ + thread_ptr = tx_thread_identify(); \ + while(1)\ + { \ + if (thread_ptr -> tx_thread_extension_ptr) \ + { \ + (a) = (b *)(thread_ptr -> tx_thread_extension_ptr); \ + break; \ + } \ + tx_thread_sleep(1); \ + } \ + } +#endif /* TX_THREAD_EXTENSION_PTR_GET */ + +#ifndef TX_TIMER_EXTENSION_PTR_SET +#define TX_TIMER_EXTENSION_PTR_SET(a, b) { \ + TX_TIMER *timer_ptr; \ + timer_ptr = (TX_TIMER *) (a); \ + (timer_ptr -> tx_timer_internal.tx_timer_internal_extension_ptr) = (VOID *)(b); \ + } +#endif /* TX_TIMER_EXTENSION_PTR_SET */ + +#ifndef TX_TIMER_EXTENSION_PTR_GET +#define TX_TIMER_EXTENSION_PTR_GET(a, b, c) { \ + TX_PARAMETER_NOT_USED(c); \ + if (!_tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr) \ + return; \ + (a) = (b *)(_tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr); \ + } +#endif /* TX_TIMER_EXTENSION_PTR_GET */ + +#else /* not 64 bit */ + +#ifndef TX_THREAD_EXTENSION_PTR_SET +#define TX_THREAD_EXTENSION_PTR_SET(a, b) +#endif /* TX_THREAD_EXTENSION_PTR_SET */ + +#ifndef TX_THREAD_EXTENSION_PTR_GET +#define TX_THREAD_EXTENSION_PTR_GET(a, b, c) { \ + (a) = (b *)(c); \ + } +#endif /* TX_THREAD_EXTENSION_PTR_GET */ + +#ifndef TX_TIMER_EXTENSION_PTR_SET +#define TX_TIMER_EXTENSION_PTR_SET(a, b) +#endif /* TX_TIMER_EXTENSION_PTR_SET */ + +#ifndef TX_TIMER_EXTENSION_PTR_GET +#define TX_TIMER_EXTENSION_PTR_GET(a, b, c) { \ + (a) = (b *)(c); \ + } +#endif /* TX_TIMER_EXTENSION_PTR_GET */ + +#endif /* TX_64_BIT */ + + + +/* Define the common timer tick reference for use by other middleware components. The default + value is 10ms, but may be replaced by a port specific version in tx_port.h or by the user + as a compilation option. */ + +#ifndef TX_TIMER_TICKS_PER_SECOND +#define TX_TIMER_TICKS_PER_SECOND (100UL) +#endif + + +/* Event numbers 0 through 4095 are reserved by Azure RTOS. Specific event assignments are: + + ThreadX events: 1-199 + FileX events: 200-299 + NetX events: 300-599 + USBX events: 600-999 + GUIX events: 1000-1500 + + User-defined event numbers start at 4096 and continue through 65535, as defined by the constants + TX_TRACE_USER_EVENT_START and TX_TRACE_USER_EVENT_END, respectively. User events should be based + on these constants in case the user event number assignment is changed in future releases. */ + +#define TX_TRACE_USER_EVENT_START 4096 /* I1, I2, I3, I4 are user defined */ +#define TX_TRACE_USER_EVENT_END 65535 /* I1, I2, I3, I4 are user defined */ + + +/* Define event filters that can be used to selectively disable certain events or groups of events. */ + +#define TX_TRACE_ALL_EVENTS 0x000007FF /* All ThreadX events */ +#define TX_TRACE_INTERNAL_EVENTS 0x00000001 /* ThreadX internal events */ +#define TX_TRACE_BLOCK_POOL_EVENTS 0x00000002 /* ThreadX Block Pool events */ +#define TX_TRACE_BYTE_POOL_EVENTS 0x00000004 /* ThreadX Byte Pool events */ +#define TX_TRACE_EVENT_FLAGS_EVENTS 0x00000008 /* ThreadX Event Flags events */ +#define TX_TRACE_INTERRUPT_CONTROL_EVENT 0x00000010 /* ThreadX Interrupt Control events */ +#define TX_TRACE_MUTEX_EVENTS 0x00000020 /* ThreadX Mutex events */ +#define TX_TRACE_QUEUE_EVENTS 0x00000040 /* ThreadX Queue events */ +#define TX_TRACE_SEMAPHORE_EVENTS 0x00000080 /* ThreadX Semaphore events */ +#define TX_TRACE_THREAD_EVENTS 0x00000100 /* ThreadX Thread events */ +#define TX_TRACE_TIME_EVENTS 0x00000200 /* ThreadX Time events */ +#define TX_TRACE_TIMER_EVENTS 0x00000400 /* ThreadX Timer events */ +#define TX_TRACE_USER_EVENTS 0x80000000UL /* ThreadX User Events */ + + +/* Define basic alignment type used in block and byte pool operations. This data type must + be at least 32-bits in size and also be large enough to hold a pointer type. */ + +#ifndef ALIGN_TYPE_DEFINED +#define ALIGN_TYPE ULONG +#endif + + +/* Define the control block definitions for all system objects. */ + + +/* Define the basic timer management structures. These are the structures + used to manage thread sleep, timeout, and user timer requests. */ + +/* Determine if the internal timer control block has an extension defined. If not, + define the extension to whitespace. */ + +#ifndef TX_TIMER_INTERNAL_EXTENSION +#define TX_TIMER_INTERNAL_EXTENSION +#endif + + +/* Define the common internal timer control block. */ + +typedef struct TX_TIMER_INTERNAL_STRUCT +{ + + /* Define the remaining ticks and re-initialization tick values. */ + ULONG tx_timer_internal_remaining_ticks; + ULONG tx_timer_internal_re_initialize_ticks; + + /* Define the timeout function and timeout function parameter. */ + VOID (*tx_timer_internal_timeout_function)(ULONG id); + ULONG tx_timer_internal_timeout_param; + + + /* Define the next and previous internal link pointers for active + internal timers. */ + struct TX_TIMER_INTERNAL_STRUCT + *tx_timer_internal_active_next, + *tx_timer_internal_active_previous; + + /* Keep track of the pointer to the head of this list as well. */ + struct TX_TIMER_INTERNAL_STRUCT + **tx_timer_internal_list_head; + + /* Define optional extension to internal timer control block. */ + TX_TIMER_INTERNAL_EXTENSION + +} TX_TIMER_INTERNAL; + + +/* Determine if the timer control block has an extension defined. If not, + define the extension to whitespace. */ + +#ifndef TX_TIMER_EXTENSION +#define TX_TIMER_EXTENSION +#endif + + +/* Define the timer structure utilized by the application. */ + +typedef struct TX_TIMER_STRUCT +{ + + /* Define the timer ID used for error checking. */ + ULONG tx_timer_id; + + /* Define the timer's name. */ + CHAR *tx_timer_name; + + /* Define the actual contents of the timer. This is the block that + is used in the actual timer expiration processing. */ + TX_TIMER_INTERNAL tx_timer_internal; + + /* Define the pointers for the created list. */ + struct TX_TIMER_STRUCT + *tx_timer_created_next, + *tx_timer_created_previous; + + /* Define optional extension to timer control block. */ + TX_TIMER_EXTENSION + +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO + + /* Define the number of timer activations. */ + ULONG tx_timer_performance_activate_count; + + /* Define the number of timer reactivations. */ + ULONG tx_timer_performance_reactivate_count; + + /* Define the number of timer deactivations. */ + ULONG tx_timer_performance_deactivate_count; + + /* Define the number of timer expirations. */ + ULONG tx_timer_performance_expiration_count; + + /* Define the total number of timer expiration adjustments. */ + ULONG tx_timer_performance__expiration_adjust_count; +#endif + +} TX_TIMER; + + +/* ThreadX thread control block structure follows. Additional fields + can be added providing they are added after the information that is + referenced in the port-specific assembly code. */ + +typedef struct TX_THREAD_STRUCT +{ + /* The first section of the control block contains critical + information that is referenced by the port-specific + assembly language code. Any changes in this section could + necessitate changes in the assembly language. */ + + ULONG tx_thread_id; /* Control block ID */ + ULONG tx_thread_run_count; /* Thread's run counter */ + VOID *tx_thread_stack_ptr; /* Thread's stack pointer */ + VOID *tx_thread_stack_start; /* Stack starting address */ + VOID *tx_thread_stack_end; /* Stack ending address */ + ULONG tx_thread_stack_size; /* Stack size */ + ULONG tx_thread_time_slice; /* Current time-slice */ + ULONG tx_thread_new_time_slice; /* New time-slice */ + + /* Define pointers to the next and previous ready threads. */ + struct TX_THREAD_STRUCT + *tx_thread_ready_next, + *tx_thread_ready_previous; + + /***************************************************************/ + + /* Define the first port extension in the thread control block. This + is typically defined to whitespace or a pointer type in tx_port.h. */ + TX_THREAD_EXTENSION_0 + + CHAR *tx_thread_name; /* Pointer to thread's name */ + UINT tx_thread_priority; /* Priority of thread (0-1023) */ + UINT tx_thread_state; /* Thread's execution state */ + UINT tx_thread_delayed_suspend; /* Delayed suspend flag */ + UINT tx_thread_suspending; /* Thread suspending flag */ + UINT tx_thread_preempt_threshold; /* Preemption threshold */ + + /* Define the thread schedule hook. The usage of this is port/application specific, + but when used, the function pointer designated is called whenever the thread is + scheduled and unscheduled. */ + VOID (*tx_thread_schedule_hook)(struct TX_THREAD_STRUCT *thread_ptr, ULONG id); + + /* Nothing after this point is referenced by the target-specific + assembly language. Hence, information after this point can + be added to the control block providing the complete system + is recompiled. */ + + /* Define the thread's entry point and input parameter. */ + VOID (*tx_thread_entry)(ULONG id); + ULONG tx_thread_entry_parameter; + + /* Define the thread's timer block. This is used for thread + sleep and timeout requests. */ + TX_TIMER_INTERNAL tx_thread_timer; + + /* Define the thread's cleanup function and associated data. This + is used to cleanup various data structures when a thread + suspension is lifted or terminated either by the user or + a timeout. */ + VOID (*tx_thread_suspend_cleanup)(struct TX_THREAD_STRUCT *thread_ptr, ULONG suspension_sequence); + VOID *tx_thread_suspend_control_block; + struct TX_THREAD_STRUCT + *tx_thread_suspended_next, + *tx_thread_suspended_previous; + ULONG tx_thread_suspend_info; + VOID *tx_thread_additional_suspend_info; + UINT tx_thread_suspend_option; + UINT tx_thread_suspend_status; + + /* Define the second port extension in the thread control block. This + is typically defined to whitespace or a pointer type in tx_port.h. */ + TX_THREAD_EXTENSION_1 + + /* Define pointers to the next and previous threads in the + created list. */ + struct TX_THREAD_STRUCT + *tx_thread_created_next, + *tx_thread_created_previous; + + /* Define the third port extension in the thread control block. This + is typically defined to whitespace in tx_port.h. */ + TX_THREAD_EXTENSION_2 + + /* Define a pointer type for FileX extensions. */ +#ifndef TX_NO_FILEX_POINTER + VOID *tx_thread_filex_ptr; +#endif + + /* Define the priority inheritance variables. These will be used + to manage priority inheritance changes applied to this thread + as a result of mutex get operations. */ + UINT tx_thread_user_priority; + UINT tx_thread_user_preempt_threshold; + UINT tx_thread_inherit_priority; + + /* Define the owned mutex count and list head pointer. */ + UINT tx_thread_owned_mutex_count; + struct TX_MUTEX_STRUCT + *tx_thread_owned_mutex_list; + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + + /* Define the number of times this thread is resumed. */ + ULONG tx_thread_performance_resume_count; + + /* Define the number of times this thread suspends. */ + ULONG tx_thread_performance_suspend_count; + + /* Define the number of times this thread is preempted by calling + a ThreadX API service. */ + ULONG tx_thread_performance_solicited_preemption_count; + + /* Define the number of times this thread is preempted by an + ISR calling a ThreadX API service. */ + ULONG tx_thread_performance_interrupt_preemption_count; + + /* Define the number of priority inversions for this thread. */ + ULONG tx_thread_performance_priority_inversion_count; + + /* Define the last thread pointer to preempt this thread. */ + struct TX_THREAD_STRUCT + *tx_thread_performance_last_preempting_thread; + + /* Define the total number of times this thread was time-sliced. */ + ULONG tx_thread_performance_time_slice_count; + + /* Define the total number of times this thread relinquishes. */ + ULONG tx_thread_performance_relinquish_count; + + /* Define the total number of times this thread had a timeout. */ + ULONG tx_thread_performance_timeout_count; + + /* Define the total number of times this thread had suspension lifted + because of the tx_thread_wait_abort service. */ + ULONG tx_thread_performance_wait_abort_count; +#endif + + /* Define the highest stack pointer variable. */ + VOID *tx_thread_stack_highest_ptr; /* Stack highest usage pointer */ + + +#ifndef TX_DISABLE_NOTIFY_CALLBACKS + + /* Define the application callback routine used to notify the application when + the thread is entered or exits. */ + VOID (*tx_thread_entry_exit_notify)(struct TX_THREAD_STRUCT *thread_ptr, UINT type); +#endif + + /* Define the fourth port extension in the thread control block. This + is typically defined to whitespace in tx_port.h. */ + TX_THREAD_EXTENSION_3 + + + /* Define variables for supporting execution profile. */ + /* Note that in ThreadX 5.x, user would define TX_ENABLE_EXECUTION_CHANGE_NOTIFY and use TX_THREAD_EXTENSION_3 + to define the following two variables. + For Azure RTOS 6, user shall use TX_EXECUTION_PROFILE_ENABLE instead of TX_ENABLE_EXECUTION_CHANGE_NOTIFY, + and SHALL NOT add variables to TX_THREAD_EXTENSION_3. */ +#if (defined(TX_EXECUTION_PROFILE_ENABLE) && !defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY)) + EXECUTION_TIME tx_thread_execution_time_total; + EXECUTION_TIME_SOURCE_TYPE tx_thread_execution_time_last_start; +#endif + + /* Define suspension sequence number. This is used to ensure suspension is still valid when + cleanup routine executes. */ + ULONG tx_thread_suspension_sequence; + +#if defined(TX_ENABLE_RANDOM_NUMBER_STACK_FILLING) && defined(TX_ENABLE_STACK_CHECKING) + + /* Define the random stack fill number. This can be used to detect stack overflow. */ + ULONG tx_thread_stack_fill_value; +#endif + + /* Define the user extension field. This typically is defined + to white space, but some ports of ThreadX may need to have + additional fields in the thread control block. This is + defined in the file tx_port.h. */ + TX_THREAD_USER_EXTENSION + +} TX_THREAD; + + +/* Define the block memory pool structure utilized by the application. */ + +typedef struct TX_BLOCK_POOL_STRUCT +{ + + /* Define the block pool ID used for error checking. */ + ULONG tx_block_pool_id; + + /* Define the block pool's name. */ + CHAR *tx_block_pool_name; + + /* Define the number of available memory blocks in the pool. */ + UINT tx_block_pool_available; + + /* Save the initial number of blocks. */ + UINT tx_block_pool_total; + + /* Define the head pointer of the available block pool. */ + UCHAR *tx_block_pool_available_list; + + /* Save the start address of the block pool's memory area. */ + UCHAR *tx_block_pool_start; + + /* Save the block pool's size in bytes. */ + ULONG tx_block_pool_size; + + /* Save the individual memory block size - rounded for alignment. */ + UINT tx_block_pool_block_size; + + /* Define the block pool suspension list head along with a count of + how many threads are suspended. */ + struct TX_THREAD_STRUCT + *tx_block_pool_suspension_list; + UINT tx_block_pool_suspended_count; + + /* Define the created list next and previous pointers. */ + struct TX_BLOCK_POOL_STRUCT + *tx_block_pool_created_next, + *tx_block_pool_created_previous; + +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO + + /* Define the number of block allocates. */ + ULONG tx_block_pool_performance_allocate_count; + + /* Define the number of block releases. */ + ULONG tx_block_pool_performance_release_count; + + /* Define the number of block pool suspensions. */ + ULONG tx_block_pool_performance_suspension_count; + + /* Define the number of block pool timeouts. */ + ULONG tx_block_pool_performance_timeout_count; +#endif + + /* Define the port extension in the block pool control block. This + is typically defined to whitespace in tx_port.h. */ + TX_BLOCK_POOL_EXTENSION + +} TX_BLOCK_POOL; + + +/* Determine if the byte allocate extension is defined. If not, define the + extension to whitespace. */ + +#ifndef TX_BYTE_ALLOCATE_EXTENSION +#define TX_BYTE_ALLOCATE_EXTENSION +#endif + + +/* Determine if the byte release extension is defined. If not, define the + extension to whitespace. */ + +#ifndef TX_BYTE_RELEASE_EXTENSION +#define TX_BYTE_RELEASE_EXTENSION +#endif + + +/* Define the byte memory pool structure utilized by the application. */ + +typedef struct TX_BYTE_POOL_STRUCT +{ + + /* Define the byte pool ID used for error checking. */ + ULONG tx_byte_pool_id; + + /* Define the byte pool's name. */ + CHAR *tx_byte_pool_name; + + /* Define the number of available bytes in the pool. */ + ULONG tx_byte_pool_available; + + /* Define the number of fragments in the pool. */ + UINT tx_byte_pool_fragments; + + /* Define the head pointer of byte pool. */ + UCHAR *tx_byte_pool_list; + + /* Define the search pointer used for initial searching for memory + in a byte pool. */ + UCHAR *tx_byte_pool_search; + + /* Save the start address of the byte pool's memory area. */ + UCHAR *tx_byte_pool_start; + + /* Save the byte pool's size in bytes. */ + ULONG tx_byte_pool_size; + + /* This is used to mark the owner of the byte memory pool during + a search. If this value changes during the search, the local search + pointer must be reset. */ + struct TX_THREAD_STRUCT + *tx_byte_pool_owner; + + /* Define the byte pool suspension list head along with a count of + how many threads are suspended. */ + struct TX_THREAD_STRUCT + *tx_byte_pool_suspension_list; + UINT tx_byte_pool_suspended_count; + + /* Define the created list next and previous pointers. */ + struct TX_BYTE_POOL_STRUCT + *tx_byte_pool_created_next, + *tx_byte_pool_created_previous; + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + + /* Define the number of allocates. */ + ULONG tx_byte_pool_performance_allocate_count; + + /* Define the number of releases. */ + ULONG tx_byte_pool_performance_release_count; + + /* Define the number of adjacent memory fragment merges. */ + ULONG tx_byte_pool_performance_merge_count; + + /* Define the number of memory fragment splits. */ + ULONG tx_byte_pool_performance_split_count; + + /* Define the number of memory fragments searched that either were not free or could not satisfy the + request. */ + ULONG tx_byte_pool_performance_search_count; + + /* Define the number of byte pool suspensions. */ + ULONG tx_byte_pool_performance_suspension_count; + + /* Define the number of byte pool timeouts. */ + ULONG tx_byte_pool_performance_timeout_count; +#endif + + /* Define the port extension in the byte pool control block. This + is typically defined to whitespace in tx_port.h. */ + TX_BYTE_POOL_EXTENSION + +} TX_BYTE_POOL; + + +/* Define the event flags group structure utilized by the application. */ + +typedef struct TX_EVENT_FLAGS_GROUP_STRUCT +{ + + /* Define the event flags group ID used for error checking. */ + ULONG tx_event_flags_group_id; + + /* Define the event flags group's name. */ + CHAR *tx_event_flags_group_name; + + /* Define the actual current event flags in this group. A zero in a + particular bit indicates the event flag is not set. */ + ULONG tx_event_flags_group_current; + + /* Define the reset search flag that is set when an ISR sets flags during + the search of the suspended threads list. */ + UINT tx_event_flags_group_reset_search; + + /* Define the event flags group suspension list head along with a count of + how many threads are suspended. */ + struct TX_THREAD_STRUCT + *tx_event_flags_group_suspension_list; + UINT tx_event_flags_group_suspended_count; + + /* Define the created list next and previous pointers. */ + struct TX_EVENT_FLAGS_GROUP_STRUCT + *tx_event_flags_group_created_next, + *tx_event_flags_group_created_previous; + + /* Define the delayed clearing event flags. */ + ULONG tx_event_flags_group_delayed_clear; + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + + /* Define the number of event flag sets. */ + ULONG tx_event_flags_group_performance_set_count; + + /* Define the number of event flag gets. */ + ULONG tx_event_flags_group__performance_get_count; + + /* Define the number of event flag suspensions. */ + ULONG tx_event_flags_group___performance_suspension_count; + + /* Define the number of event flag timeouts. */ + ULONG tx_event_flags_group____performance_timeout_count; +#endif + +#ifndef TX_DISABLE_NOTIFY_CALLBACKS + + /* Define the application callback routine used to notify the application when + an event flag is set. */ + VOID (*tx_event_flags_group_set_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *group_ptr); +#endif + + /* Define the port extension in the event flags group control block. This + is typically defined to whitespace in tx_port.h. */ + TX_EVENT_FLAGS_GROUP_EXTENSION + +} TX_EVENT_FLAGS_GROUP; + + +/* Determine if the mutex put extension 1 is defined. If not, define the + extension to whitespace. */ + +#ifndef TX_MUTEX_PUT_EXTENSION_1 +#define TX_MUTEX_PUT_EXTENSION_1 +#endif + + +/* Determine if the mutex put extension 2 is defined. If not, define the + extension to whitespace. */ + +#ifndef TX_MUTEX_PUT_EXTENSION_2 +#define TX_MUTEX_PUT_EXTENSION_2 +#endif + + +/* Determine if the mutex priority change extension is defined. If not, define the + extension to whitespace. */ + +#ifndef TX_MUTEX_PRIORITY_CHANGE_EXTENSION +#define TX_MUTEX_PRIORITY_CHANGE_EXTENSION +#endif + + +/* Define the mutex structure utilized by the application. */ + +typedef struct TX_MUTEX_STRUCT +{ + + /* Define the mutex ID used for error checking. */ + ULONG tx_mutex_id; + + /* Define the mutex's name. */ + CHAR *tx_mutex_name; + + /* Define the mutex ownership count. */ + UINT tx_mutex_ownership_count; + + /* Define the mutex ownership pointer. This pointer points to the + the thread that owns the mutex. */ + TX_THREAD *tx_mutex_owner; + + /* Define the priority inheritance flag. If this flag is set, priority + inheritance will be in effect. */ + UINT tx_mutex_inherit; + + /* Define the save area for the owning thread's original priority. */ + UINT tx_mutex_original_priority; + + /* Define the mutex suspension list head along with a count of + how many threads are suspended. */ + struct TX_THREAD_STRUCT + *tx_mutex_suspension_list; + UINT tx_mutex_suspended_count; + + /* Define the created list next and previous pointers. */ + struct TX_MUTEX_STRUCT + *tx_mutex_created_next, + *tx_mutex_created_previous; + + /* Define the priority of the highest priority thread waiting for + this mutex. */ + UINT tx_mutex_highest_priority_waiting; + + /* Define the owned list next and previous pointers. */ + struct TX_MUTEX_STRUCT + *tx_mutex_owned_next, + *tx_mutex_owned_previous; + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Define the 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 + + /* Define the port extension in the mutex control block. This + is typically defined to whitespace in tx_port.h. */ + TX_MUTEX_EXTENSION + +} TX_MUTEX; + + +/* Define the queue structure utilized by the application. */ + +typedef struct TX_QUEUE_STRUCT +{ + + /* Define the queue ID used for error checking. */ + ULONG tx_queue_id; + + /* Define the queue's name. */ + CHAR *tx_queue_name; + + /* Define the message size that was specified in queue creation. */ + UINT tx_queue_message_size; + + /* Define the total number of messages in the queue. */ + UINT tx_queue_capacity; + + /* Define the current number of messages enqueued and the available + queue storage space. */ + UINT tx_queue_enqueued; + UINT tx_queue_available_storage; + + /* Define pointers that represent the start and end for the queue's + message area. */ + ULONG *tx_queue_start; + ULONG *tx_queue_end; + + /* Define the queue read and write pointers. Send requests use the write + pointer while receive requests use the read pointer. */ + ULONG *tx_queue_read; + ULONG *tx_queue_write; + + /* Define the queue suspension list head along with a count of + how many threads are suspended. */ + struct TX_THREAD_STRUCT + *tx_queue_suspension_list; + UINT tx_queue_suspended_count; + + /* Define the created list next and previous pointers. */ + struct TX_QUEUE_STRUCT + *tx_queue_created_next, + *tx_queue_created_previous; + +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO + + /* Define the number of messages sent to this queue. */ + ULONG tx_queue_performance_messages_sent_count; + + /* Define the number of messages received from this queue. */ + ULONG tx_queue_performance_messages_received_count; + + /* Define the number of empty suspensions on this queue. */ + ULONG tx_queue_performance_empty_suspension_count; + + /* Define the number of full suspensions on this queue. */ + ULONG tx_queue_performance_full_suspension_count; + + /* Define the number of full non-suspensions on this queue. These + messages are rejected with an appropriate error code. */ + ULONG tx_queue_performance_full_error_count; + + /* Define the number of queue timeouts. */ + ULONG tx_queue_performance_timeout_count; +#endif + +#ifndef TX_DISABLE_NOTIFY_CALLBACKS + + /* Define the application callback routine used to notify the application when + the a message is sent to the queue. */ + VOID (*tx_queue_send_notify)(struct TX_QUEUE_STRUCT *queue_ptr); +#endif + + /* Define the port extension in the queue control block. This + is typically defined to whitespace in tx_port.h. */ + TX_QUEUE_EXTENSION + +} TX_QUEUE; + + +/* Define the semaphore structure utilized by the application. */ + +typedef struct TX_SEMAPHORE_STRUCT +{ + + /* Define the semaphore ID used for error checking. */ + ULONG tx_semaphore_id; + + /* Define the semaphore's name. */ + CHAR *tx_semaphore_name; + + /* Define the actual semaphore count. A zero means that no semaphore + instance is available. */ + ULONG tx_semaphore_count; + + /* Define the semaphore suspension list head along with a count of + how many threads are suspended. */ + struct TX_THREAD_STRUCT + *tx_semaphore_suspension_list; + UINT tx_semaphore_suspended_count; + + /* Define the created list next and previous pointers. */ + struct TX_SEMAPHORE_STRUCT + *tx_semaphore_created_next, + *tx_semaphore_created_previous; + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + + /* Define the number of semaphore puts. */ + ULONG tx_semaphore_performance_put_count; + + /* Define the number of semaphore gets. */ + ULONG tx_semaphore_performance_get_count; + + /* Define the number of semaphore suspensions. */ + ULONG tx_semaphore_performance_suspension_count; + + /* Define the number of semaphore timeouts. */ + ULONG tx_semaphore_performance_timeout_count; +#endif + +#ifndef TX_DISABLE_NOTIFY_CALLBACKS + + /* Define the application callback routine used to notify the application when + the a semaphore is put. */ + VOID (*tx_semaphore_put_notify)(struct TX_SEMAPHORE_STRUCT *semaphore_ptr); +#endif + + /* Define the port extension in the semaphore control block. This + is typically defined to whitespace in tx_port.h. */ + TX_SEMAPHORE_EXTENSION + +} TX_SEMAPHORE; + + +/* Define the system API mappings based on the error checking + selected by the user. Note: this section is only applicable to + application source code, hence the conditional that turns off this + stuff when the include file is processed by the ThreadX source. */ + +#ifndef TX_SOURCE_CODE + + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef TX_DISABLE_ERROR_CHECKING + + +/* Services without error checking. */ + +#define tx_kernel_enter _tx_initialize_kernel_enter + +#define tx_block_allocate _tx_block_allocate +#define tx_block_pool_create _tx_block_pool_create +#define tx_block_pool_delete _tx_block_pool_delete +#define tx_block_pool_info_get _tx_block_pool_info_get +#define tx_block_pool_performance_info_get _tx_block_pool_performance_info_get +#define tx_block_pool_performance_system_info_get _tx_block_pool_performance_system_info_get +#define tx_block_pool_prioritize _tx_block_pool_prioritize +#define tx_block_release _tx_block_release + +#define tx_byte_allocate _tx_byte_allocate +#define tx_byte_pool_create _tx_byte_pool_create +#define tx_byte_pool_delete _tx_byte_pool_delete +#define tx_byte_pool_info_get _tx_byte_pool_info_get +#define tx_byte_pool_performance_info_get _tx_byte_pool_performance_info_get +#define tx_byte_pool_performance_system_info_get _tx_byte_pool_performance_system_info_get +#define tx_byte_pool_prioritize _tx_byte_pool_prioritize +#define tx_byte_release _tx_byte_release + +#define tx_event_flags_create _tx_event_flags_create +#define tx_event_flags_delete _tx_event_flags_delete +#define tx_event_flags_get _tx_event_flags_get +#define tx_event_flags_info_get _tx_event_flags_info_get +#define tx_event_flags_performance_info_get _tx_event_flags_performance_info_get +#define tx_event_flags_performance_system_info_get _tx_event_flags_performance_system_info_get +#define tx_event_flags_set _tx_event_flags_set +#define tx_event_flags_set_notify _tx_event_flags_set_notify + +#ifdef TX_ENABLE_EVENT_LOGGING +UINT _tx_el_interrupt_control(UINT new_posture); +#define tx_interrupt_control _tx_el_interrupt_control +#else +#ifdef TX_ENABLE_EVENT_TRACE +UINT _tx_trace_interrupt_control(UINT new_posture); +#define tx_interrupt_control _tx_trace_interrupt_control +#else +#define tx_interrupt_control _tx_thread_interrupt_control +#endif +#endif + +#define tx_mutex_create _tx_mutex_create +#define tx_mutex_delete _tx_mutex_delete +#define tx_mutex_get _tx_mutex_get +#define tx_mutex_info_get _tx_mutex_info_get +#define tx_mutex_performance_info_get _tx_mutex_performance_info_get +#define tx_mutex_performance_system_info_get _tx_mutex_performance_system_info_get +#define tx_mutex_prioritize _tx_mutex_prioritize +#define tx_mutex_put _tx_mutex_put + +#define tx_queue_create _tx_queue_create +#define tx_queue_delete _tx_queue_delete +#define tx_queue_flush _tx_queue_flush +#define tx_queue_info_get _tx_queue_info_get +#define tx_queue_performance_info_get _tx_queue_performance_info_get +#define tx_queue_performance_system_info_get _tx_queue_performance_system_info_get +#define tx_queue_receive _tx_queue_receive +#define tx_queue_send _tx_queue_send +#define tx_queue_send_notify _tx_queue_send_notify +#define tx_queue_front_send _tx_queue_front_send +#define tx_queue_prioritize _tx_queue_prioritize + +#define tx_semaphore_ceiling_put _tx_semaphore_ceiling_put +#define tx_semaphore_create _tx_semaphore_create +#define tx_semaphore_delete _tx_semaphore_delete +#define tx_semaphore_get _tx_semaphore_get +#define tx_semaphore_info_get _tx_semaphore_info_get +#define tx_semaphore_performance_info_get _tx_semaphore_performance_info_get +#define tx_semaphore_performance_system_info_get _tx_semaphore_performance_system_info_get +#define tx_semaphore_prioritize _tx_semaphore_prioritize +#define tx_semaphore_put _tx_semaphore_put +#define tx_semaphore_put_notify _tx_semaphore_put_notify + +#define tx_thread_create _tx_thread_create +#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 +#define tx_thread_info_get _tx_thread_info_get +#define tx_thread_performance_info_get _tx_thread_performance_info_get +#define tx_thread_performance_system_info_get _tx_thread_performance_system_info_get +#define tx_thread_preemption_change _tx_thread_preemption_change +#define tx_thread_priority_change _tx_thread_priority_change +#define tx_thread_relinquish _tx_thread_relinquish +#define tx_thread_reset _tx_thread_reset +#define tx_thread_resume _tx_thread_resume +#define tx_thread_sleep _tx_thread_sleep +#define tx_thread_stack_error_notify _tx_thread_stack_error_notify +#define tx_thread_suspend _tx_thread_suspend +#define tx_thread_terminate _tx_thread_terminate +#define tx_thread_time_slice_change _tx_thread_time_slice_change +#define tx_thread_wait_abort _tx_thread_wait_abort + +#define tx_time_get _tx_time_get +#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 _tx_timer_create +#define tx_timer_deactivate _tx_timer_deactivate +#define tx_timer_delete _tx_timer_delete +#define tx_timer_info_get _tx_timer_info_get +#define tx_timer_performance_info_get _tx_timer_performance_info_get +#define tx_timer_performance_system_info_get _tx_timer_performance_system_info_get + +#define tx_trace_enable _tx_trace_enable +#define tx_trace_event_filter _tx_trace_event_filter +#define tx_trace_event_unfilter _tx_trace_event_unfilter +#define tx_trace_disable _tx_trace_disable +#define tx_trace_isr_enter_insert _tx_trace_isr_enter_insert +#define tx_trace_isr_exit_insert _tx_trace_isr_exit_insert +#define tx_trace_buffer_full_notify _tx_trace_buffer_full_notify +#define tx_trace_user_event_insert _tx_trace_user_event_insert + +#else + +/* Services with error checking. */ + +#define tx_kernel_enter _tx_initialize_kernel_enter + +/* Define the system API mappings depending on the runtime error + checking behavior selected by the user. */ + +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING + +/* Services with MULTI runtime error checking ThreadX. */ + +#define tx_block_allocate _txr_block_allocate +#define tx_block_pool_create(p,n,b,s,l) _txr_block_pool_create((p),(n),(b),(s),(l),(sizeof(TX_BLOCK_POOL))) +#define tx_block_pool_delete _txr_block_pool_delete +#define tx_block_pool_info_get _txr_block_pool_info_get +#define tx_block_pool_performance_info_get _tx_block_pool_performance_info_get +#define tx_block_pool_performance_system_info_get _tx_block_pool_performance_system_info_get +#define tx_block_pool_prioritize _txr_block_pool_prioritize +#define tx_block_release _txr_block_release + +#define tx_byte_allocate _txr_byte_allocate +#define tx_byte_pool_create(p,n,s,l) _txr_byte_pool_create((p),(n),(s),(l),(sizeof(TX_BYTE_POOL))) +#define tx_byte_pool_delete _txr_byte_pool_delete +#define tx_byte_pool_info_get _txr_byte_pool_info_get +#define tx_byte_pool_performance_info_get _tx_byte_pool_performance_info_get +#define tx_byte_pool_performance_system_info_get _tx_byte_pool_performance_system_info_get +#define tx_byte_pool_prioritize _txr_byte_pool_prioritize +#define tx_byte_release _txr_byte_release + +#define tx_event_flags_create(g,n) _txr_event_flags_create((g),(n),(sizeof(TX_EVENT_FLAGS_GROUP))) +#define tx_event_flags_delete _txr_event_flags_delete +#define tx_event_flags_get _txr_event_flags_get +#define tx_event_flags_info_get _txr_event_flags_info_get +#define tx_event_flags_performance_info_get _tx_event_flags_performance_info_get +#define tx_event_flags_performance_system_info_get _tx_event_flags_performance_system_info_get +#define tx_event_flags_set _txr_event_flags_set +#define tx_event_flags_set_notify _txr_event_flags_set_notify + +#ifdef TX_ENABLE_EVENT_LOGGING +UINT _tx_el_interrupt_control(UINT new_posture); +#define tx_interrupt_control _tx_el_interrupt_control +#else +#ifdef TX_ENABLE_EVENT_TRACE +UINT _tx_trace_interrupt_control(UINT new_posture); +#define tx_interrupt_control _tx_trace_interrupt_control +#else +#define tx_interrupt_control _tx_thread_interrupt_control +#endif +#endif + +#define tx_mutex_create(m,n,i) _txr_mutex_create((m),(n),(i),(sizeof(TX_MUTEX))) +#define tx_mutex_delete _txr_mutex_delete +#define tx_mutex_get _txr_mutex_get +#define tx_mutex_info_get _txr_mutex_info_get +#define tx_mutex_performance_info_get _tx_mutex_performance_info_get +#define tx_mutex_performance_system_info_get _tx_mutex_performance_system_info_get +#define tx_mutex_prioritize _txr_mutex_prioritize +#define tx_mutex_put _txr_mutex_put + +#define tx_queue_create(q,n,m,s,l) _txr_queue_create((q),(n),(m),(s),(l),(sizeof(TX_QUEUE))) +#define tx_queue_delete _txr_queue_delete +#define tx_queue_flush _txr_queue_flush +#define tx_queue_info_get _txr_queue_info_get +#define tx_queue_performance_info_get _tx_queue_performance_info_get +#define tx_queue_performance_system_info_get _tx_queue_performance_system_info_get +#define tx_queue_receive _txr_queue_receive +#define tx_queue_send _txr_queue_send +#define tx_queue_send_notify _txr_queue_send_notify +#define tx_queue_front_send _txr_queue_front_send +#define tx_queue_prioritize _txr_queue_prioritize + +#define tx_semaphore_ceiling_put _txr_semaphore_ceiling_put +#define tx_semaphore_create(s,n,i) _txr_semaphore_create((s),(n),(i),(sizeof(TX_SEMAPHORE))) +#define tx_semaphore_delete _txr_semaphore_delete +#define tx_semaphore_get _txr_semaphore_get +#define tx_semaphore_info_get _txr_semaphore_info_get +#define tx_semaphore_performance_info_get _tx_semaphore_performance_info_get +#define tx_semaphore_performance_system_info_get _tx_semaphore_performance_system_info_get +#define tx_semaphore_prioritize _txr_semaphore_prioritize +#define tx_semaphore_put _txr_semaphore_put +#define tx_semaphore_put_notify _txr_semaphore_put_notify + +#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))) +#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 +#define tx_thread_info_get _txr_thread_info_get +#define tx_thread_performance_info_get _tx_thread_performance_info_get +#define tx_thread_performance_system_info_get _tx_thread_performance_system_info_get +#define tx_thread_preemption_change _txr_thread_preemption_change +#define tx_thread_priority_change _txr_thread_priority_change +#define tx_thread_relinquish _txe_thread_relinquish +#define tx_thread_reset _txr_thread_reset +#define tx_thread_resume _txr_thread_resume +#define tx_thread_sleep _tx_thread_sleep +#define tx_thread_stack_error_notify _tx_thread_stack_error_notify +#define tx_thread_suspend _txr_thread_suspend +#define tx_thread_terminate _txr_thread_terminate +#define tx_thread_time_slice_change _txr_thread_time_slice_change +#define tx_thread_wait_abort _txr_thread_wait_abort + +#define tx_time_get _tx_time_get +#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(t,n,e,i,c,r,a) _txr_timer_create((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#define tx_timer_deactivate _txr_timer_deactivate +#define tx_timer_delete _txr_timer_delete +#define tx_timer_info_get _txr_timer_info_get +#define tx_timer_performance_info_get _tx_timer_performance_info_get +#define tx_timer_performance_system_info_get _tx_timer_performance_system_info_get + +#define tx_trace_enable _tx_trace_enable +#define tx_trace_event_filter _tx_trace_event_filter +#define tx_trace_event_unfilter _tx_trace_event_unfilter +#define tx_trace_disable _tx_trace_disable +#define tx_trace_isr_enter_insert _tx_trace_isr_enter_insert +#define tx_trace_isr_exit_insert _tx_trace_isr_exit_insert +#define tx_trace_buffer_full_notify _tx_trace_buffer_full_notify +#define tx_trace_user_event_insert _tx_trace_user_event_insert + +#else + +#define tx_block_allocate _txe_block_allocate +#define tx_block_pool_create(p,n,b,s,l) _txe_block_pool_create((p),(n),(b),(s),(l),(sizeof(TX_BLOCK_POOL))) +#define tx_block_pool_delete _txe_block_pool_delete +#define tx_block_pool_info_get _txe_block_pool_info_get +#define tx_block_pool_performance_info_get _tx_block_pool_performance_info_get +#define tx_block_pool_performance_system_info_get _tx_block_pool_performance_system_info_get +#define tx_block_pool_prioritize _txe_block_pool_prioritize +#define tx_block_release _txe_block_release + +#define tx_byte_allocate _txe_byte_allocate +#define tx_byte_pool_create(p,n,s,l) _txe_byte_pool_create((p),(n),(s),(l),(sizeof(TX_BYTE_POOL))) +#define tx_byte_pool_delete _txe_byte_pool_delete +#define tx_byte_pool_info_get _txe_byte_pool_info_get +#define tx_byte_pool_performance_info_get _tx_byte_pool_performance_info_get +#define tx_byte_pool_performance_system_info_get _tx_byte_pool_performance_system_info_get +#define tx_byte_pool_prioritize _txe_byte_pool_prioritize +#define tx_byte_release _txe_byte_release + +#define tx_event_flags_create(g,n) _txe_event_flags_create((g),(n),(sizeof(TX_EVENT_FLAGS_GROUP))) +#define tx_event_flags_delete _txe_event_flags_delete +#define tx_event_flags_get _txe_event_flags_get +#define tx_event_flags_info_get _txe_event_flags_info_get +#define tx_event_flags_performance_info_get _tx_event_flags_performance_info_get +#define tx_event_flags_performance_system_info_get _tx_event_flags_performance_system_info_get +#define tx_event_flags_set _txe_event_flags_set +#define tx_event_flags_set_notify _txe_event_flags_set_notify + +#ifdef TX_ENABLE_EVENT_LOGGING +UINT _tx_el_interrupt_control(UINT new_posture); +#define tx_interrupt_control _tx_el_interrupt_control +#else +#ifdef TX_ENABLE_EVENT_TRACE +#define tx_interrupt_control _tx_trace_interrupt_control +#else +#define tx_interrupt_control _tx_thread_interrupt_control +#endif +#endif + +#define tx_mutex_create(m,n,i) _txe_mutex_create((m),(n),(i),(sizeof(TX_MUTEX))) +#define tx_mutex_delete _txe_mutex_delete +#define tx_mutex_get _txe_mutex_get +#define tx_mutex_info_get _txe_mutex_info_get +#define tx_mutex_performance_info_get _tx_mutex_performance_info_get +#define tx_mutex_performance_system_info_get _tx_mutex_performance_system_info_get +#define tx_mutex_prioritize _txe_mutex_prioritize +#define tx_mutex_put _txe_mutex_put + +#define tx_queue_create(q,n,m,s,l) _txe_queue_create((q),(n),(m),(s),(l),(sizeof(TX_QUEUE))) +#define tx_queue_delete _txe_queue_delete +#define tx_queue_flush _txe_queue_flush +#define tx_queue_info_get _txe_queue_info_get +#define tx_queue_performance_info_get _tx_queue_performance_info_get +#define tx_queue_performance_system_info_get _tx_queue_performance_system_info_get +#define tx_queue_receive _txe_queue_receive +#define tx_queue_send _txe_queue_send +#define tx_queue_send_notify _txe_queue_send_notify +#define tx_queue_front_send _txe_queue_front_send +#define tx_queue_prioritize _txe_queue_prioritize + +#define tx_semaphore_ceiling_put _txe_semaphore_ceiling_put +#define tx_semaphore_create(s,n,i) _txe_semaphore_create((s),(n),(i),(sizeof(TX_SEMAPHORE))) +#define tx_semaphore_delete _txe_semaphore_delete +#define tx_semaphore_get _txe_semaphore_get +#define tx_semaphore_info_get _txe_semaphore_info_get +#define tx_semaphore_performance_info_get _tx_semaphore_performance_info_get +#define tx_semaphore_performance_system_info_get _tx_semaphore_performance_system_info_get +#define tx_semaphore_prioritize _txe_semaphore_prioritize +#define tx_semaphore_put _txe_semaphore_put +#define tx_semaphore_put_notify _txe_semaphore_put_notify + +#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))) +#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 +#define tx_thread_info_get _txe_thread_info_get +#define tx_thread_performance_info_get _tx_thread_performance_info_get +#define tx_thread_performance_system_info_get _tx_thread_performance_system_info_get +#define tx_thread_preemption_change _txe_thread_preemption_change +#define tx_thread_priority_change _txe_thread_priority_change +#define tx_thread_relinquish _txe_thread_relinquish +#define tx_thread_reset _txe_thread_reset +#define tx_thread_resume _txe_thread_resume +#define tx_thread_sleep _tx_thread_sleep +#define tx_thread_stack_error_notify _tx_thread_stack_error_notify +#define tx_thread_suspend _txe_thread_suspend +#define tx_thread_terminate _txe_thread_terminate +#define tx_thread_time_slice_change _txe_thread_time_slice_change +#define tx_thread_wait_abort _txe_thread_wait_abort + +#define tx_time_get _tx_time_get +#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(t,n,e,i,c,r,a) _txe_timer_create((t),(n),(e),(i),(c),(r),(a),(sizeof(TX_TIMER))) +#define tx_timer_deactivate _txe_timer_deactivate +#define tx_timer_delete _txe_timer_delete +#define tx_timer_info_get _txe_timer_info_get +#define tx_timer_performance_info_get _tx_timer_performance_info_get +#define tx_timer_performance_system_info_get _tx_timer_performance_system_info_get + +#define tx_trace_enable _tx_trace_enable +#define tx_trace_event_filter _tx_trace_event_filter +#define tx_trace_event_unfilter _tx_trace_event_unfilter +#define tx_trace_disable _tx_trace_disable +#define tx_trace_isr_enter_insert _tx_trace_isr_enter_insert +#define tx_trace_isr_exit_insert _tx_trace_isr_exit_insert +#define tx_trace_buffer_full_notify _tx_trace_buffer_full_notify +#define tx_trace_user_event_insert _tx_trace_user_event_insert + +#endif +#endif + +#endif + + +/* Declare the tx_application_define function as having C linkage. */ + +VOID tx_application_define(VOID *first_unused_memory); + + +/* Define the function prototypes of the ThreadX API. */ + + +/* Define block memory pool management function prototypes. */ + +UINT _tx_block_allocate(TX_BLOCK_POOL *pool_ptr, VOID **block_ptr, ULONG wait_option); +UINT _tx_block_pool_create(TX_BLOCK_POOL *pool_ptr, CHAR *name_ptr, ULONG block_size, + VOID *pool_start, ULONG pool_size); +UINT _tx_block_pool_delete(TX_BLOCK_POOL *pool_ptr); +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); +UINT _tx_block_pool_performance_info_get(TX_BLOCK_POOL *pool_ptr, ULONG *allocates, ULONG *releases, + ULONG *suspensions, ULONG *timeouts); +UINT _tx_block_pool_performance_system_info_get(ULONG *allocates, ULONG *releases, + ULONG *suspensions, ULONG *timeouts); +UINT _tx_block_pool_prioritize(TX_BLOCK_POOL *pool_ptr); +UINT _tx_block_release(VOID *block_ptr); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_block_allocate(TX_BLOCK_POOL *pool_ptr, VOID **block_ptr, ULONG wait_option); +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); +UINT _txe_block_pool_delete(TX_BLOCK_POOL *pool_ptr); +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 _txe_block_pool_prioritize(TX_BLOCK_POOL *pool_ptr); +UINT _txe_block_release(VOID *block_ptr); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_block_allocate(TX_BLOCK_POOL *pool_ptr, VOID **block_ptr, ULONG wait_option); +UINT _txr_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); +UINT _txr_block_pool_delete(TX_BLOCK_POOL *pool_ptr); +UINT _txr_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 _txr_block_pool_prioritize(TX_BLOCK_POOL *pool_ptr); +UINT _txr_block_release(VOID *block_ptr); +#endif + + +/* Define byte memory pool management function prototypes. */ + +UINT _tx_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, ULONG memory_size, + ULONG wait_option); +UINT _tx_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start, + ULONG pool_size); +UINT _tx_byte_pool_delete(TX_BYTE_POOL *pool_ptr); +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); +UINT _tx_byte_pool_performance_info_get(TX_BYTE_POOL *pool_ptr, ULONG *allocates, ULONG *releases, + ULONG *fragments_searched, ULONG *merges, ULONG *splits, ULONG *suspensions, ULONG *timeouts); +UINT _tx_byte_pool_performance_system_info_get(ULONG *allocates, ULONG *releases, + ULONG *fragments_searched, ULONG *merges, ULONG *splits, ULONG *suspensions, ULONG *timeouts); +UINT _tx_byte_pool_prioritize(TX_BYTE_POOL *pool_ptr); +UINT _tx_byte_release(VOID *memory_ptr); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, ULONG memory_size, + ULONG wait_option); +UINT _txe_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start, + ULONG pool_size, UINT pool_control_block_size); +UINT _txe_byte_pool_delete(TX_BYTE_POOL *pool_ptr); +UINT _txe_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); +UINT _txe_byte_pool_prioritize(TX_BYTE_POOL *pool_ptr); +UINT _txe_byte_release(VOID *memory_ptr); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, ULONG memory_size, + ULONG wait_option); +UINT _txr_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start, + ULONG pool_size, UINT pool_control_block_size); +UINT _txr_byte_pool_delete(TX_BYTE_POOL *pool_ptr); +UINT _txr_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); +UINT _txr_byte_pool_prioritize(TX_BYTE_POOL *pool_ptr); +UINT _txr_byte_release(VOID *memory_ptr); +#endif + + +/* Define event flags management function prototypes. */ + +UINT _tx_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr); +UINT _tx_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_ptr); +UINT _tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, + UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option); +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); +UINT _tx_event_flags_performance_info_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG *sets, ULONG *gets, + ULONG *suspensions, ULONG *timeouts); +UINT _tx_event_flags_performance_system_info_get(ULONG *sets, ULONG *gets, + ULONG *suspensions, ULONG *timeouts); +UINT _tx_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, + UINT set_option); +UINT _tx_event_flags_set_notify(TX_EVENT_FLAGS_GROUP *group_ptr, VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr, UINT event_control_block_size); +UINT _txe_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_ptr); +UINT _txe_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, + UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option); +UINT _txe_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); +UINT _txe_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, + UINT set_option); +UINT _txe_event_flags_set_notify(TX_EVENT_FLAGS_GROUP *group_ptr, VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr, UINT event_control_block_size); +UINT _txr_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_ptr); +UINT _txr_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, + UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option); +UINT _txr_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); +UINT _txr_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, + UINT set_option); +UINT _txr_event_flags_set_notify(TX_EVENT_FLAGS_GROUP *group_ptr, VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); +#endif + + +/* Define initialization function prototypes. */ + +VOID _tx_initialize_kernel_enter(VOID); + + +/* Define mutex management function prototypes. */ + +UINT _tx_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit); +UINT _tx_mutex_delete(TX_MUTEX *mutex_ptr); +UINT _tx_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option); +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); +UINT _tx_mutex_performance_info_get(TX_MUTEX *mutex_ptr, ULONG *puts, ULONG *gets, + ULONG *suspensions, ULONG *timeouts, ULONG *inversions, ULONG *inheritances); +UINT _tx_mutex_performance_system_info_get(ULONG *puts, ULONG *gets, ULONG *suspensions, ULONG *timeouts, + ULONG *inversions, ULONG *inheritances); +UINT _tx_mutex_prioritize(TX_MUTEX *mutex_ptr); +UINT _tx_mutex_put(TX_MUTEX *mutex_ptr); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit, UINT mutex_control_block_size); +UINT _txe_mutex_delete(TX_MUTEX *mutex_ptr); +UINT _txe_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option); +UINT _txe_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); +UINT _txe_mutex_prioritize(TX_MUTEX *mutex_ptr); +UINT _txe_mutex_put(TX_MUTEX *mutex_ptr); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit, UINT mutex_control_block_size); +UINT _txr_mutex_delete(TX_MUTEX *mutex_ptr); +UINT _txr_mutex_get(TX_MUTEX *mutex_ptr, ULONG wait_option); +UINT _txr_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); +UINT _txr_mutex_prioritize(TX_MUTEX *mutex_ptr); +UINT _txr_mutex_put(TX_MUTEX *mutex_ptr); +#endif + + +/* Define queue management function prototypes. */ + +UINT _tx_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size, + VOID *queue_start, ULONG queue_size); +UINT _tx_queue_delete(TX_QUEUE *queue_ptr); +UINT _tx_queue_flush(TX_QUEUE *queue_ptr); +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); +UINT _tx_queue_performance_info_get(TX_QUEUE *queue_ptr, ULONG *messages_sent, ULONG *messages_received, + ULONG *empty_suspensions, ULONG *full_suspensions, ULONG *full_errors, ULONG *timeouts); +UINT _tx_queue_performance_system_info_get(ULONG *messages_sent, ULONG *messages_received, + ULONG *empty_suspensions, ULONG *full_suspensions, ULONG *full_errors, ULONG *timeouts); +UINT _tx_queue_prioritize(TX_QUEUE *queue_ptr); +UINT _tx_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_ptr, ULONG wait_option); +UINT _tx_queue_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option); +UINT _tx_queue_send_notify(TX_QUEUE *queue_ptr, VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); +UINT _tx_queue_front_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size, + VOID *queue_start, ULONG queue_size, UINT queue_control_block_size); +UINT _txe_queue_delete(TX_QUEUE *queue_ptr); +UINT _txe_queue_flush(TX_QUEUE *queue_ptr); +UINT _txe_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); +UINT _txe_queue_prioritize(TX_QUEUE *queue_ptr); +UINT _txe_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_ptr, ULONG wait_option); +UINT _txe_queue_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option); +UINT _txe_queue_send_notify(TX_QUEUE *queue_ptr, VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); +UINT _txe_queue_front_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size, + VOID *queue_start, ULONG queue_size, UINT queue_control_block_size); +UINT _txr_queue_delete(TX_QUEUE *queue_ptr); +UINT _txr_queue_flush(TX_QUEUE *queue_ptr); +UINT _txr_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); +UINT _txr_queue_prioritize(TX_QUEUE *queue_ptr); +UINT _txr_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_ptr, ULONG wait_option); +UINT _txr_queue_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option); +UINT _txr_queue_send_notify(TX_QUEUE *queue_ptr, VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); +UINT _txr_queue_front_send(TX_QUEUE *queue_ptr, VOID *source_ptr, ULONG wait_option); +#endif + + +/* Define semaphore management function prototypes. */ + +UINT _tx_semaphore_ceiling_put(TX_SEMAPHORE *semaphore_ptr, ULONG ceiling); +UINT _tx_semaphore_create(TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count); +UINT _tx_semaphore_delete(TX_SEMAPHORE *semaphore_ptr); +UINT _tx_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option); +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); +UINT _tx_semaphore_performance_info_get(TX_SEMAPHORE *semaphore_ptr, ULONG *puts, ULONG *gets, + ULONG *suspensions, ULONG *timeouts); +UINT _tx_semaphore_performance_system_info_get(ULONG *puts, ULONG *gets, ULONG *suspensions, ULONG *timeouts); +UINT _tx_semaphore_prioritize(TX_SEMAPHORE *semaphore_ptr); +UINT _tx_semaphore_put(TX_SEMAPHORE *semaphore_ptr); +UINT _tx_semaphore_put_notify(TX_SEMAPHORE *semaphore_ptr, VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_semaphore_ceiling_put(TX_SEMAPHORE *semaphore_ptr, ULONG ceiling); +UINT _txe_semaphore_create(TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count, UINT semaphore_control_block_size); +UINT _txe_semaphore_delete(TX_SEMAPHORE *semaphore_ptr); +UINT _txe_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option); +UINT _txe_semaphore_info_get(TX_SEMAPHORE *semaphore_ptr, CHAR **name, ULONG *current_value, + TX_THREAD **first_suspended, ULONG *suspended_count, + TX_SEMAPHORE **next_semaphore); +UINT _txe_semaphore_prioritize(TX_SEMAPHORE *semaphore_ptr); +UINT _txe_semaphore_put(TX_SEMAPHORE *semaphore_ptr); +UINT _txe_semaphore_put_notify(TX_SEMAPHORE *semaphore_ptr, VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_semaphore_ceiling_put(TX_SEMAPHORE *semaphore_ptr, ULONG ceiling); +UINT _txr_semaphore_create(TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count, UINT semaphore_control_block_size); +UINT _txr_semaphore_delete(TX_SEMAPHORE *semaphore_ptr); +UINT _txr_semaphore_get(TX_SEMAPHORE *semaphore_ptr, ULONG wait_option); +UINT _txr_semaphore_info_get(TX_SEMAPHORE *semaphore_ptr, CHAR **name, ULONG *current_value, + TX_THREAD **first_suspended, ULONG *suspended_count, + TX_SEMAPHORE **next_semaphore); +UINT _txr_semaphore_prioritize(TX_SEMAPHORE *semaphore_ptr); +UINT _txr_semaphore_put(TX_SEMAPHORE *semaphore_ptr); +UINT _txr_semaphore_put_notify(TX_SEMAPHORE *semaphore_ptr, VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); +#endif + + +/* Define thread control function prototypes. */ + +VOID _tx_thread_context_save(VOID); +VOID _tx_thread_context_restore(VOID); +UINT _tx_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, + VOID (*entry_function)(ULONG entry_input), ULONG 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); +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); +UINT _tx_thread_interrupt_control(UINT new_posture); +UINT _tx_thread_performance_info_get(TX_THREAD *thread_ptr, ULONG *resumptions, ULONG *suspensions, + ULONG *solicited_preemptions, ULONG *interrupt_preemptions, ULONG *priority_inversions, + ULONG *time_slices, ULONG *relinquishes, ULONG *timeouts, ULONG *wait_aborts, TX_THREAD **last_preempted_by); +UINT _tx_thread_performance_system_info_get(ULONG *resumptions, ULONG *suspensions, + ULONG *solicited_preemptions, ULONG *interrupt_preemptions, ULONG *priority_inversions, + ULONG *time_slices, ULONG *relinquishes, ULONG *timeouts, ULONG *wait_aborts, + ULONG *non_idle_returns, ULONG *idle_returns); +UINT _tx_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, + UINT *old_threshold); +UINT _tx_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, + UINT *old_priority); +VOID _tx_thread_relinquish(VOID); +UINT _tx_thread_reset(TX_THREAD *thread_ptr); +UINT _tx_thread_resume(TX_THREAD *thread_ptr); +UINT _tx_thread_sleep(ULONG timer_ticks); +UINT _tx_thread_stack_error_notify(VOID (*stack_error_handler)(TX_THREAD *thread_ptr)); +UINT _tx_thread_suspend(TX_THREAD *thread_ptr); +UINT _tx_thread_terminate(TX_THREAD *thread_ptr); +UINT _tx_thread_time_slice_change(TX_THREAD *thread_ptr, ULONG new_time_slice, ULONG *old_time_slice); +UINT _tx_thread_wait_abort(TX_THREAD *thread_ptr); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, + VOID (*entry_function)(ULONG entry_input), 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); +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, CHAR **name, UINT *state, ULONG *run_count, + UINT *priority, UINT *preemption_threshold, ULONG *time_slice, + TX_THREAD **next_thread, TX_THREAD **next_suspended_thread); +UINT _txe_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, + UINT *old_threshold); +UINT _txe_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, + UINT *old_priority); +VOID _txe_thread_relinquish(VOID); +UINT _txe_thread_reset(TX_THREAD *thread_ptr); +UINT _txe_thread_resume(TX_THREAD *thread_ptr); +UINT _txe_thread_suspend(TX_THREAD *thread_ptr); +UINT _txe_thread_terminate(TX_THREAD *thread_ptr); +UINT _txe_thread_time_slice_change(TX_THREAD *thread_ptr, ULONG new_time_slice, ULONG *old_time_slice); +UINT _txe_thread_wait_abort(TX_THREAD *thread_ptr); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_thread_create(TX_THREAD *thread_ptr, CHAR *name_ptr, + VOID (*entry_function)(ULONG entry_input), 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); +UINT _txr_thread_delete(TX_THREAD *thread_ptr); +UINT _txr_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type)); +UINT _txr_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); +UINT _txr_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, + UINT *old_threshold); +UINT _txr_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, + UINT *old_priority); +UINT _txr_thread_reset(TX_THREAD *thread_ptr); +UINT _txr_thread_resume(TX_THREAD *thread_ptr); +UINT _txr_thread_suspend(TX_THREAD *thread_ptr); +UINT _txr_thread_terminate(TX_THREAD *thread_ptr); +UINT _txr_thread_time_slice_change(TX_THREAD *thread_ptr, ULONG new_time_slice, ULONG *old_time_slice); +UINT _txr_thread_wait_abort(TX_THREAD *thread_ptr); +#endif + + +/* Define timer management function prototypes. */ + +UINT _tx_timer_activate(TX_TIMER *timer_ptr); +UINT _tx_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG reschedule_ticks); +UINT _tx_timer_create(TX_TIMER *timer_ptr, CHAR *name_ptr, + VOID (*expiration_function)(ULONG input), ULONG 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, CHAR **name, UINT *active, ULONG *remaining_ticks, + ULONG *reschedule_ticks, TX_TIMER **next_timer); +UINT _tx_timer_performance_info_get(TX_TIMER *timer_ptr, ULONG *activates, ULONG *reactivates, + ULONG *deactivates, ULONG *expirations, ULONG *expiration_adjusts); +UINT _tx_timer_performance_system_info_get(ULONG *activates, ULONG *reactivates, + ULONG *deactivates, ULONG *expirations, ULONG *expiration_adjusts); + +ULONG _tx_time_get(VOID); +VOID _tx_time_set(ULONG new_time); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _txe_timer_activate(TX_TIMER *timer_ptr); +UINT _txe_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG reschedule_ticks); +UINT _txe_timer_create(TX_TIMER *timer_ptr, 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_deactivate(TX_TIMER *timer_ptr); +UINT _txe_timer_delete(TX_TIMER *timer_ptr); +UINT _txe_timer_info_get(TX_TIMER *timer_ptr, CHAR **name, UINT *active, ULONG *remaining_ticks, + ULONG *reschedule_ticks, TX_TIMER **next_timer); +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING +UINT _txr_timer_activate(TX_TIMER *timer_ptr); +UINT _txr_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG reschedule_ticks); +UINT _txr_timer_create(TX_TIMER *timer_ptr, 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 _txr_timer_deactivate(TX_TIMER *timer_ptr); +UINT _txr_timer_delete(TX_TIMER *timer_ptr); +UINT _txr_timer_info_get(TX_TIMER *timer_ptr, CHAR **name, UINT *active, ULONG *remaining_ticks, + ULONG *reschedule_ticks, TX_TIMER **next_timer); +#endif + + +/* Define trace API function prototypes. */ + +UINT _tx_trace_enable(VOID *trace_buffer_start, ULONG trace_buffer_size, ULONG registry_entries); +UINT _tx_trace_event_filter(ULONG event_filter_bits); +UINT _tx_trace_event_unfilter(ULONG event_unfilter_bits); +UINT _tx_trace_disable(VOID); +VOID _tx_trace_isr_enter_insert(ULONG isr_id); +VOID _tx_trace_isr_exit_insert(ULONG isr_id); +UINT _tx_trace_buffer_full_notify(VOID (*full_buffer_callback)(VOID *buffer)); +UINT _tx_trace_user_event_insert(ULONG event_id, ULONG info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4); +UINT _tx_trace_interrupt_control(UINT new_posture); + + +/* Add a default macro that can be re-defined in tx_port.h to add default processing when a thread starts. Common usage + would be for enabling floating point for a thread by default, however, the additional processing could be anything + defined in tx_port.h. */ + +#ifndef TX_THREAD_STARTED_EXTENSION +#define TX_THREAD_STARTED_EXTENSION(thread_ptr) +#endif + + +/* Add a default macro that can be re-defined in tx_port.h to add processing to the thread stack analyze function. + By default, this is simply defined as whitespace. */ + +#ifndef TX_THREAD_STACK_ANALYZE_EXTENSION +#define TX_THREAD_STACK_ANALYZE_EXTENSION +#endif + + +/* Add a default macro that can be re-defined in tx_port.h to add processing to the initialize kernel enter function. + By default, this is simply defined as whitespace. */ + +#ifndef TX_INITIALIZE_KERNEL_ENTER_EXTENSION +#define TX_INITIALIZE_KERNEL_ENTER_EXTENSION +#endif + + +/* Add a default macro that can be re-defined in tx_port.h to add processing to the initialize random number generator. + By default, this is simply defined as whitespace. */ + +#ifndef TX_INITIALIZE_RANDOM_GENERATOR_INITIALIZATION +#define TX_INITIALIZE_RANDOM_GENERATOR_INITIALIZATION +#endif + + +/* Define the TX_RAND macro to the standard library function, if not already defined. */ + +#ifndef TX_RAND +#define TX_RAND() rand() +#endif + + +/* Check for MISRA compliance requirements. */ + +#ifdef TX_MISRA_ENABLE + + +/* Define MISRA-specific routines. */ + +VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); +UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); +UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); +ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); +ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); +ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); +ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); +ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); +VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); +VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, UINT size); +ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, TX_TIMER_INTERNAL **ptr2); +TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL **ptr1, ULONG size); +VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL *internal_timer, TX_TIMER **user_timer); +VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, VOID **highest_stack); +VOID _tx_misra_trace_event_insert(ULONG event_id, VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4, ULONG filter, ULONG time_stamp); +UINT _tx_misra_always_true(void); +UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **pointer); +UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); +UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); +TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); +UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); +TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); +UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); +TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); +UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); +ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); +TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); +TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); +ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); +TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); +UINT _tx_misra_status_get(UINT status); +TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); +TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); +VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); +TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); +VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); +CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); +TX_THREAD *_tx_misra_void_to_thread_pointer_convert(VOID *pointer); +UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); +VOID _tx_misra_event_flags_group_not_used(TX_EVENT_FLAGS_GROUP *group_ptr); +VOID _tx_misra_event_flags_set_notify_not_used(VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); +VOID _tx_misra_queue_not_used(TX_QUEUE *queue_ptr); +VOID _tx_misra_queue_send_notify_not_used(VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); +VOID _tx_misra_semaphore_not_used(TX_SEMAPHORE *semaphore_ptr); +VOID _tx_misra_semaphore_put_notify_not_used(VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); +VOID _tx_misra_thread_not_used(TX_THREAD *thread_ptr); +VOID _tx_misra_thread_entry_exit_notify_not_used(VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id)); + +#define TX_MEMSET(a,b,c) _tx_misra_memset((a), (UINT) (b), (UINT) (c)) +#define TX_UCHAR_POINTER_ADD(a,b) _tx_misra_uchar_pointer_add((UCHAR *) (a), (ULONG) (b)) +#define TX_UCHAR_POINTER_SUB(a,b) _tx_misra_uchar_pointer_sub((UCHAR *) (a), (ULONG) (b)) +#define TX_UCHAR_POINTER_DIF(a,b) _tx_misra_uchar_pointer_dif((UCHAR *) (a), (UCHAR *) (b)) +#define TX_ULONG_POINTER_ADD(a,b) _tx_misra_ulong_pointer_add((ULONG *) (a), (ULONG) (b)) +#define TX_ULONG_POINTER_SUB(a,b) _tx_misra_ulong_pointer_sub((ULONG *) (a), (ULONG) (b)) +#define TX_ULONG_POINTER_DIF(a,b) _tx_misra_ulong_pointer_dif((ULONG *) (a), (ULONG *) (b)) +#define TX_POINTER_TO_ULONG_CONVERT(a) _tx_misra_pointer_to_ulong_convert((VOID *) (a)) +#define TX_ULONG_TO_POINTER_CONVERT(a) _tx_misra_ulong_to_pointer_convert((ULONG) (a)) +#define TX_QUEUE_MESSAGE_COPY(s,d,z) _tx_misra_message_copy(&(s), &(d), (z)); +#define TX_TIMER_POINTER_DIF(a,b) _tx_misra_timer_pointer_dif((TX_TIMER_INTERNAL **) (a), (TX_TIMER_INTERNAL **) (b)) +#define TX_TIMER_POINTER_ADD(a,b) _tx_misra_timer_pointer_add((TX_TIMER_INTERNAL **) (a), (ULONG) (b)) +#define TX_USER_TIMER_POINTER_GET(a,b) _tx_misra_user_timer_pointer_get((TX_TIMER_INTERNAL *) (a), (TX_TIMER **) &(b)); +#define TX_THREAD_STACK_CHECK(a) _tx_misra_thread_stack_check((a), &((a)->tx_thread_stack_highest_ptr)); +#ifdef TX_ENABLE_EVENT_TRACE +#define TX_TRACE_IN_LINE_INSERT(i,a,b,c,d,e) _tx_misra_trace_event_insert((ULONG) (i), (VOID *) (a), (ULONG) (b), (ULONG) (c), (ULONG) (d), (ULONG) (e), ((ULONG) TX_TRACE_TIME_SOURCE)); +#endif +#define TX_LOOP_FOREVER (_tx_misra_always_true() == TX_TRUE) +#define TX_INDIRECT_VOID_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_indirect_void_to_uchar_pointer_convert((a)) +#define TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(a) _tx_misra_uchar_to_indirect_uchar_pointer_convert((a)) +#define TX_BLOCK_POOL_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_block_pool_to_uchar_pointer_convert((a)) +#define TX_VOID_TO_BLOCK_POOL_POINTER_CONVERT(a) _tx_misra_void_to_block_pool_pointer_convert((a)) +#define TX_VOID_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_void_to_uchar_pointer_convert((a)) +#define TX_UCHAR_TO_BLOCK_POOL_POINTER_CONVERT(a) _tx_misra_uchar_to_block_pool_pointer_convert((a)) +#define TX_VOID_TO_INDIRECT_UCHAR_POINTER_CONVERT(a) _tx_misra_void_to_indirect_uchar_pointer_convert((a)) +#define TX_VOID_TO_BYTE_POOL_POINTER_CONVERT(a) _tx_misra_void_to_byte_pool_pointer_convert((a)) +#define TX_BYTE_POOL_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_byte_pool_to_uchar_pointer_convert((a)) +#define TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(a) _tx_misra_uchar_to_align_type_pointer_convert((a)) +#define TX_UCHAR_TO_INDIRECT_BYTE_POOL_POINTER(a) _tx_misra_uchar_to_indirect_byte_pool_pointer_convert((a)) +#define TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(a) _tx_misra_void_to_event_flags_pointer_convert((a)) +#define TX_VOID_TO_ULONG_POINTER_CONVERT(a) _tx_misra_void_to_ulong_pointer_convert((a)) +#define TX_VOID_TO_MUTEX_POINTER_CONVERT(a) _tx_misra_void_to_mutex_pointer_convert((a)) +#define TX_MUTEX_PRIORITIZE_MISRA_EXTENSION(a) _tx_misra_status_get((a)) +#define TX_VOID_TO_QUEUE_POINTER_CONVERT(a) _tx_misra_void_to_queue_pointer_convert((a)) +#define TX_VOID_TO_SEMAPHORE_POINTER_CONVERT(a) _tx_misra_void_to_semaphore_pointer_convert((a)) +#define TX_UCHAR_TO_VOID_POINTER_CONVERT(a) _tx_misra_uchar_to_void_pointer_convert((a)) +#define TX_ULONG_TO_THREAD_POINTER_CONVERT(a) _tx_misra_ulong_to_thread_pointer_convert((a)) +#define TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(a) _tx_misra_timer_indirect_to_void_pointer_convert((a)) +#ifndef TX_TIMER_INITIALIZE_EXTENSION +#define TX_TIMER_INITIALIZE_EXTENSION(a) status = _tx_misra_status_get((a)); +#endif +#define TX_CONST_CHAR_TO_CHAR_POINTER_CONVERT(a) _tx_misra_const_char_to_char_pointer_convert((a)) +#define TX_VOID_TO_THREAD_POINTER_CONVERT(a) _tx_misra_void_to_thread_pointer_convert((a)) +#define TX_CHAR_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_char_to_uchar_pointer_convert((a)) +#define TX_EVENT_FLAGS_GROUP_NOT_USED(a) _tx_misra_event_flags_group_not_used((a)) +#define TX_EVENT_FLAGS_SET_NOTIFY_NOT_USED(a) _tx_misra_event_flags_set_notify_not_used((a)) +#define TX_QUEUE_NOT_USED(a) _tx_misra_queue_not_used((a)) +#define TX_QUEUE_SEND_NOTIFY_NOT_USED(a) _tx_misra_queue_send_notify_not_used((a)) +#define TX_SEMAPHORE_NOT_USED(a) _tx_misra_semaphore_not_used((a)) +#define TX_SEMAPHORE_PUT_NOTIFY_NOT_USED(a) _tx_misra_semaphore_put_notify_not_used((a)) +#define TX_THREAD_NOT_USED(a) _tx_misra_thread_not_used((a)) +#define TX_THREAD_ENTRY_EXIT_NOTIFY_NOT_USED(a) _tx_misra_thread_entry_exit_notify_not_used((a)) + +#else + +/* Define the TX_MEMSET macro to the standard library function, if not already defined. */ + +#ifndef TX_MEMSET +#define TX_MEMSET(a,b,c) memset((a),(b),(c)) +#endif + +#define TX_UCHAR_POINTER_ADD(a,b) (((UCHAR *) (a)) + ((UINT) (b))) +#define TX_UCHAR_POINTER_SUB(a,b) (((UCHAR *) (a)) - ((UINT) (b))) +#define TX_UCHAR_POINTER_DIF(a,b) ((ULONG)(((UCHAR *) (a)) - ((UCHAR *) (b)))) +#define TX_ULONG_POINTER_ADD(a,b) (((ULONG *) (a)) + ((UINT) (b))) +#define TX_ULONG_POINTER_SUB(a,b) (((ULONG *) (a)) - ((UINT) (b))) +#define TX_ULONG_POINTER_DIF(a,b) ((ULONG)(((ULONG *) (a)) - ((ULONG *) (b)))) +#define TX_POINTER_TO_ULONG_CONVERT(a) ((ULONG) ((VOID *) (a))) +#define TX_ULONG_TO_POINTER_CONVERT(a) ((VOID *) ((ULONG) (a))) +#define TX_POINTER_TO_ALIGN_TYPE_CONVERT(a) ((ALIGN_TYPE) ((VOID *) (a))) +#define TX_ALIGN_TYPE_TO_POINTER_CONVERT(a) ((VOID *) ((ALIGN_TYPE) (a))) +#define TX_TIMER_POINTER_DIF(a,b) ((ULONG)(((TX_TIMER_INTERNAL **) (a)) - ((TX_TIMER_INTERNAL **) (b)))) +#define TX_TIMER_POINTER_ADD(a,b) (((TX_TIMER_INTERNAL **) (a)) + ((ULONG) (b))) +#define TX_USER_TIMER_POINTER_GET(a,b) { \ + UCHAR *working_ptr; \ + working_ptr = (UCHAR *) (a); \ + (b) = (TX_TIMER *) working_ptr; \ + working_ptr = working_ptr - (((UCHAR *) &(b) -> tx_timer_internal) - ((UCHAR *) &(b) -> tx_timer_id)); \ + (b) = (TX_TIMER *) working_ptr; \ + } +#define TX_LOOP_FOREVER ((UINT) 1) +#define TX_INDIRECT_VOID_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR **) ((VOID *) (a))) +#define TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(a) ((UCHAR **) ((VOID *) (a))) +#define TX_BLOCK_POOL_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR *) ((VOID *) (a))) +#define TX_VOID_TO_BLOCK_POOL_POINTER_CONVERT(a) ((TX_BLOCK_POOL *) ((VOID *) (a))) +#define TX_VOID_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR *) ((VOID *) (a))) +#define TX_UCHAR_TO_BLOCK_POOL_POINTER_CONVERT(a) ((TX_BLOCK_POOL *) ((VOID *) (a))) +#define TX_VOID_TO_INDIRECT_UCHAR_POINTER_CONVERT(a) ((UCHAR **) ((VOID *) (a))) +#define TX_VOID_TO_BYTE_POOL_POINTER_CONVERT(a) ((TX_BYTE_POOL *) ((VOID *) (a))) +#define TX_BYTE_POOL_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR *) ((VOID *) (a))) +#ifndef TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT +#define TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(a) ((ALIGN_TYPE *) ((VOID *) (a))) +#endif +#define TX_UCHAR_TO_INDIRECT_BYTE_POOL_POINTER(a) ((TX_BYTE_POOL **) ((VOID *) (a))) +#define TX_VOID_TO_EVENT_FLAGS_POINTER_CONVERT(a) ((TX_EVENT_FLAGS_GROUP *) ((VOID *) (a))) +#define TX_VOID_TO_ULONG_POINTER_CONVERT(a) ((ULONG *) ((VOID *) (a))) +#define TX_VOID_TO_MUTEX_POINTER_CONVERT(a) ((TX_MUTEX *) ((VOID *) (a))) +#define TX_VOID_TO_QUEUE_POINTER_CONVERT(a) ((TX_QUEUE *) ((VOID *) (a))) +#define TX_VOID_TO_SEMAPHORE_POINTER_CONVERT(a) ((TX_SEMAPHORE *) ((VOID *) (a))) +#define TX_UCHAR_TO_VOID_POINTER_CONVERT(a) ((VOID *) (a)) +#define TX_ULONG_TO_THREAD_POINTER_CONVERT(a) ((TX_THREAD *) ((VOID *) (a))) +#ifndef TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT +#define TX_TIMER_INDIRECT_TO_VOID_POINTER_CONVERT(a) ((VOID *) (a)) +#endif +#ifndef TX_TIMER_INITIALIZE_EXTENSION +#define TX_TIMER_INITIALIZE_EXTENSION(a) +#endif +#define TX_CONST_CHAR_TO_CHAR_POINTER_CONVERT(a) ((CHAR *) ((VOID *) (a))) +#define TX_VOID_TO_THREAD_POINTER_CONVERT(a) ((TX_THREAD *) ((VOID *) (a))) +#define TX_CHAR_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR *) ((VOID *) (a))) +#ifndef TX_EVENT_FLAGS_GROUP_NOT_USED +#define TX_EVENT_FLAGS_GROUP_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_EVENT_FLAGS_SET_NOTIFY_NOT_USED +#define TX_EVENT_FLAGS_SET_NOTIFY_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_QUEUE_NOT_USED +#define TX_QUEUE_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_QUEUE_SEND_NOTIFY_NOT_USED +#define TX_QUEUE_SEND_NOTIFY_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_SEMAPHORE_NOT_USED +#define TX_SEMAPHORE_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_SEMAPHORE_PUT_NOTIFY_NOT_USED +#define TX_SEMAPHORE_PUT_NOTIFY_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_THREAD_NOT_USED +#define TX_THREAD_NOT_USED(a) ((void)(a)) +#endif +#ifndef TX_THREAD_ENTRY_EXIT_NOTIFY_NOT_USED +#define TX_THREAD_ENTRY_EXIT_NOTIFY_NOT_USED(a) ((void)(a)) +#endif + +#endif + + +/* Determine if there is an tx_api.h extension file to include. */ + +#ifdef TX_THREAD_API_EXTENSION + +/* Yes, bring in the tx_api.h extension file. */ +#include "tx_api_extension.h" + +#endif + + +/* Define safety critical configuration and exception handling. */ + +#ifdef TX_SAFETY_CRITICAL + +/* Ensure the maximum number of priorities is defined in safety critical mode. */ +#ifndef TX_MAX_PRIORITIES +#error "tx_port.h: TX_MAX_PRIORITIES not defined." +#endif + +/* Ensure the maximum number of priorities is a multiple of 32. */ +#if (TX_MAX_PRIORITIES %32) != 0 +#error "tx_port.h: TX_MAX_PRIORITIES must be a multiple of 32." +#endif + +/* Ensure error checking is enabled. */ +#ifdef TX_DISABLE_ERROR_CHECKING +#error "TX_DISABLE_ERROR_CHECKING must not be defined." +#endif + +/* Ensure timer ISR processing is not defined. */ +#ifdef TX_TIMER_PROCESS_IN_ISR +#error "TX_TIMER_PROCESS_IN_ISR must not be defined." +#endif + +/* Ensure timer reactivation in-line is not defined. */ +#ifdef TX_REACTIVATE_INLINE +#error "TX_REACTIVATE_INLINE must not be defined." +#endif + +/* Ensure disable stack filling is not defined. */ +#ifdef TX_DISABLE_STACK_FILLING +#error "TX_DISABLE_STACK_FILLING must not be defined." +#endif + +/* Ensure enable stack checking is not defined. */ +#ifdef TX_ENABLE_STACK_CHECKING +#error "TX_ENABLE_STACK_CHECKING must not be defined." +#endif + +/* Ensure disable preemption-threshold is not defined. */ +#ifdef TX_DISABLE_PREEMPTION_THRESHOLD +#error "TX_DISABLE_PREEMPTION_THRESHOLD must not be defined." +#endif + +/* Ensure disable redundant clearing is not defined. */ +#ifdef TX_DISABLE_REDUNDANT_CLEARING +#error "TX_DISABLE_REDUNDANT_CLEARING must not be defined." +#endif + +/* Ensure no timer is not defined. */ +#ifdef TX_NO_TIMER +#error "TX_NO_TIMER must not be defined." +#endif + +/* Ensure disable notify callbacks is not defined. */ +#ifdef TX_DISABLE_NOTIFY_CALLBACKS +#error "TX_DISABLE_NOTIFY_CALLBACKS must not be defined." +#endif + +/* Ensure in-line thread suspend/resume is not defined. */ +#ifdef TX_INLINE_THREAD_RESUME_SUSPEND +#error "TX_INLINE_THREAD_RESUME_SUSPEND must not be defined." +#endif + +/* Ensure not interruptable is not defined. */ +#ifdef TX_NOT_INTERRUPTABLE +#error "TX_NOT_INTERRUPTABLE must not be defined." +#endif + +/* Ensure event trace enable is not defined. */ +#ifdef TX_ENABLE_EVENT_TRACE +#error "TX_ENABLE_EVENT_TRACE must not be defined." +#endif + +/* Ensure block pool performance info enable is not defined. */ +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#error "TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure byte pool performance info enable is not defined. */ +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#error "TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure event flag performance info enable is not defined. */ +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#error "TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure mutex performance info enable is not defined. */ +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO +#error "TX_MUTEX_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure queue performance info enable is not defined. */ +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO +#error "TX_QUEUE_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure semaphore performance info enable is not defined. */ +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#error "TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure thread performance info enable is not defined. */ +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO +#error "TX_THREAD_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + +/* Ensure timer performance info enable is not defined. */ +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO +#error "TX_TIMER_ENABLE_PERFORMANCE_INFO must not be defined." +#endif + + +/* Now define the safety critical exception handler. */ + +VOID _tx_safety_critical_exception_handler(CHAR *file_name, INT line_number, UINT status); + + +#ifndef TX_SAFETY_CRITICAL_EXCEPTION +#define TX_SAFETY_CRITICAL_EXCEPTION(a, b, c) _tx_safety_critical_exception_handler(a, b, c); +#endif + +#ifndef TX_SAFETY_CRITICAL_EXCEPTION_HANDLER +#define TX_SAFETY_CRITICAL_EXCEPTION_HANDLER VOID _tx_safety_critical_exception_handler(CHAR *file_name, INT line_number, UINT status) \ + { \ + while(1) \ + { \ + } \ + } +#endif +#endif + + +#ifdef TX_ENABLE_MULTI_ERROR_CHECKING + +/* Define ThreadX API MULTI run-time error checking function. */ +void __ghs_rnerr(char *errMsg, int stackLevels, int stackTraceDisplay, void *hexVal); + +#endif + +/* Bring in the event logging constants and prototypes. Note that + TX_ENABLE_EVENT_LOGGING must be defined when building the ThreadX + library components in order to enable event logging. */ + +#ifdef TX_ENABLE_EVENT_LOGGING +#include "tx_el.h" +#else +#ifndef TX_SOURCE_CODE +#ifndef TX_MISRA_ENABLE +#define _tx_el_user_event_insert(a,b,c,d,e) +#endif +#endif +#define TX_EL_INITIALIZE +#define TX_EL_THREAD_REGISTER(a) +#define TX_EL_THREAD_UNREGISTER(a) +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) +#define TX_EL_BYTE_ALLOCATE_INSERT +#define TX_EL_BYTE_POOL_CREATE_INSERT +#define TX_EL_BYTE_POOL_DELETE_INSERT +#define TX_EL_BYTE_RELEASE_INSERT +#define TX_EL_BLOCK_ALLOCATE_INSERT +#define TX_EL_BLOCK_POOL_CREATE_INSERT +#define TX_EL_BLOCK_POOL_DELETE_INSERT +#define TX_EL_BLOCK_RELEASE_INSERT +#define TX_EL_EVENT_FLAGS_CREATE_INSERT +#define TX_EL_EVENT_FLAGS_DELETE_INSERT +#define TX_EL_EVENT_FLAGS_GET_INSERT +#define TX_EL_EVENT_FLAGS_SET_INSERT +#define TX_EL_INTERRUPT_CONTROL_INSERT +#define TX_EL_QUEUE_CREATE_INSERT +#define TX_EL_QUEUE_DELETE_INSERT +#define TX_EL_QUEUE_FLUSH_INSERT +#define TX_EL_QUEUE_RECEIVE_INSERT +#define TX_EL_QUEUE_SEND_INSERT +#define TX_EL_SEMAPHORE_CREATE_INSERT +#define TX_EL_SEMAPHORE_DELETE_INSERT +#define TX_EL_SEMAPHORE_GET_INSERT +#define TX_EL_SEMAPHORE_PUT_INSERT +#define TX_EL_THREAD_CREATE_INSERT +#define TX_EL_THREAD_DELETE_INSERT +#define TX_EL_THREAD_IDENTIFY_INSERT +#define TX_EL_THREAD_PREEMPTION_CHANGE_INSERT +#define TX_EL_THREAD_PRIORITY_CHANGE_INSERT +#define TX_EL_THREAD_RELINQUISH_INSERT +#define TX_EL_THREAD_RESUME_INSERT +#define TX_EL_THREAD_SLEEP_INSERT +#define TX_EL_THREAD_SUSPEND_INSERT +#define TX_EL_THREAD_TERMINATE_INSERT +#define TX_EL_THREAD_TIME_SLICE_CHANGE_INSERT +#define TX_EL_TIME_GET_INSERT +#define TX_EL_TIME_SET_INSERT +#define TX_EL_TIMER_ACTIVATE_INSERT +#define TX_EL_TIMER_CHANGE_INSERT +#define TX_EL_TIMER_CREATE_INSERT +#define TX_EL_TIMER_DEACTIVATE_INSERT +#define TX_EL_TIMER_DELETE_INSERT +#define TX_EL_BLOCK_POOL_INFO_GET_INSERT +#define TX_EL_BLOCK_POOL_PRIORITIZE_INSERT +#define TX_EL_BYTE_POOL_INFO_GET_INSERT +#define TX_EL_BYTE_POOL_PRIORITIZE_INSERT +#define TX_EL_EVENT_FLAGS_INFO_GET_INSERT +#define TX_EL_MUTEX_CREATE_INSERT +#define TX_EL_MUTEX_DELETE_INSERT +#define TX_EL_MUTEX_GET_INSERT +#define TX_EL_MUTEX_INFO_GET_INSERT +#define TX_EL_MUTEX_PRIORITIZE_INSERT +#define TX_EL_MUTEX_PUT_INSERT +#define TX_EL_QUEUE_INFO_GET_INSERT +#define TX_EL_QUEUE_FRONT_SEND_INSERT +#define TX_EL_QUEUE_PRIORITIZE_INSERT +#define TX_EL_SEMAPHORE_INFO_GET_INSERT +#define TX_EL_SEMAPHORE_PRIORITIZE_INSERT +#define TX_EL_THREAD_INFO_GET_INSERT +#define TX_EL_THREAD_WAIT_ABORT_INSERT +#define TX_EL_TIMER_INFO_GET_INSERT +#define TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_EVENT_FLAGS__PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_EVENT_FLAGS_SET_NOTIFY_INSERT +#define TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_QUEUE_SEND_NOTIFY_INSERT +#define TX_EL_SEMAPHORE_CEILING_PUT_INSERT +#define TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_SEMAPHORE_PUT_NOTIFY_INSERT +#define TX_EL_THREAD_ENTRY_EXIT_NOTIFY_INSERT +#define TX_EL_THREAD_RESET_INSERT +#define TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#define TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT +#define TX_EL_TIMER_PERFORMANCE_INFO_GET_INSERT +#define TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET_INSERT + +#endif + +/* Define the get system state macro. By default, it simply maps to the variable _tx_thread_system_state. */ +/* Note that prior to Azure RTOS 6.1, this symbol was defined in tx_thread.h. */ +#ifndef TX_THREAD_GET_SYSTEM_STATE +#define TX_THREAD_GET_SYSTEM_STATE() _tx_thread_system_state +#endif + + + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif + diff --git a/common/inc/tx_block_pool.h b/common/inc/tx_block_pool.h new file mode 100644 index 0000000..2a8bb51 --- /dev/null +++ b/common/inc/tx_block_pool.h @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_block_pool.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX block memory management component, */ +/* including all data types and external references. It is assumed */ +/* that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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_BLOCK_POOL_H +#define TX_BLOCK_POOL_H + + +/* Define block memory control specific data definitions. */ + +#define TX_BLOCK_POOL_ID ((ULONG) 0x424C4F43) + + +/* Determine if in-line component initialization is supported by the + caller. */ + +#ifdef TX_INVOKE_INLINE_INITIALIZATION + +/* Yes, in-line initialization is supported, remap the block memory pool + initialization function. */ + +#ifndef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#define _tx_block_pool_initialize() \ + _tx_block_pool_created_ptr = TX_NULL; \ + _tx_block_pool_created_count = TX_EMPTY +#else +#define _tx_block_pool_initialize() \ + _tx_block_pool_created_ptr = TX_NULL; \ + _tx_block_pool_created_count = TX_EMPTY; \ + _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 +#define TX_BLOCK_POOL_INIT +#else + +/* No in-line initialization is supported, use standard function call. */ +VOID _tx_block_pool_initialize(VOID); +#endif + + +/* Define internal block memory pool management function prototypes. */ + +VOID _tx_block_pool_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence); + + +/* Block pool management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_BLOCK_POOL_INIT +#define BLOCK_POOL_DECLARE +#else +#define BLOCK_POOL_DECLARE extern +#endif + + +/* Define the head pointer of the created block pool list. */ + +BLOCK_POOL_DECLARE TX_BLOCK_POOL * _tx_block_pool_created_ptr; + + +/* Define the variable that holds the number of created block pools. */ + +BLOCK_POOL_DECLARE ULONG _tx_block_pool_created_count; + + +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO + +/* Define the total number of block allocates. */ + +BLOCK_POOL_DECLARE ULONG _tx_block_pool_performance_allocate_count; + + +/* Define the total number of block releases. */ + +BLOCK_POOL_DECLARE ULONG _tx_block_pool_performance_release_count; + + +/* Define the total number of block pool suspensions. */ + +BLOCK_POOL_DECLARE ULONG _tx_block_pool_performance_suspension_count; + + +/* Define the total number of block pool timeouts. */ + +BLOCK_POOL_DECLARE ULONG _tx_block_pool_performance_timeout_count; + + +#endif + + +/* Define default post block pool delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_BLOCK_POOL_DELETE_PORT_COMPLETION +#define TX_BLOCK_POOL_DELETE_PORT_COMPLETION(p) +#endif + + +#endif diff --git a/common/inc/tx_byte_pool.h b/common/inc/tx_byte_pool.h new file mode 100644 index 0000000..8f1050f --- /dev/null +++ b/common/inc/tx_byte_pool.h @@ -0,0 +1,178 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_byte_pool.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX byte memory management component, */ +/* including all data types and external references. It is assumed */ +/* that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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_BYTE_POOL_H +#define TX_BYTE_POOL_H + + +/* Define byte memory control specific data definitions. */ + +#define TX_BYTE_POOL_ID ((ULONG) 0x42595445) + +#ifndef TX_BYTE_BLOCK_FREE +#define TX_BYTE_BLOCK_FREE ((ULONG) 0xFFFFEEEEUL) +#endif + +#ifndef TX_BYTE_BLOCK_MIN +#define TX_BYTE_BLOCK_MIN ((ULONG) 20) +#endif + +#ifndef TX_BYTE_POOL_MIN +#define TX_BYTE_POOL_MIN ((ULONG) 100) +#endif + + +/* Determine if in-line component initialization is supported by the + caller. */ + +#ifdef TX_INVOKE_INLINE_INITIALIZATION + +/* Yes, in-line initialization is supported, remap the byte memory pool + initialization function. */ + +#ifndef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#define _tx_byte_pool_initialize() \ + _tx_byte_pool_created_ptr = TX_NULL; \ + _tx_byte_pool_created_count = TX_EMPTY +#else +#define _tx_byte_pool_initialize() \ + _tx_byte_pool_created_ptr = TX_NULL; \ + _tx_byte_pool_created_count = TX_EMPTY; \ + _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 +#define TX_BYTE_POOL_INIT +#else + +/* No in-line initialization is supported, use standard function call. */ +VOID _tx_byte_pool_initialize(VOID); +#endif + + +/* Define internal byte memory pool management function prototypes. */ + +UCHAR *_tx_byte_pool_search(TX_BYTE_POOL *pool_ptr, ULONG memory_size); +VOID _tx_byte_pool_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence); + + +/* Byte pool management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_BYTE_POOL_INIT +#define BYTE_POOL_DECLARE +#else +#define BYTE_POOL_DECLARE extern +#endif + + +/* Define the head pointer of the created byte pool list. */ + +BYTE_POOL_DECLARE TX_BYTE_POOL * _tx_byte_pool_created_ptr; + + +/* Define the variable that holds the number of created byte pools. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_created_count; + + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + +/* Define the total number of allocates. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_allocate_count; + + +/* Define the total number of releases. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_release_count; + + +/* Define the total number of adjacent memory fragment merges. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_merge_count; + + +/* Define the total number of memory fragment splits. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_split_count; + + +/* Define the total number of memory fragments searched during allocation. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_search_count; + + +/* Define the total number of byte pool suspensions. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_suspension_count; + + +/* Define the total number of byte pool timeouts. */ + +BYTE_POOL_DECLARE ULONG _tx_byte_pool_performance_timeout_count; + + +#endif + + +/* Define default post byte pool delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_BYTE_POOL_DELETE_PORT_COMPLETION +#define TX_BYTE_POOL_DELETE_PORT_COMPLETION(p) +#endif + + +#endif diff --git a/common/inc/tx_event_flags.h b/common/inc/tx_event_flags.h new file mode 100644 index 0000000..51e9953 --- /dev/null +++ b/common/inc/tx_event_flags.h @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_event_flags.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX event flags management component, */ +/* including all data types and external references. It is assumed */ +/* that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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_EVENT_FLAGS_H +#define TX_EVENT_FLAGS_H + + +/* Define event flags control specific data definitions. */ + +#define TX_EVENT_FLAGS_ID ((ULONG) 0x4456444E) +#define TX_EVENT_FLAGS_AND_MASK ((UINT) 0x2) +#define TX_EVENT_FLAGS_CLEAR_MASK ((UINT) 0x1) + + +/* Determine if in-line component initialization is supported by the + caller. */ +#ifdef TX_INVOKE_INLINE_INITIALIZATION + +/* Yes, in-line initialization is supported, remap the event flag initialization + function. */ + +#ifndef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#define _tx_event_flags_initialize() \ + _tx_event_flags_created_ptr = TX_NULL; \ + _tx_event_flags_created_count = TX_EMPTY +#else +#define _tx_event_flags_initialize() \ + _tx_event_flags_created_ptr = TX_NULL; \ + _tx_event_flags_created_count = TX_EMPTY; \ + _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 +#define TX_EVENT_FLAGS_INIT +#else + +/* No in-line initialization is supported, use standard function call. */ +VOID _tx_event_flags_initialize(VOID); +#endif + + +/* Define internal event flags management function prototypes. */ + +VOID _tx_event_flags_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence); + + +/* Event flags management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_EVENT_FLAGS_INIT +#define EVENT_FLAGS_DECLARE +#else +#define EVENT_FLAGS_DECLARE extern +#endif + + +/* Define the head pointer of the created event flags list. */ + +EVENT_FLAGS_DECLARE TX_EVENT_FLAGS_GROUP * _tx_event_flags_created_ptr; + + +/* Define the variable that holds the number of created event flag groups. */ + +EVENT_FLAGS_DECLARE ULONG _tx_event_flags_created_count; + + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + +/* Define the total number of event flag sets. */ + +EVENT_FLAGS_DECLARE ULONG _tx_event_flags_performance_set_count; + + +/* Define the total number of event flag gets. */ + +EVENT_FLAGS_DECLARE ULONG _tx_event_flags_performance_get_count; + + +/* Define the total number of event flag suspensions. */ + +EVENT_FLAGS_DECLARE ULONG _tx_event_flags_performance_suspension_count; + + +/* Define the total number of event flag timeouts. */ + +EVENT_FLAGS_DECLARE ULONG _tx_event_flags_performance_timeout_count; + + +#endif + +/* Define default post event flag group delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_EVENT_FLAGS_GROUP_DELETE_PORT_COMPLETION +#define TX_EVENT_FLAGS_GROUP_DELETE_PORT_COMPLETION(g) +#endif + + +#endif + diff --git a/common/inc/tx_initialize.h b/common/inc/tx_initialize.h new file mode 100644 index 0000000..28c7251 --- /dev/null +++ b/common/inc/tx_initialize.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_initialize.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX initialization component, including */ +/* data types and external references. It is assumed that tx_api.h */ +/* and tx_port.h have already been included. */ +/* */ +/* 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_INITIALIZE_H +#define TX_INITIALIZE_H + + +/* Define constants that indicate initialization is in progress. */ + +#define TX_INITIALIZE_IN_PROGRESS ((ULONG) 0xF0F0F0F0UL) +#define TX_INITIALIZE_ALMOST_DONE ((ULONG) 0xF0F0F0F1UL) +#define TX_INITIALIZE_IS_FINISHED ((ULONG) 0x00000000UL) + + +/* Define internal initialization function prototypes. */ + +VOID _tx_initialize_high_level(VOID); +VOID _tx_initialize_kernel_setup(VOID); +VOID _tx_initialize_low_level(VOID); + + +/* Define the macro for adding additional port-specific global data. This macro is defined + as white space, unless defined by tx_port.h. */ + +#ifndef TX_PORT_SPECIFIC_DATA +#define TX_PORT_SPECIFIC_DATA +#endif + + +/* Define the macro for adding additional port-specific pre and post initialization processing. + These macros is defined as white space, unless defined by tx_port.h. */ + +#ifndef TX_PORT_SPECIFIC_PRE_INITIALIZATION +#define TX_PORT_SPECIFIC_PRE_INITIALIZATION +#endif + +#ifndef TX_PORT_SPECIFIC_POST_INITIALIZATION +#define TX_PORT_SPECIFIC_POST_INITIALIZATION +#endif + +#ifndef TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION +#endif + + +/* Initialization component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_INITIALIZE_INIT +#define INITIALIZE_DECLARE +#else +#define INITIALIZE_DECLARE extern +#endif + + +/* 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. */ + +INITIALIZE_DECLARE VOID *_tx_initialize_unused_memory; + + +#endif diff --git a/common/inc/tx_mutex.h b/common/inc/tx_mutex.h new file mode 100644 index 0000000..a3b5238 --- /dev/null +++ b/common/inc/tx_mutex.h @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_mutex.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX mutex management component, */ +/* including all data types and external references. It is assumed */ +/* that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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_MUTEX_H +#define TX_MUTEX_H + + +/* Define mutex control specific data definitions. */ + +#define TX_MUTEX_ID ((ULONG) 0x4D555445) + + +/* Determine if in-line component initialization is supported by the + caller. */ + +#ifdef TX_INVOKE_INLINE_INITIALIZATION + +/* Yes, in-line initialization is supported, remap the mutex initialization + function. */ + +#ifndef TX_MUTEX_ENABLE_PERFORMANCE_INFO +#define _tx_mutex_initialize() \ + _tx_mutex_created_ptr = TX_NULL; \ + _tx_mutex_created_count = TX_EMPTY +#else +#define _tx_mutex_initialize() \ + _tx_mutex_created_ptr = TX_NULL; \ + _tx_mutex_created_count = TX_EMPTY; \ + _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 +#define TX_MUTEX_INIT +#else + +/* No in-line initialization is supported, use standard function call. */ +VOID _tx_mutex_initialize(VOID); +#endif + + +/* Define internal mutex management function prototypes. */ + +VOID _tx_mutex_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence); +VOID _tx_mutex_thread_release(TX_THREAD *thread_ptr); +VOID _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT new_priority); + + +/* Mutex management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_MUTEX_INIT +#define MUTEX_DECLARE +#else +#define MUTEX_DECLARE extern +#endif + + +/* Define the head pointer of the created mutex list. */ + +MUTEX_DECLARE TX_MUTEX * _tx_mutex_created_ptr; + + +/* Define the variable that holds the number of created mutexes. */ + +MUTEX_DECLARE ULONG _tx_mutex_created_count; + + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + +/* Define the total number of mutex puts. */ + +MUTEX_DECLARE ULONG _tx_mutex_performance_put_count; + + +/* Define the total number of mutex gets. */ + +MUTEX_DECLARE ULONG _tx_mutex_performance_get_count; + + +/* Define the total number of mutex suspensions. */ + +MUTEX_DECLARE ULONG _tx_mutex_performance_suspension_count; + + +/* Define the total number of mutex timeouts. */ + +MUTEX_DECLARE ULONG _tx_mutex_performance_timeout_count; + + +/* Define the total number of priority inversions. */ + +MUTEX_DECLARE ULONG _tx_mutex_performance_priority_inversion_count; + + +/* Define the total number of priority inheritance conditions. */ + +MUTEX_DECLARE ULONG _tx_mutex_performance__priority_inheritance_count; + + +#endif + + +/* Define default post mutex delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_MUTEX_DELETE_PORT_COMPLETION +#define TX_MUTEX_DELETE_PORT_COMPLETION(m) +#endif + + +#endif diff --git a/common/inc/tx_queue.h b/common/inc/tx_queue.h new file mode 100644 index 0000000..7074a91 --- /dev/null +++ b/common/inc/tx_queue.h @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_queue.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX queue management component, */ +/* including all data types and external references. It is assumed */ +/* that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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_QUEUE_H +#define TX_QUEUE_H + + +/* Define queue control specific data definitions. */ + +#define TX_QUEUE_ID ((ULONG) 0x51554555) + + +/* Determine if in-line component initialization is supported by the + caller. */ +#ifdef TX_INVOKE_INLINE_INITIALIZATION + +/* Yes, in-line initialization is supported, remap the queue initialization + function. */ + +#ifndef TX_QUEUE_ENABLE_PERFORMANCE_INFO +#define _tx_queue_initialize() \ + _tx_queue_created_ptr = TX_NULL; \ + _tx_queue_created_count = TX_EMPTY +#else +#define _tx_queue_initialize() \ + _tx_queue_created_ptr = TX_NULL; \ + _tx_queue_created_count = TX_EMPTY; \ + _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 +#define TX_QUEUE_INIT +#else + +/* No in-line initialization is supported, use standard function call. */ +VOID _tx_queue_initialize(VOID); +#endif + + +/* Define the message copy macro. Note that the source and destination + pointers must be modified since they are used subsequently. */ + +#ifndef TX_QUEUE_MESSAGE_COPY +#define TX_QUEUE_MESSAGE_COPY(s, d, z) \ + *(d)++ = *(s)++; \ + if ((z) > ((UINT) 1)) \ + { \ + while (--(z)) \ + { \ + *(d)++ = *(s)++; \ + } \ + } +#endif + + +/* Define internal queue management function prototypes. */ + +VOID _tx_queue_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence); + + +/* Queue management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_QUEUE_INIT +#define QUEUE_DECLARE +#else +#define QUEUE_DECLARE extern +#endif + + +/* Define the head pointer of the created queue list. */ + +QUEUE_DECLARE TX_QUEUE * _tx_queue_created_ptr; + + +/* Define the variable that holds the number of created queues. */ + +QUEUE_DECLARE ULONG _tx_queue_created_count; + + +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO + +/* Define the total number of messages sent. */ + +QUEUE_DECLARE ULONG _tx_queue_performance_messages_sent_count; + + +/* Define the total number of messages received. */ + +QUEUE_DECLARE ULONG _tx_queue_performance__messages_received_count; + + +/* Define the total number of queue empty suspensions. */ + +QUEUE_DECLARE ULONG _tx_queue_performance_empty_suspension_count; + + +/* Define the total number of queue full suspensions. */ + +QUEUE_DECLARE ULONG _tx_queue_performance_full_suspension_count; + + +/* Define the total number of queue full errors. */ + +QUEUE_DECLARE ULONG _tx_queue_performance_full_error_count; + + +/* Define the total number of queue timeouts. */ + +QUEUE_DECLARE ULONG _tx_queue_performance_timeout_count; + + +#endif + + +/* Define default post queue delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_QUEUE_DELETE_PORT_COMPLETION +#define TX_QUEUE_DELETE_PORT_COMPLETION(q) +#endif + + +#endif + diff --git a/common/inc/tx_semaphore.h b/common/inc/tx_semaphore.h new file mode 100644 index 0000000..6784e58 --- /dev/null +++ b/common/inc/tx_semaphore.h @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_semaphore.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX semaphore management component, */ +/* including all data types and external references. It is assumed */ +/* that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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_SEMAPHORE_H +#define TX_SEMAPHORE_H + + +/* Define semaphore control specific data definitions. */ + +#define TX_SEMAPHORE_ID ((ULONG) 0x53454D41) + + +/* Determine if in-line component initialization is supported by the + caller. */ +#ifdef TX_INVOKE_INLINE_INITIALIZATION + /* Yes, in-line initialization is supported, remap the + semaphore initialization function. */ +#ifndef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#define _tx_semaphore_initialize() \ + _tx_semaphore_created_ptr = TX_NULL; \ + _tx_semaphore_created_count = TX_EMPTY +#else +#define _tx_semaphore_initialize() \ + _tx_semaphore_created_ptr = TX_NULL; \ + _tx_semaphore_created_count = TX_EMPTY; \ + _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 +#define TX_SEMAPHORE_INIT +#else + /* No in-line initialization is supported, use standard + function call. */ +VOID _tx_semaphore_initialize(VOID); +#endif + + +/* Define internal semaphore management function prototypes. */ + +VOID _tx_semaphore_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence); + + +/* Semaphore management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_SEMAPHORE_INIT +#define SEMAPHORE_DECLARE +#else +#define SEMAPHORE_DECLARE extern +#endif + + +/* Define the head pointer of the created semaphore list. */ + +SEMAPHORE_DECLARE TX_SEMAPHORE * _tx_semaphore_created_ptr; + + +/* Define the variable that holds the number of created semaphores. */ + +SEMAPHORE_DECLARE ULONG _tx_semaphore_created_count; + + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + +/* Define the total number of semaphore puts. */ + +SEMAPHORE_DECLARE ULONG _tx_semaphore_performance_put_count; + + +/* Define the total number of semaphore gets. */ + +SEMAPHORE_DECLARE ULONG _tx_semaphore_performance_get_count; + + +/* Define the total number of semaphore suspensions. */ + +SEMAPHORE_DECLARE ULONG _tx_semaphore_performance_suspension_count; + + +/* Define the total number of semaphore timeouts. */ + +SEMAPHORE_DECLARE ULONG _tx_semaphore_performance_timeout_count; + + +#endif + + +/* Define default post semaphore delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_SEMAPHORE_DELETE_PORT_COMPLETION +#define TX_SEMAPHORE_DELETE_PORT_COMPLETION(s) +#endif + + +#endif + diff --git a/common/inc/tx_thread.h b/common/inc/tx_thread.h new file mode 100644 index 0000000..6500d40 --- /dev/null +++ b/common/inc/tx_thread.h @@ -0,0 +1,533 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_thread.h PORTABLE C */ +/* 6.1.9 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX thread control component, including */ +/* data types and external references. It is assumed that tx_api.h */ +/* and tx_port.h have already been included. */ +/* */ +/* 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 */ +/* 11-09-2020 Yuxin Zhou Modified comment(s), and */ +/* moved TX_THREAD_GET_SYSTEM_ */ +/* STATE to tx_api.h, */ +/* resulting in version 6.1.2 */ +/* 10-15-2021 Scott Larson Modified comment(s), improved */ +/* stack check error handling, */ +/* resulting in version 6.1.9 */ +/* */ +/**************************************************************************/ + +#ifndef TX_THREAD_H +#define TX_THREAD_H + + +/* Define thread control specific data definitions. */ + +#define TX_THREAD_ID ((ULONG) 0x54485244) +#define TX_THREAD_PRIORITY_GROUP_MASK ((ULONG) 0xFF) +#define TX_THREAD_EXECUTE_LOG_SIZE ((UINT) 8) + + +/* Define the MOD32 bit set macro that is used to set/clear a priority bit within a specific + priority group. */ + +#if TX_MAX_PRIORITIES > 32 +#define MAP_INDEX (map_index) +#ifndef TX_MOD32_BIT_SET +#define TX_MOD32_BIT_SET(a,b) (b) = (((ULONG) 1) << ((a)%((UINT)32))); +#endif +#else +#define MAP_INDEX (0) +#ifndef TX_MOD32_BIT_SET +#define TX_MOD32_BIT_SET(a,b) (b) = (((ULONG) 1) << ((a))); +#endif +#endif + + +/* Define the DIV32 bit set macro that is used to set/clear a priority group bit and is + only necessary when using priorities greater than 32. */ + +#if TX_MAX_PRIORITIES > 32 +#ifndef TX_DIV32_BIT_SET +#define TX_DIV32_BIT_SET(a,b) (b) = (((ULONG) 1) << ((a)/((UINT) 32))); +#endif +#endif + + +/* Define state change macro that can be used by run-mode debug agents to keep track of thread + state changes. By default, it is mapped to white space. */ + +#ifndef TX_THREAD_STATE_CHANGE +#define TX_THREAD_STATE_CHANGE(a, b) +#endif + + +/* Define the macro to get the current thread pointer. This is particularly useful in SMP + versions of ThreadX to add additional processing. The default implementation is to simply + access the global current thread pointer directly. */ + +#ifndef TX_THREAD_GET_CURRENT +#define TX_THREAD_GET_CURRENT(a) (a) = _tx_thread_current_ptr; +#endif + + +/* Define the macro to set the current thread pointer. This is particularly useful in SMP + versions of ThreadX to add additional processing. The default implementation is to simply + access the global current thread pointer directly. */ + +#ifndef TX_THREAD_SET_CURRENT +#define TX_THREAD_SET_CURRENT(a) _tx_thread_current_ptr = (a); +#endif + + + +/* Define the get system state macro. By default, it simply maps to the variable _tx_thread_system_state. */ +/* This symbol is moved to tx_api.h. Therefore removed from this file. +#ifndef TX_THREAD_GET_SYSTEM_STATE +#define TX_THREAD_GET_SYSTEM_STATE() _tx_thread_system_state +#endif +*/ + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = (ULONG) _tx_thread_preempt_disable; (c) = (c) | TX_THREAD_GET_SYSTEM_STATE(); +#endif + + +/* Define the timeout setup macro used in _tx_thread_create. */ + +#ifndef TX_THREAD_CREATE_TIMEOUT_SETUP +#define TX_THREAD_CREATE_TIMEOUT_SETUP(t) (t) -> tx_thread_timer.tx_timer_internal_timeout_function = &(_tx_thread_timeout); \ + (t) -> tx_thread_timer.tx_timer_internal_timeout_param = TX_POINTER_TO_ULONG_CONVERT((t)); +#endif + + +/* Define the thread timeout pointer setup macro used in _tx_thread_timeout. */ + +#ifndef TX_THREAD_TIMEOUT_POINTER_SETUP +#define TX_THREAD_TIMEOUT_POINTER_SETUP(t) (t) = TX_ULONG_TO_THREAD_POINTER_CONVERT(timeout_input); +#endif + + +/* Define the lowest bit set macro. Note, that this may be overridden + by a port specific definition if there is supporting assembly language + instructions in the architecture. */ + +#ifndef TX_LOWEST_SET_BIT_CALCULATE +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) \ + (b) = ((ULONG) 0); \ + (m) = (m) & ((~(m)) + ((ULONG) 1)); \ + if ((m) < ((ULONG) 0x10)) \ + { \ + if ((m) >= ((ULONG) 4)) \ + { \ + (m) = (m) >> ((ULONG) 2); \ + (b) = (b) + ((ULONG) 2); \ + } \ + (b) = (b) + ((m) >> ((ULONG) 1)); \ + } \ + else if ((m) < ((ULONG) 0x100)) \ + { \ + (m) = (m) >> ((ULONG) 4); \ + (b) = (b) + ((ULONG) 4); \ + if ((m) >= ((ULONG) 4)) \ + { \ + (m) = (m) >> ((ULONG) 2); \ + (b) = (b) + ((ULONG) 2); \ + } \ + (b) = (b) + ((m) >> ((ULONG) 1)); \ + } \ + else if ((m) < ((ULONG) 0x10000)) \ + { \ + (m) = (m) >> ((ULONG) 8); \ + (b) = (b) + ((ULONG) 8); \ + if ((m) >= ((ULONG) 0x10)) \ + { \ + (m) = (m) >> ((ULONG) 4); \ + (b) = (b) + ((ULONG) 4); \ + } \ + if ((m) >= ((ULONG) 4)) \ + { \ + (m) = (m) >> ((ULONG) 2); \ + (b) = (b) + ((ULONG) 2); \ + } \ + (b) = (b) + ((m) >> ((ULONG) 1)); \ + } \ + else \ + { \ + (m) = (m) >> ((ULONG) 16); \ + (b) = (b) + ((ULONG) 16); \ + if ((m) >= ((ULONG) 0x100)) \ + { \ + (m) = (m) >> ((ULONG) 8); \ + (b) = (b) + ((ULONG) 8); \ + } \ + if ((m) >= ((ULONG) 16)) \ + { \ + (m) = (m) >> ((ULONG) 4); \ + (b) = (b) + ((ULONG) 4); \ + } \ + if ((m) >= ((ULONG) 4)) \ + { \ + (m) = (m) >> ((ULONG) 2); \ + (b) = (b) + ((ULONG) 2); \ + } \ + (b) = (b) + ((m) >> ((ULONG) 1)); \ + } +#endif + + +/* Define the default thread stack checking. This can be overridden by + a particular port, which is necessary if the stack growth is from + low address to high address (the default logic is for stacks that + grow from high address to low address. */ + +#ifndef TX_THREAD_STACK_CHECK +#define TX_THREAD_STACK_CHECK(thread_ptr) \ + { \ + TX_INTERRUPT_SAVE_AREA \ + TX_DISABLE \ + if (((thread_ptr)) && ((thread_ptr) -> tx_thread_id == TX_THREAD_ID)) \ + { \ + if (((ULONG *) (thread_ptr) -> tx_thread_stack_ptr) < ((ULONG *) (thread_ptr) -> tx_thread_stack_highest_ptr)) \ + { \ + (thread_ptr) -> tx_thread_stack_highest_ptr = (thread_ptr) -> tx_thread_stack_ptr; \ + } \ + if ((*((ULONG *) (thread_ptr) -> tx_thread_stack_start) != TX_STACK_FILL) || \ + (*((ULONG *) (((UCHAR *) (thread_ptr) -> tx_thread_stack_end) + 1)) != TX_STACK_FILL) || \ + (((ULONG *) (thread_ptr) -> tx_thread_stack_highest_ptr) < ((ULONG *) (thread_ptr) -> tx_thread_stack_start))) \ + { \ + TX_RESTORE \ + _tx_thread_stack_error_handler((thread_ptr)); \ + TX_DISABLE \ + } \ + if (*(((ULONG *) (thread_ptr) -> tx_thread_stack_highest_ptr) - 1) != TX_STACK_FILL) \ + { \ + TX_RESTORE \ + _tx_thread_stack_analyze((thread_ptr)); \ + TX_DISABLE \ + } \ + } \ + TX_RESTORE \ + } +#endif + + +/* Define default post thread delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_THREAD_DELETE_PORT_COMPLETION +#define TX_THREAD_DELETE_PORT_COMPLETION(t) +#endif + + +/* Define default post thread reset macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_THREAD_RESET_PORT_COMPLETION +#define TX_THREAD_RESET_PORT_COMPLETION(t) +#endif + + +/* Define the thread create internal extension macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_THREAD_CREATE_INTERNAL_EXTENSION +#define TX_THREAD_CREATE_INTERNAL_EXTENSION(t) +#endif + + +/* Define internal thread control function prototypes. */ + +VOID _tx_thread_initialize(VOID); +VOID _tx_thread_schedule(VOID); +VOID _tx_thread_shell_entry(VOID); +VOID _tx_thread_stack_analyze(TX_THREAD *thread_ptr); +VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)); +VOID _tx_thread_stack_error(TX_THREAD *thread_ptr); +VOID _tx_thread_stack_error_handler(TX_THREAD *thread_ptr); +VOID _tx_thread_system_preempt_check(VOID); +VOID _tx_thread_system_resume(TX_THREAD *thread_ptr); +VOID _tx_thread_system_ni_resume(TX_THREAD *thread_ptr); +VOID _tx_thread_system_return(VOID); +VOID _tx_thread_system_suspend(TX_THREAD *thread_ptr); +VOID _tx_thread_system_ni_suspend(TX_THREAD *thread_ptr, ULONG wait_option); +VOID _tx_thread_time_slice(VOID); +VOID _tx_thread_timeout(ULONG timeout_input); + + +/* Thread control component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#define THREAD_DECLARE extern + + +/* 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE TX_THREAD * _tx_thread_execute_ptr; + + +/* Define the head pointer of the created thread list. */ + +THREAD_DECLARE TX_THREAD * _tx_thread_created_ptr; + + +/* Define the variable that holds the number of created threads. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE volatile ULONG _tx_thread_system_state; + + +/* 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. */ + +THREAD_DECLARE 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 +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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 +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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 */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE ULONG _tx_thread_performance_relinquish_count; + + +/* Define the total number of thread timeouts. Each time a thread has a + timeout this variable is incremented. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE 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. */ + +THREAD_DECLARE ULONG _tx_thread_performance__execute_log_index; +THREAD_DECLARE TX_THREAD * _tx_thread_performance_execute_log[TX_THREAD_EXECUTE_LOG_SIZE]; + +#endif + +#endif + diff --git a/common/inc/tx_timer.h b/common/inc/tx_timer.h new file mode 100644 index 0000000..4703b14 --- /dev/null +++ b/common/inc/tx_timer.h @@ -0,0 +1,214 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_timer.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX timer management component, including */ +/* data types and external references. It is assumed that tx_api.h */ +/* and tx_port.h have already been included. */ +/* */ +/* 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_H +#define TX_TIMER_H + + +/* Define timer management specific data definitions. */ + +#define TX_TIMER_ID ((ULONG) 0x4154494D) +#define TX_TIMER_ENTRIES ((ULONG) 32) + + +/* Define internal timer management function prototypes. */ + +VOID _tx_timer_expiration_process(VOID); +VOID _tx_timer_initialize(VOID); +VOID _tx_timer_system_activate(TX_TIMER_INTERNAL *timer_ptr); +VOID _tx_timer_system_deactivate(TX_TIMER_INTERNAL *timer_ptr); +VOID _tx_timer_thread_entry(ULONG timer_thread_input); + + +/* Timer management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_TIMER_INIT +#define TIMER_DECLARE +#else +#define TIMER_DECLARE extern +#endif + + +/* Define the system clock value that is continually incremented by the + periodic timer interrupt processing. */ + +TIMER_DECLARE volatile ULONG _tx_timer_system_clock; + + +/* Define the current time slice value. If non-zero, a time-slice is active. + Otherwise, the time_slice is not active. */ + +TIMER_DECLARE ULONG _tx_timer_time_slice; + + +/* Define the time-slice expiration flag. This is used to indicate that a time-slice + has happened. */ + +TIMER_DECLARE 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. */ + +TIMER_DECLARE 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. */ + +TIMER_DECLARE TX_TIMER_INTERNAL **_tx_timer_list_start; +TIMER_DECLARE 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. */ + +TIMER_DECLARE TX_TIMER_INTERNAL **_tx_timer_current_ptr; + + +/* Define the timer expiration flag. This is used to indicate that a timer + has expired. */ + +TIMER_DECLARE UINT _tx_timer_expired; + + +/* Define the created timer list head pointer. */ + +TIMER_DECLARE TX_TIMER *_tx_timer_created_ptr; + + +/* Define the created timer count. */ + +TIMER_DECLARE ULONG _tx_timer_created_count; + + +/* Define the pointer to the timer that has expired and is being processed. */ + +TIMER_DECLARE TX_TIMER_INTERNAL *_tx_timer_expired_timer_ptr; + + +#ifndef TX_TIMER_PROCESS_IN_ISR + +/* Define the timer thread's control block. */ + +TIMER_DECLARE TX_THREAD _tx_timer_thread; + + +/* Define the variable that holds the timer thread's starting stack address. */ + +TIMER_DECLARE VOID *_tx_timer_stack_start; + + +/* Define the variable that holds the timer thread's stack size. */ + +TIMER_DECLARE ULONG _tx_timer_stack_size; + + +/* Define the variable that holds the timer thread's priority. */ + +TIMER_DECLARE UINT _tx_timer_priority; + +/* Define the system timer thread's stack. The default size is defined + in tx_port.h. */ + +TIMER_DECLARE 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. */ + +TIMER_DECLARE UINT _tx_timer_processing_active; + +#endif + +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO + +/* Define the total number of timer activations. */ + +TIMER_DECLARE ULONG _tx_timer_performance_activate_count; + + +/* Define the total number of timer reactivations. */ + +TIMER_DECLARE ULONG _tx_timer_performance_reactivate_count; + + +/* Define the total number of timer deactivations. */ + +TIMER_DECLARE ULONG _tx_timer_performance_deactivate_count; + + +/* Define the total number of timer expirations. */ + +TIMER_DECLARE 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. */ + +TIMER_DECLARE ULONG _tx_timer_performance__expiration_adjust_count; + + +#endif + + +/* Define default post timer delete macro to whitespace, if it hasn't been defined previously (typically in tx_port.h). */ + +#ifndef TX_TIMER_DELETE_PORT_COMPLETION +#define TX_TIMER_DELETE_PORT_COMPLETION(t) +#endif + + +#endif diff --git a/common/inc/tx_trace.h b/common/inc/tx_trace.h new file mode 100644 index 0000000..dd78580 --- /dev/null +++ b/common/inc/tx_trace.h @@ -0,0 +1,560 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_trace.h PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX trace component, including constants */ +/* and structure definitions as well as external references. It is */ +/* assumed that tx_api.h and tx_port.h have already been included. */ +/* */ +/* 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 */ +/* */ +/**************************************************************************/ + + +/* Include necessary system files. */ + +#ifndef TX_TRACE_H +#define TX_TRACE_H + + +/* Determine if tracing is enabled. If not, simply define the in-line trace + macros to whitespace. */ + +#ifndef TX_ENABLE_EVENT_TRACE +#define TX_TRACE_INITIALIZE +#define TX_TRACE_OBJECT_REGISTER(t,p,n,a,b) +#define TX_TRACE_OBJECT_UNREGISTER(o) +#define TX_TRACE_IN_LINE_INSERT(i,a,b,c,d,f) +#else + +/* Event tracing is enabled. */ + +/* Ensure that the thread component information is included. */ + +#include "tx_thread.h" + + +/* Define trace port-specfic extension to white space if it isn't defined + already. */ + +#ifndef TX_TRACE_PORT_EXTENSION +#define TX_TRACE_PORT_EXTENSION +#endif + + +/* Define the default clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE ++_tx_trace_simulated_time +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* Define the ID showing the event trace buffer is valid. */ + +#define TX_TRACE_VALID 0x54585442UL + + +/* ThreadX Trace Description. The ThreadX Trace feature is designed to capture + events in real-time in a circular event buffer. This buffer may be analyzed by other + tools. The high-level format of the Trace structure is: + + [Trace Control Header ] + [Trace Object Registry - Entry 0 ] + ... + [Trace Object Registry - Entry "n" ] + [Trace Buffer - Entry 0 ] + ... + [Trace Buffer - Entry "n" ] + +*/ + + +/* Trace Control Header. The Trace Control Header contains information that + defines the format of the Trace Object Registry as well as the location and + current entry of the Trace Buffer itself. The high-level format of the + Trace Control Header is: + + Entry Size Description + + [Trace ID] 4 This 4-byte field contains the ThreadX Trace + Identification. If the trace buffer is valid, the + contents are 0x54585442 (TXTB). Since it is written as + a 32-bit unsigned word, this value is also used to + determine if the event trace information is in + little or big endian format. + [Timer Valid Mask] 4 Mask of valid bits in the 32-bit time stamp. This + enables use of 32, 24, 16, or event 8-bit timers. + If the time source is 32-bits, the mask is + 0xFFFFFFFF. If the time source is 16-bits, the + mask is 0x0000FFFF. + [Trace Base Address] 4 The base address for all trace pointer. Subtracting + the pointer and this address will yield the proper + offset into the trace buffer. + [Trace Object Registry Start Pointer] 4 Pointer to the start of Trace Object Registry + [Reserved] 2 Reserved two bytes - should be 0x0000 + [Trace Object Object Name Size] 2 Number of bytes in object name + [Trace Object Registry End Pointer] 4 Pointer to the end of Trace Object Registry + [Trace Buffer Start Pointer] 4 Pointer to the start of the Trace Buffer Area + [Trace Buffer End Pointer] 4 Pointer to the end of the Trace Buffer Area + [Trace Buffer Current Pointer] 4 Pointer to the oldest entry in the Trace Buffer. + This entry will be overwritten on the next event and + incremented to the next event (wrapping to the top + if the buffer end pointer is exceeded). + [Reserved] 4 Reserved 4 bytes, should be 0xAAAAAAAA + [Reserved] 4 Reserved 4 bytes, should be 0xBBBBBBBB + [Reserved] 4 Reserved 4 bytes, should be 0xCCCCCCCC +*/ + + +/* Define the Trace Control Header. */ + +typedef struct TX_TRACE_HEADER_STRUCT +{ + + ULONG tx_trace_header_id; + ULONG tx_trace_header_timer_valid_mask; + ULONG tx_trace_header_trace_base_address; + ULONG tx_trace_header_registry_start_pointer; + USHORT tx_trace_header_reserved1; + USHORT tx_trace_header_object_name_size; + ULONG tx_trace_header_registry_end_pointer; + ULONG tx_trace_header_buffer_start_pointer; + ULONG tx_trace_header_buffer_end_pointer; + ULONG tx_trace_header_buffer_current_pointer; + ULONG tx_trace_header_reserved2; + ULONG tx_trace_header_reserved3; + ULONG tx_trace_header_reserved4; +} TX_TRACE_HEADER; + + +/* Trace Object Registry. The Trace Object Registry is used to map the object pointer in the trace buffer to + the application's name for the object (defined during object creation in ThreadX). */ + +#ifndef TX_TRACE_OBJECT_REGISTRY_NAME +#define TX_TRACE_OBJECT_REGISTRY_NAME 32 +#endif + + +/* Define the object name types as well as the contents of any additional parameters that might be useful in + trace analysis. */ + +#define TX_TRACE_OBJECT_TYPE_NOT_VALID ((UCHAR) 0) /* Object is not valid */ +#define TX_TRACE_OBJECT_TYPE_THREAD ((UCHAR) 1) /* P1 = stack start address, P2 = stack size */ +#define TX_TRACE_OBJECT_TYPE_TIMER ((UCHAR) 2) /* P1 = initial ticks, P2 = reschedule ticks */ +#define TX_TRACE_OBJECT_TYPE_QUEUE ((UCHAR) 3) /* P1 = queue size, P2 = message size */ +#define TX_TRACE_OBJECT_TYPE_SEMAPHORE ((UCHAR) 4) /* P1 = initial instances */ +#define TX_TRACE_OBJECT_TYPE_MUTEX ((UCHAR) 5) /* P1 = priority inheritance flag */ +#define TX_TRACE_OBJECT_TYPE_EVENT_FLAGS ((UCHAR) 6) /* none */ +#define TX_TRACE_OBJECT_TYPE_BLOCK_POOL ((UCHAR) 7) /* P1 = total blocks, P2 = block size */ +#define TX_TRACE_OBJECT_TYPE_BYTE_POOL ((UCHAR) 8) /* P1 = total bytes */ + + +typedef struct TX_TRACE_OBJECT_ENTRY_STRUCT +{ + + UCHAR tx_trace_object_entry_available; /* TX_TRUE -> available */ + UCHAR tx_trace_object_entry_type; /* Types defined above */ + UCHAR tx_trace_object_entry_reserved1; /* Should be zero - except for thread */ + UCHAR tx_trace_object_entry_reserved2; /* Should be zero - except for thread */ + ULONG tx_trace_object_entry_thread_pointer; /* ThreadX object pointer */ + ULONG tx_trace_object_entry_param_1; /* Parameter value defined */ + ULONG tx_trace_object_entry_param_2; /* according to type above */ + UCHAR tx_trace_object_entry_name[TX_TRACE_OBJECT_REGISTRY_NAME]; /* Object name */ +} TX_TRACE_OBJECT_ENTRY; + + +/* Trace Buffer Entry. The Trace Buffer Entry contains information about a particular + event in the system. The high-level format of the Trace Buffer Entry is: + + Entry Size Description + + [Thread Pointer] 4 This 4-byte field contains the pointer to the + ThreadX thread running that caused the event. + If this field is NULL, the entry hasn't been used + yet. If this field is 0xFFFFFFFF, the event occurred + from within an ISR. If this entry is 0xF0F0F0F0, the + event occurred during initialization. + [Thread Priority or 4 This 4-byte field contains the current thread pointer for interrupt + Current Thread events or the thread preemption-threshold/priority for thread events. + Preemption-Threshold/ + Priority] + [Event ID] 4 This 4-byte field contains the Event ID of the event. A value of + 0xFFFFFFFF indicates the event is invalid. All events are marked + as invalid during initialization. + [Time Stamp] 4 This 4-byte field contains the time stamp of the event. + [Information Field 1] 4 This 4-byte field contains the first 4-bytes of information + specific to the event. + [Information Field 2] 4 This 4-byte field contains the second 4-bytes of information + specific to the event. + [Information Field 3] 4 This 4-byte field contains the third 4-bytes of information + specific to the event. + [Information Field 4] 4 This 4-byte field contains the fourth 4-bytes of information + specific to the event. +*/ + +#define TX_TRACE_INVALID_EVENT 0xFFFFFFFFUL + + +/* Define ThreadX Trace Events, along with a brief description of the additional information fields, + where I1 -> Information Field 1, I2 -> Information Field 2, etc. */ + +/* Event numbers 0 through 4095 are reserved by Azure RTOS. Specific event assignments are: + + ThreadX events: 1-199 + FileX events: 200-299 + NetX events: 300-599 + USBX events: 600-999 + + User-defined event numbers start at 4096 and continue through 65535, as defined by the constants + TX_TRACE_USER_EVENT_START and TX_TRACE_USER_EVENT_END, respectively. User events should be based + on these constants in case the user event number assignment is changed in future releases. */ + +/* Define the basic ThreadX thread scheduling events first. */ + +#define TX_TRACE_THREAD_RESUME 1 /* I1 = thread ptr, I2 = previous_state, I3 = stack ptr, I4 = next thread */ +#define TX_TRACE_THREAD_SUSPEND 2 /* I1 = thread ptr, I2 = new_state, I3 = stack ptr I4 = next thread */ +#define TX_TRACE_ISR_ENTER 3 /* I1 = stack_ptr, I2 = ISR number, I3 = system state, I4 = preempt disable */ +#define TX_TRACE_ISR_EXIT 4 /* I1 = stack_ptr, I2 = ISR number, I3 = system state, I4 = preempt disable */ +#define TX_TRACE_TIME_SLICE 5 /* I1 = next thread ptr, I2 = system state, I3 = preempt disable, I4 = stack*/ +#define TX_TRACE_RUNNING 6 /* None */ + + +/* Define the rest of the ThreadX system events. */ + +#define TX_TRACE_BLOCK_ALLOCATE 10 /* I1 = pool ptr, I2 = memory ptr, I3 = wait option, I4 = remaining blocks */ +#define TX_TRACE_BLOCK_POOL_CREATE 11 /* I1 = pool ptr, I2 = pool_start, I3 = total blocks, I4 = block size */ +#define TX_TRACE_BLOCK_POOL_DELETE 12 /* I1 = pool ptr, I2 = stack ptr */ +#define TX_TRACE_BLOCK_POOL_INFO_GET 13 /* I1 = pool ptr */ +#define TX_TRACE_BLOCK_POOL_PERFORMANCE_INFO_GET 14 /* I1 = pool ptr */ +#define TX_TRACE_BLOCK_POOL__PERFORMANCE_SYSTEM_INFO_GET 15 /* None */ +#define TX_TRACE_BLOCK_POOL_PRIORITIZE 16 /* I1 = pool ptr, I2 = suspended count, I3 = stack ptr */ +#define TX_TRACE_BLOCK_RELEASE 17 /* I1 = pool ptr, I2 = memory ptr, I3 = suspended, I4 = stack ptr */ +#define TX_TRACE_BYTE_ALLOCATE 20 /* I1 = pool ptr, I2 = memory ptr, I3 = size requested, I4 = wait option */ +#define TX_TRACE_BYTE_POOL_CREATE 21 /* I1 = pool ptr, I2 = start ptr, I3 = pool size, I4 = stack ptr */ +#define TX_TRACE_BYTE_POOL_DELETE 22 /* I1 = pool ptr, I2 = stack ptr */ +#define TX_TRACE_BYTE_POOL_INFO_GET 23 /* I1 = pool ptr */ +#define TX_TRACE_BYTE_POOL_PERFORMANCE_INFO_GET 24 /* I1 = pool ptr */ +#define TX_TRACE_BYTE_POOL__PERFORMANCE_SYSTEM_INFO_GET 25 /* None */ +#define TX_TRACE_BYTE_POOL_PRIORITIZE 26 /* I1 = pool ptr, I2 = suspended count, I3 = stack ptr */ +#define TX_TRACE_BYTE_RELEASE 27 /* I1 = pool ptr, I2 = memory ptr, I3 = suspended, I4 = available bytes */ +#define TX_TRACE_EVENT_FLAGS_CREATE 30 /* I1 = group ptr, I2 = stack ptr */ +#define TX_TRACE_EVENT_FLAGS_DELETE 31 /* I1 = group ptr, I2 = stack ptr */ +#define TX_TRACE_EVENT_FLAGS_GET 32 /* I1 = group ptr, I2 = requested flags, I3 = current flags, I4 = get option*/ +#define TX_TRACE_EVENT_FLAGS_INFO_GET 33 /* I1 = group ptr */ +#define TX_TRACE_EVENT_FLAGS_PERFORMANCE_INFO_GET 34 /* I1 = group ptr */ +#define TX_TRACE_EVENT_FLAGS__PERFORMANCE_SYSTEM_INFO_GET 35 /* None */ +#define TX_TRACE_EVENT_FLAGS_SET 36 /* I1 = group ptr, I2 = flags to set, I3 = set option, I4= suspended count */ +#define TX_TRACE_EVENT_FLAGS_SET_NOTIFY 37 /* I1 = group ptr */ +#define TX_TRACE_INTERRUPT_CONTROL 40 /* I1 = new interrupt posture, I2 = stack ptr */ +#define TX_TRACE_MUTEX_CREATE 50 /* I1 = mutex ptr, I2 = inheritance, I3 = stack ptr */ +#define TX_TRACE_MUTEX_DELETE 51 /* I1 = mutex ptr, I2 = stack ptr */ +#define TX_TRACE_MUTEX_GET 52 /* I1 = mutex ptr, I2 = wait option, I3 = owning thread, I4 = own count */ +#define TX_TRACE_MUTEX_INFO_GET 53 /* I1 = mutex ptr */ +#define TX_TRACE_MUTEX_PERFORMANCE_INFO_GET 54 /* I1 = mutex ptr */ +#define TX_TRACE_MUTEX_PERFORMANCE_SYSTEM_INFO_GET 55 /* None */ +#define TX_TRACE_MUTEX_PRIORITIZE 56 /* I1 = mutex ptr, I2 = suspended count, I3 = stack ptr */ +#define TX_TRACE_MUTEX_PUT 57 /* I1 = mutex ptr, I2 = owning thread, I3 = own count, I4 = stack ptr */ +#define TX_TRACE_QUEUE_CREATE 60 /* I1 = queue ptr, I2 = message size, I3 = queue start, I4 = queue size */ +#define TX_TRACE_QUEUE_DELETE 61 /* I1 = queue ptr, I2 = stack ptr */ +#define TX_TRACE_QUEUE_FLUSH 62 /* I1 = queue ptr, I2 = stack ptr */ +#define TX_TRACE_QUEUE_FRONT_SEND 63 /* I1 = queue ptr, I2 = source ptr, I3 = wait option, I4 = enqueued */ +#define TX_TRACE_QUEUE_INFO_GET 64 /* I1 = queue ptr */ +#define TX_TRACE_QUEUE_PERFORMANCE_INFO_GET 65 /* I1 = queue ptr */ +#define TX_TRACE_QUEUE_PERFORMANCE_SYSTEM_INFO_GET 66 /* None */ +#define TX_TRACE_QUEUE_PRIORITIZE 67 /* I1 = queue ptr, I2 = suspended count, I3 = stack ptr */ +#define TX_TRACE_QUEUE_RECEIVE 68 /* I1 = queue ptr, I2 = destination ptr, I3 = wait option, I4 = enqueued */ +#define TX_TRACE_QUEUE_SEND 69 /* I1 = queue ptr, I2 = source ptr, I3 = wait option, I4 = enqueued */ +#define TX_TRACE_QUEUE_SEND_NOTIFY 70 /* I1 = queue ptr */ +#define TX_TRACE_SEMAPHORE_CEILING_PUT 80 /* I1 = semaphore ptr, I2 = current count, I3 = suspended count,I4 =ceiling */ +#define TX_TRACE_SEMAPHORE_CREATE 81 /* I1 = semaphore ptr, I2 = initial count, I3 = stack ptr */ +#define TX_TRACE_SEMAPHORE_DELETE 82 /* I1 = semaphore ptr, I2 = stack ptr */ +#define TX_TRACE_SEMAPHORE_GET 83 /* I1 = semaphore ptr, I2 = wait option, I3 = current count, I4 = stack ptr */ +#define TX_TRACE_SEMAPHORE_INFO_GET 84 /* I1 = semaphore ptr */ +#define TX_TRACE_SEMAPHORE_PERFORMANCE_INFO_GET 85 /* I1 = semaphore ptr */ +#define TX_TRACE_SEMAPHORE__PERFORMANCE_SYSTEM_INFO_GET 86 /* None */ +#define TX_TRACE_SEMAPHORE_PRIORITIZE 87 /* I1 = semaphore ptr, I2 = suspended count, I2 = stack ptr */ +#define TX_TRACE_SEMAPHORE_PUT 88 /* I1 = semaphore ptr, I2 = current count, I3 = suspended count,I4=stack ptr*/ +#define TX_TRACE_SEMAPHORE_PUT_NOTIFY 89 /* I1 = semaphore ptr */ +#define TX_TRACE_THREAD_CREATE 100 /* I1 = thread ptr, I2 = priority, I3 = stack ptr, I4 = stack_size */ +#define TX_TRACE_THREAD_DELETE 101 /* I1 = thread ptr, I2 = stack ptr */ +#define TX_TRACE_THREAD_ENTRY_EXIT_NOTIFY 102 /* I1 = thread ptr, I2 = thread state, I3 = stack ptr */ +#define TX_TRACE_THREAD_IDENTIFY 103 /* None */ +#define TX_TRACE_THREAD_INFO_GET 104 /* I1 = thread ptr, I2 = thread state */ +#define TX_TRACE_THREAD_PERFORMANCE_INFO_GET 105 /* I1 = thread ptr, I2 = thread state */ +#define TX_TRACE_THREAD_PERFORMANCE_SYSTEM_INFO_GET 106 /* None */ +#define TX_TRACE_THREAD_PREEMPTION_CHANGE 107 /* I1 = thread ptr, I2 = new threshold, I3 = old threshold, I4 =thread state*/ +#define TX_TRACE_THREAD_PRIORITY_CHANGE 108 /* I1 = thread ptr, I2 = new priority, I3 = old priority, I4 = thread state */ +#define TX_TRACE_THREAD_RELINQUISH 109 /* I1 = stack ptr, I2 = next thread ptr */ +#define TX_TRACE_THREAD_RESET 110 /* I1 = thread ptr, I2 = thread state */ +#define TX_TRACE_THREAD_RESUME_API 111 /* I1 = thread ptr, I2 = thread state, I3 = stack ptr */ +#define TX_TRACE_THREAD_SLEEP 112 /* I1 = sleep value, I2 = thread state, I3 = stack ptr */ +#define TX_TRACE_THREAD_STACK_ERROR_NOTIFY 113 /* None */ +#define TX_TRACE_THREAD_SUSPEND_API 114 /* I1 = thread ptr, I2 = thread state, I3 = stack ptr */ +#define TX_TRACE_THREAD_TERMINATE 115 /* I1 = thread ptr, I2 = thread state, I3 = stack ptr */ +#define TX_TRACE_THREAD_TIME_SLICE_CHANGE 116 /* I1 = thread ptr, I2 = new timeslice, I3 = old timeslice */ +#define TX_TRACE_THREAD_WAIT_ABORT 117 /* I1 = thread ptr, I2 = thread state, I3 = stack ptr */ +#define TX_TRACE_TIME_GET 120 /* I1 = current time, I2 = stack ptr */ +#define TX_TRACE_TIME_SET 121 /* I1 = new time */ +#define TX_TRACE_TIMER_ACTIVATE 122 /* I1 = timer ptr */ +#define TX_TRACE_TIMER_CHANGE 123 /* I1 = timer ptr, I2 = initial ticks, I3= reschedule ticks */ +#define TX_TRACE_TIMER_CREATE 124 /* I1 = timer ptr, I2 = initial ticks, I3= reschedule ticks, I4 = enable */ +#define TX_TRACE_TIMER_DEACTIVATE 125 /* I1 = timer ptr, I2 = stack ptr */ +#define TX_TRACE_TIMER_DELETE 126 /* I1 = timer ptr */ +#define TX_TRACE_TIMER_INFO_GET 127 /* I1 = timer ptr, I2 = stack ptr */ +#define TX_TRACE_TIMER_PERFORMANCE_INFO_GET 128 /* I1 = timer ptr */ +#define TX_TRACE_TIMER_PERFORMANCE_SYSTEM_INFO_GET 129 /* None */ + + +/* Define the an Trace Buffer Entry. */ + +typedef struct TX_TRACE_BUFFER_ENTRY_STRUCT +{ + + ULONG tx_trace_buffer_entry_thread_pointer; + ULONG tx_trace_buffer_entry_thread_priority; + ULONG tx_trace_buffer_entry_event_id; + ULONG tx_trace_buffer_entry_time_stamp; +#ifdef TX_MISRA_ENABLE + ULONG tx_trace_buffer_entry_info_1; + ULONG tx_trace_buffer_entry_info_2; + ULONG tx_trace_buffer_entry_info_3; + ULONG tx_trace_buffer_entry_info_4; +#else + ULONG tx_trace_buffer_entry_information_field_1; + ULONG tx_trace_buffer_entry_information_field_2; + ULONG tx_trace_buffer_entry_information_field_3; + ULONG tx_trace_buffer_entry_information_field_4; +#endif +} TX_TRACE_BUFFER_ENTRY; + + +/* Trace management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef TX_TRACE_INIT +#define TRACE_DECLARE +#else +#define TRACE_DECLARE extern +#endif + + +/* Define the pointer to the start of the trace buffer control structure. */ + +TRACE_DECLARE TX_TRACE_HEADER *_tx_trace_header_ptr; + + +/* Define the pointer to the start of the trace object registry area in the trace buffer. */ + +TRACE_DECLARE TX_TRACE_OBJECT_ENTRY *_tx_trace_registry_start_ptr; + + +/* Define the pointer to the end of the trace object registry area in the trace buffer. */ + +TRACE_DECLARE TX_TRACE_OBJECT_ENTRY *_tx_trace_registry_end_ptr; + + +/* Define the pointer to the starting entry of the actual trace event area of the trace buffer. */ + +TRACE_DECLARE TX_TRACE_BUFFER_ENTRY *_tx_trace_buffer_start_ptr; + + +/* Define the pointer to the ending entry of the actual trace event area of the trace buffer. */ + +TRACE_DECLARE TX_TRACE_BUFFER_ENTRY *_tx_trace_buffer_end_ptr; + + +/* Define the pointer to the current entry of the actual trace event area of the trace buffer. */ + +TRACE_DECLARE TX_TRACE_BUFFER_ENTRY *_tx_trace_buffer_current_ptr; + + +/* Define the trace event enable bits, where each bit represents a type of event that can be enabled + or disabled dynamically by the application. */ + +TRACE_DECLARE ULONG _tx_trace_event_enable_bits; + + +/* Define a counter that is used in environments that don't have a timer source. This counter + is incremented on each use giving each event a unique timestamp. */ + +TRACE_DECLARE ULONG _tx_trace_simulated_time; + + +/* Define the function pointer used to call the application when the trace buffer wraps. If NULL, + the application has not registered a callback function. */ + +TRACE_DECLARE VOID (*_tx_trace_full_notify_function)(VOID *buffer); + + +/* Define the total number of registry entries. */ + +TRACE_DECLARE ULONG _tx_trace_total_registry_entries; + + +/* Define a counter that is used to track the number of available registry entries. */ + +TRACE_DECLARE ULONG _tx_trace_available_registry_entries; + + +/* Define an index that represents the start of the registry search. */ + +TRACE_DECLARE ULONG _tx_trace_registry_search_start; + + +/* Define the event trace macros that are expanded in-line when event tracing is enabled. */ + +#ifdef TX_MISRA_ENABLE +#define TX_TRACE_INFO_FIELD_ASSIGNMENT(a,b,c,d) trace_event_ptr -> tx_trace_buffer_entry_info_1 = (ULONG) (a); trace_event_ptr -> tx_trace_buffer_entry_info_2 = (ULONG) (b); trace_event_ptr -> tx_trace_buffer_entry_info_3 = (ULONG) (c); trace_event_ptr -> tx_trace_buffer_entry_info_4 = (ULONG) (d); +#else +#define TX_TRACE_INFO_FIELD_ASSIGNMENT(a,b,c,d) trace_event_ptr -> tx_trace_buffer_entry_information_field_1 = (ULONG) (a); trace_event_ptr -> tx_trace_buffer_entry_information_field_2 = (ULONG) (b); trace_event_ptr -> tx_trace_buffer_entry_information_field_3 = (ULONG) (c); trace_event_ptr -> tx_trace_buffer_entry_information_field_4 = (ULONG) (d); +#endif + + +#define TX_TRACE_INITIALIZE _tx_trace_initialize(); +#define TX_TRACE_OBJECT_REGISTER(t,p,n,a,b) _tx_trace_object_register((UCHAR) (t), (VOID *) (p), (CHAR *) (n), (ULONG) (a), (ULONG) (b)); +#define TX_TRACE_OBJECT_UNREGISTER(o) _tx_trace_object_unregister((VOID *) (o)); +#ifndef TX_TRACE_IN_LINE_INSERT +#define TX_TRACE_IN_LINE_INSERT(i,a,b,c,d,e) \ + { \ + TX_TRACE_BUFFER_ENTRY *trace_event_ptr; \ + ULONG trace_system_state; \ + ULONG trace_priority; \ + TX_THREAD *trace_thread_ptr; \ + trace_event_ptr = _tx_trace_buffer_current_ptr; \ + if ((trace_event_ptr) && (_tx_trace_event_enable_bits & ((ULONG) (e)))) \ + { \ + TX_TRACE_PORT_EXTENSION \ + trace_system_state = (ULONG) TX_THREAD_GET_SYSTEM_STATE(); \ + TX_THREAD_GET_CURRENT(trace_thread_ptr) \ + \ + if (trace_system_state == 0) \ + { \ + trace_priority = trace_thread_ptr -> tx_thread_priority; \ + trace_priority = trace_priority | 0x80000000UL | (trace_thread_ptr -> tx_thread_preempt_threshold << 16); \ + } \ + else if (trace_system_state < 0xF0F0F0F0UL) \ + { \ + trace_priority = (ULONG) trace_thread_ptr; \ + trace_thread_ptr = (TX_THREAD *) 0xFFFFFFFFUL; \ + } \ + else \ + { \ + trace_thread_ptr = (TX_THREAD *) 0xF0F0F0F0UL; \ + trace_priority = 0; \ + } \ + trace_event_ptr -> tx_trace_buffer_entry_thread_pointer = (ULONG) trace_thread_ptr; \ + trace_event_ptr -> tx_trace_buffer_entry_thread_priority = (ULONG) trace_priority; \ + trace_event_ptr -> tx_trace_buffer_entry_event_id = (ULONG) (i); \ + trace_event_ptr -> tx_trace_buffer_entry_time_stamp = (ULONG) TX_TRACE_TIME_SOURCE; \ + TX_TRACE_INFO_FIELD_ASSIGNMENT((a),(b),(c),(d)) \ + trace_event_ptr++; \ + if (trace_event_ptr >= _tx_trace_buffer_end_ptr) \ + { \ + trace_event_ptr = _tx_trace_buffer_start_ptr; \ + _tx_trace_buffer_current_ptr = trace_event_ptr; \ + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr; \ + if (_tx_trace_full_notify_function) \ + (_tx_trace_full_notify_function)((VOID *) _tx_trace_header_ptr); \ + } \ + else \ + { \ + _tx_trace_buffer_current_ptr = trace_event_ptr; \ + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr; \ + } \ + } \ + } +#endif +#endif + + +#ifdef TX_SOURCE_CODE + +/* Define internal function prototypes of the trace component, only if compiling ThreadX source code. */ + +VOID _tx_trace_initialize(VOID); +VOID _tx_trace_object_register(UCHAR object_type, VOID *object_ptr, CHAR *object_name, ULONG parameter_1, ULONG parameter_2); +VOID _tx_trace_object_unregister(VOID *object_ptr); + + +#ifdef TX_ENABLE_EVENT_TRACE + +/* Check for MISRA compliance requirements. */ + +#ifdef TX_MISRA_ENABLE + +/* Define MISRA-specific routines. */ + +UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); +TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); +TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); +TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); +UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); + + +#define TX_OBJECT_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_object_to_uchar_pointer_convert((a)) +#define TX_UCHAR_TO_OBJECT_POINTER_CONVERT(a) _tx_misra_uchar_to_object_pointer_convert((a)) +#define TX_UCHAR_TO_HEADER_POINTER_CONVERT(a) _tx_misra_uchar_to_header_pointer_convert((a)) +#define TX_UCHAR_TO_ENTRY_POINTER_CONVERT(a) _tx_misra_uchar_to_entry_pointer_convert((a)) +#define TX_ENTRY_TO_UCHAR_POINTER_CONVERT(a) _tx_misra_entry_to_uchar_pointer_convert((a)) + +#else + +#define TX_OBJECT_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR *) ((VOID *) (a))) +#define TX_UCHAR_TO_OBJECT_POINTER_CONVERT(a) ((TX_TRACE_OBJECT_ENTRY *) ((VOID *) (a))) +#define TX_UCHAR_TO_HEADER_POINTER_CONVERT(a) ((TX_TRACE_HEADER *) ((VOID *) (a))) +#define TX_UCHAR_TO_ENTRY_POINTER_CONVERT(a) ((TX_TRACE_BUFFER_ENTRY *) ((VOID *) (a))) +#define TX_ENTRY_TO_UCHAR_POINTER_CONVERT(a) ((UCHAR *) ((VOID *) (a))) + +#endif +#endif +#endif +#endif + diff --git a/common/inc/tx_user_sample.h b/common/inc/tx_user_sample.h new file mode 100644 index 0000000..e7ecb56 --- /dev/null +++ b/common/inc/tx_user_sample.h @@ -0,0 +1,317 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** User Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_user.h PORTABLE C */ +/* 6.3.0 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains user defines for configuring ThreadX in specific */ +/* ways. This file will have an effect only if the application and */ +/* ThreadX library are built with TX_INCLUDE_USER_DEFINE_FILE defined. */ +/* Note that all the defines in this file may also be made on the */ +/* command line when building ThreadX library and application objects. */ +/* */ +/* 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-02-2021 Scott Larson Modified comment(s), */ +/* added option to remove */ +/* FileX pointer, */ +/* resulting in version 6.1.5 */ +/* 06-02-2021 Scott Larson Added options for multiple */ +/* block pool search & delay, */ +/* resulting in version 6.1.7 */ +/* 10-15-2021 Yuxin Zhou Modified comment(s), added */ +/* user-configurable symbol */ +/* TX_TIMER_TICKS_PER_SECOND */ +/* resulting in version 6.1.9 */ +/* 04-25-2022 Wenhui Xie Modified comment(s), */ +/* optimized the definition of */ +/* TX_TIMER_TICKS_PER_SECOND, */ +/* resulting in version 6.1.11 */ +/* 10-31-2023 Xiuwen Cai Modified comment(s), */ +/* added option for random */ +/* number stack filling, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ + +#ifndef TX_USER_H +#define TX_USER_H + + +/* Define various build options for the ThreadX port. The application should either make changes + here by commenting or un-commenting the conditional compilation defined OR supply the defines + though the compiler's equivalent of the -D option. + + For maximum speed, the following should be defined: + + TX_MAX_PRIORITIES 32 + TX_DISABLE_PREEMPTION_THRESHOLD + TX_DISABLE_REDUNDANT_CLEARING + TX_DISABLE_NOTIFY_CALLBACKS + TX_NOT_INTERRUPTABLE + TX_TIMER_PROCESS_IN_ISR + TX_REACTIVATE_INLINE + TX_DISABLE_STACK_FILLING + TX_INLINE_THREAD_RESUME_SUSPEND + + For minimum size, the following should be defined: + + TX_MAX_PRIORITIES 32 + TX_DISABLE_PREEMPTION_THRESHOLD + TX_DISABLE_REDUNDANT_CLEARING + TX_DISABLE_NOTIFY_CALLBACKS + TX_NO_FILEX_POINTER + TX_NOT_INTERRUPTABLE + TX_TIMER_PROCESS_IN_ISR + + Of course, many of these defines reduce functionality and/or change the behavior of the + system in ways that may not be worth the trade-off. For example, the TX_TIMER_PROCESS_IN_ISR + results in faster and smaller code, however, it increases the amount of processing in the ISR. + In addition, some services that are available in timers are not available from ISRs and will + therefore return an error if this option is used. This may or may not be desirable for a + given application. */ + + +/* Override various options with default values already assigned in tx_port.h. Please also refer + to tx_port.h for descriptions on each of these options. */ + +/* +#define TX_MAX_PRIORITIES 32 +#define TX_MINIMUM_STACK ???? +#define TX_THREAD_USER_EXTENSION ???? +#define TX_TIMER_THREAD_STACK_SIZE ???? +#define TX_TIMER_THREAD_PRIORITY ???? +*/ + +/* Define the common timer tick reference for use by other middleware components. The default + value is 10ms (i.e. 100 ticks, defined in tx_api.h), but may be replaced by a port-specific + version in tx_port.h or here. + Note: the actual hardware timer value may need to be changed (usually in tx_initialize_low_level). */ + +/* +#define TX_TIMER_TICKS_PER_SECOND (100UL) +*/ + +/* Determine if there is a FileX pointer in the thread control block. + By default, the pointer is there for legacy/backwards compatibility. + The pointer must also be there for applications using FileX. + Define this to save space in the thread control block. +*/ + +/* +#define TX_NO_FILEX_POINTER +*/ + +/* Determine if timer expirations (application timers, timeouts, and tx_thread_sleep calls + should be processed within the a system timer thread or directly in the timer ISR. + By default, the timer thread is used. When the following is defined, the timer expiration + processing is done directly from the timer ISR, thereby eliminating the timer thread control + block, stack, and context switching to activate it. */ + +/* +#define TX_TIMER_PROCESS_IN_ISR +*/ + +/* Determine if in-line timer reactivation should be used within the timer expiration processing. + By default, this is disabled and a function call is used. When the following is defined, + reactivating is performed in-line resulting in faster timer processing but slightly larger + code size. */ + +/* +#define TX_REACTIVATE_INLINE +*/ + +/* Determine is stack filling is enabled. By default, ThreadX stack filling is enabled, + which places an 0xEF pattern in each byte of each thread's stack. This is used by + debuggers with ThreadX-awareness and by the ThreadX run-time stack checking feature. */ + +/* +#define TX_DISABLE_STACK_FILLING +*/ + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +/* +#define TX_ENABLE_STACK_CHECKING +*/ + +/* Determine if random number is used for stack filling. By default, ThreadX uses a fixed + pattern for stack filling. When the following is defined, ThreadX uses a random number + for stack filling. This is effective only when TX_ENABLE_STACK_CHECKING is defined. */ + +/* +#define TX_ENABLE_RANDOM_NUMBER_STACK_FILLING +*/ + +/* Determine if preemption-threshold should be disabled. By default, preemption-threshold is + enabled. If the application does not use preemption-threshold, it may be disabled to reduce + code size and improve performance. */ + +/* +#define TX_DISABLE_PREEMPTION_THRESHOLD +*/ + +/* Determine if global ThreadX variables should be cleared. If the compiler startup code clears + the .bss section prior to ThreadX running, the define can be used to eliminate unnecessary + clearing of ThreadX global variables. */ + +/* +#define TX_DISABLE_REDUNDANT_CLEARING +*/ + +/* Determine if no timer processing is required. This option will help eliminate the timer + processing when not needed. The user will also have to comment out the call to + tx_timer_interrupt, which is typically made from assembly language in + tx_initialize_low_level. Note: if TX_NO_TIMER is used, the define TX_TIMER_PROCESS_IN_ISR + must also be used and tx_timer_initialize must be removed from ThreadX library. */ + +/* +#define TX_NO_TIMER +#ifndef TX_TIMER_PROCESS_IN_ISR +#define TX_TIMER_PROCESS_IN_ISR +#endif +*/ + +/* Determine if the notify callback option should be disabled. By default, notify callbacks are + enabled. If the application does not use notify callbacks, they may be disabled to reduce + code size and improve performance. */ + +/* +#define TX_DISABLE_NOTIFY_CALLBACKS +*/ + + +/* Determine if the tx_thread_resume and tx_thread_suspend services should have their internal + code in-line. This results in a larger image, but improves the performance of the thread + resume and suspend services. */ + +/* +#define TX_INLINE_THREAD_RESUME_SUSPEND +*/ + + +/* Determine if the internal ThreadX code is non-interruptable. This results in smaller code + size and less processing overhead, but increases the interrupt lockout time. */ + +/* +#define TX_NOT_INTERRUPTABLE +*/ + + +/* Determine if the trace event logging code should be enabled. This causes slight increases in + code size and overhead, but provides the ability to generate system trace information which + is available for viewing in TraceX. */ + +/* +#define TX_ENABLE_EVENT_TRACE +*/ + + +/* Determine if block pool performance gathering is required by the application. When the following is + defined, ThreadX gathers various block pool performance information. */ + +/* +#define TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if byte pool performance gathering is required by the application. When the following is + defined, ThreadX gathers various byte pool performance information. */ + +/* +#define TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if event flags performance gathering is required by the application. When the following is + defined, ThreadX gathers various event flags performance information. */ + +/* +#define TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if mutex performance gathering is required by the application. When the following is + defined, ThreadX gathers various mutex performance information. */ + +/* +#define TX_MUTEX_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if queue performance gathering is required by the application. When the following is + defined, ThreadX gathers various queue performance information. */ + +/* +#define TX_QUEUE_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if semaphore performance gathering is required by the application. When the following is + defined, ThreadX gathers various semaphore performance information. */ + +/* +#define TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if thread performance gathering is required by the application. When the following is + defined, ThreadX gathers various thread performance information. */ + +/* +#define TX_THREAD_ENABLE_PERFORMANCE_INFO +*/ + +/* Determine if timer performance gathering is required by the application. When the following is + defined, ThreadX gathers various timer performance information. */ + +/* +#define TX_TIMER_ENABLE_PERFORMANCE_INFO +*/ + +/* Override options for byte pool searches of multiple blocks. */ + +/* +#define TX_BYTE_POOL_MULTIPLE_BLOCK_SEARCH 20 +*/ + +/* Override options for byte pool search delay to avoid thrashing. */ + +/* +#define TX_BYTE_POOL_DELAY_VALUE 3 +*/ + +#endif + diff --git a/common/src/tx_block_allocate.c b/common/src/tx_block_allocate.c new file mode 100644 index 0000000..b2c7bef --- /dev/null +++ b/common/src/tx_block_allocate.c @@ -0,0 +1,373 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_block_pool_cleanup.c b/common/src/tx_block_pool_cleanup.c new file mode 100644 index 0000000..9bae546 --- /dev/null +++ b/common/src/tx_block_pool_cleanup.c @@ -0,0 +1,214 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_block_pool_create.c b/common/src/tx_block_pool_create.c new file mode 100644 index 0000000..5461201 --- /dev/null +++ b/common/src/tx_block_pool_create.c @@ -0,0 +1,214 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_block_pool_delete.c b/common/src/tx_block_pool_delete.c new file mode 100644 index 0000000..da27ef5 --- /dev/null +++ b/common/src/tx_block_pool_delete.c @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_block_pool_info_get.c b/common/src/tx_block_pool_info_get.c new file mode 100644 index 0000000..aebd0db --- /dev/null +++ b/common/src/tx_block_pool_info_get.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_block_pool_initialize.c b/common/src/tx_block_pool_initialize.c new file mode 100644 index 0000000..2113215 --- /dev/null +++ b/common/src/tx_block_pool_initialize.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_block_pool_performance_info_get.c b/common/src/tx_block_pool_performance_info_get.c new file mode 100644 index 0000000..84f6802 --- /dev/null +++ b/common/src/tx_block_pool_performance_info_get.c @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* block pool. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to block pool control blk */ +/* allocates Destination for the number of */ +/* allocations from this pool */ +/* releases Destination for the number of */ +/* blocks released back to pool */ +/* suspensions Destination for number of */ +/* suspensions on this pool */ +/* timeouts Destination for number of timeouts*/ +/* on this pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_BLOCK_POOL *pool_ptr, ULONG *allocates, ULONG *releases, + ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Determine if this is a legal request. */ + if (pool_ptr == TX_NULL) + { + + /* Block pool pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the pool ID is invalid. */ + else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID) + { + + /* Block pool pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL_PERFORMANCE_INFO_GET, pool_ptr, 0, 0, 0, TX_TRACE_BLOCK_POOL_EVENTS) + + /* Log this kernel call. */ + TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the number of allocations from this block pool. */ + if (allocates != TX_NULL) + { + + *allocates = pool_ptr -> tx_block_pool_performance_allocate_count; + } + + /* Retrieve the number of blocks released to this block pool. */ + if (releases != TX_NULL) + { + + *releases = pool_ptr -> tx_block_pool_performance_release_count; + } + + /* Retrieve the number of thread suspensions on this block pool. */ + if (suspensions != TX_NULL) + { + + *suspensions = pool_ptr -> tx_block_pool_performance_suspension_count; + } + + /* Retrieve the number of thread timeouts on this block pool. */ + if (timeouts != TX_NULL) + { + + *timeouts = pool_ptr -> tx_block_pool_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + status = TX_SUCCESS; + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (pool_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (allocates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (releases != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_block_pool_performance_system_info_get.c b/common/src/tx_block_pool_performance_system_info_get.c new file mode 100644 index 0000000..0707295 --- /dev/null +++ b/common/src/tx_block_pool_performance_system_info_get.c @@ -0,0 +1,174 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves block pool performance information. */ +/* */ +/* INPUT */ +/* */ +/* allocates Destination for the total number */ +/* of block allocations */ +/* releases Destination for the total number */ +/* of blocks released */ +/* suspensions Destination for the total number */ +/* of suspensions */ +/* timeouts Destination for total number of */ +/* timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *allocates, ULONG *releases, ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_BLOCK_POOL__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_BLOCK_POOL_EVENTS) + + /* Log this kernel call. */ + TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the total number of block allocations. */ + if (allocates != TX_NULL) + { + + *allocates = _tx_block_pool_performance_allocate_count; + } + + /* Retrieve the total number of blocks released. */ + if (releases != TX_NULL) + { + + *releases = _tx_block_pool_performance_release_count; + } + + /* Retrieve the total number of block pool thread suspensions. */ + if (suspensions != TX_NULL) + { + + *suspensions = _tx_block_pool_performance_suspension_count; + } + + /* Retrieve the total number of block pool thread timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_block_pool_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (allocates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (releases != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_block_pool_prioritize.c b/common/src/tx_block_pool_prioritize.c new file mode 100644 index 0000000..c4ee4e9 --- /dev/null +++ b/common/src/tx_block_pool_prioritize.c @@ -0,0 +1,250 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_block_release.c b/common/src/tx_block_release.c new file mode 100644 index 0000000..3b94c1b --- /dev/null +++ b/common/src/tx_block_release.c @@ -0,0 +1,205 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_allocate.c b/common/src/tx_byte_allocate.c new file mode 100644 index 0000000..69e837e --- /dev/null +++ b/common/src/tx_byte_allocate.c @@ -0,0 +1,410 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_pool_cleanup.c b/common/src/tx_byte_pool_cleanup.c new file mode 100644 index 0000000..a1260c5 --- /dev/null +++ b/common/src/tx_byte_pool_cleanup.c @@ -0,0 +1,213 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_byte_pool_create.c b/common/src/tx_byte_pool_create.c new file mode 100644 index 0000000..439eed7 --- /dev/null +++ b/common/src/tx_byte_pool_create.c @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_pool_delete.c b/common/src/tx_byte_pool_delete.c new file mode 100644 index 0000000..fc3d9be --- /dev/null +++ b/common/src/tx_byte_pool_delete.c @@ -0,0 +1,212 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_pool_info_get.c b/common/src/tx_byte_pool_info_get.c new file mode 100644 index 0000000..339aa77 --- /dev/null +++ b/common/src/tx_byte_pool_info_get.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_pool_initialize.c b/common/src/tx_byte_pool_initialize.c new file mode 100644 index 0000000..6551453 --- /dev/null +++ b/common/src/tx_byte_pool_initialize.c @@ -0,0 +1,150 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_byte_pool_performance_info_get.c b/common/src/tx_byte_pool_performance_info_get.c new file mode 100644 index 0000000..400804a --- /dev/null +++ b/common/src/tx_byte_pool_performance_info_get.c @@ -0,0 +1,254 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* byte pool. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to byte pool control block*/ +/* allocates Destination for number of */ +/* allocates on this pool */ +/* releases Destination for number of */ +/* releases on this pool */ +/* fragments_searched Destination for number of */ +/* fragments searched during */ +/* allocation */ +/* merges Destination for number of adjacent*/ +/* free fragments merged */ +/* splits Destination for number of */ +/* fragments split during */ +/* allocation */ +/* suspensions Destination for number of */ +/* suspensions on this pool */ +/* timeouts Destination for number of timeouts*/ +/* on this byte pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_BYTE_POOL *pool_ptr, ULONG *allocates, ULONG *releases, + ULONG *fragments_searched, ULONG *merges, ULONG *splits, ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + +UINT status; + + + /* Determine if this is a legal request. */ + if (pool_ptr == TX_NULL) + { + + /* Byte pool pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the pool ID is invalid. */ + else if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID) + { + + /* Byte pool pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL_PERFORMANCE_INFO_GET, pool_ptr, 0, 0, 0, TX_TRACE_BYTE_POOL_EVENTS) + + /* Log this kernel call. */ + TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the number of allocates on this byte pool. */ + if (allocates != TX_NULL) + { + + *allocates = pool_ptr -> tx_byte_pool_performance_allocate_count; + } + + /* Retrieve the number of releases on this byte pool. */ + if (releases != TX_NULL) + { + + *releases = pool_ptr -> tx_byte_pool_performance_release_count; + } + + /* Retrieve the number of fragments searched in this byte pool. */ + if (fragments_searched != TX_NULL) + { + + *fragments_searched = pool_ptr -> tx_byte_pool_performance_search_count; + } + + /* Retrieve the number of fragments merged on this byte pool. */ + if (merges != TX_NULL) + { + + *merges = pool_ptr -> tx_byte_pool_performance_merge_count; + } + + /* Retrieve the number of fragment splits on this byte pool. */ + if (splits != TX_NULL) + { + + *splits = pool_ptr -> tx_byte_pool_performance_split_count; + } + + /* Retrieve the number of suspensions on this byte pool. */ + if (suspensions != TX_NULL) + { + + *suspensions = pool_ptr -> tx_byte_pool_performance_suspension_count; + } + + /* Retrieve the number of timeouts on this byte pool. */ + if (timeouts != TX_NULL) + { + + *timeouts = pool_ptr -> tx_byte_pool_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + status = TX_SUCCESS; + } + + /* Return completion status. */ + return(status); +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (pool_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (allocates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (releases != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (fragments_searched != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (merges != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (splits != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_byte_pool_performance_system_info_get.c b/common/src/tx_byte_pool_performance_system_info_get.c new file mode 100644 index 0000000..266e276 --- /dev/null +++ b/common/src/tx_byte_pool_performance_system_info_get.c @@ -0,0 +1,222 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves byte pool performance information. */ +/* */ +/* INPUT */ +/* */ +/* allocates Destination for total number of */ +/* allocates */ +/* releases Destination for total number of */ +/* releases */ +/* fragments_searched Destination for total number of */ +/* fragments searched during */ +/* allocation */ +/* merges Destination for total number of */ +/* adjacent free fragments merged */ +/* splits Destination for total number of */ +/* fragments split during */ +/* allocation */ +/* suspensions Destination for total number of */ +/* suspensions */ +/* timeouts Destination for total number of */ +/* timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *allocates, ULONG *releases, + ULONG *fragments_searched, ULONG *merges, ULONG *splits, ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_BYTE_POOL__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_BYTE_POOL_EVENTS) + + /* Log this kernel call. */ + TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the total number of byte pool allocates. */ + if (allocates != TX_NULL) + { + + *allocates = _tx_byte_pool_performance_allocate_count; + } + + /* Retrieve the total number of byte pool releases. */ + if (releases != TX_NULL) + { + + *releases = _tx_byte_pool_performance_release_count; + } + + /* Retrieve the total number of byte pool fragments searched. */ + if (fragments_searched != TX_NULL) + { + + *fragments_searched = _tx_byte_pool_performance_search_count; + } + + /* Retrieve the total number of byte pool fragments merged. */ + if (merges != TX_NULL) + { + + *merges = _tx_byte_pool_performance_merge_count; + } + + /* Retrieve the total number of byte pool fragment splits. */ + if (splits != TX_NULL) + { + + *splits = _tx_byte_pool_performance_split_count; + } + + /* Retrieve the total number of byte pool suspensions. */ + if (suspensions != TX_NULL) + { + + *suspensions = _tx_byte_pool_performance_suspension_count; + } + + /* Retrieve the total number of byte pool timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_byte_pool_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (allocates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (releases != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (fragments_searched != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (merges != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (splits != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_byte_pool_prioritize.c b/common/src/tx_byte_pool_prioritize.c new file mode 100644 index 0000000..0076e50 --- /dev/null +++ b/common/src/tx_byte_pool_prioritize.c @@ -0,0 +1,250 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_pool_search.c b/common/src/tx_byte_pool_search.c new file mode 100644 index 0000000..504ad74 --- /dev/null +++ b/common/src/tx_byte_pool_search.c @@ -0,0 +1,353 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_byte_release.c b/common/src/tx_byte_release.c new file mode 100644 index 0000000..387320b --- /dev/null +++ b/common/src/tx_byte_release.c @@ -0,0 +1,377 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_event_flags_cleanup.c b/common/src/tx_event_flags_cleanup.c new file mode 100644 index 0000000..3f87056 --- /dev/null +++ b/common/src/tx_event_flags_cleanup.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_event_flags_create.c b/common/src/tx_event_flags_create.c new file mode 100644 index 0000000..2195527 --- /dev/null +++ b/common/src/tx_event_flags_create.c @@ -0,0 +1,142 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_event_flags_delete.c b/common/src/tx_event_flags_delete.c new file mode 100644 index 0000000..2b7c890 --- /dev/null +++ b/common/src/tx_event_flags_delete.c @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_event_flags_get.c b/common/src/tx_event_flags_get.c new file mode 100644 index 0000000..4e9abb8 --- /dev/null +++ b/common/src/tx_event_flags_get.c @@ -0,0 +1,406 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_event_flags_info_get.c b/common/src/tx_event_flags_info_get.c new file mode 100644 index 0000000..9d409bc --- /dev/null +++ b/common/src/tx_event_flags_info_get.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_event_flags_initialize.c b/common/src/tx_event_flags_initialize.c new file mode 100644 index 0000000..f7b107c --- /dev/null +++ b/common/src/tx_event_flags_initialize.c @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_event_flags_performance_info_get.c b/common/src/tx_event_flags_performance_info_get.c new file mode 100644 index 0000000..c0529b0 --- /dev/null +++ b/common/src/tx_event_flags_performance_info_get.c @@ -0,0 +1,203 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* event flag group. */ +/* */ +/* INPUT */ +/* */ +/* group_ptr Pointer to event flag group */ +/* sets Destination for the number of */ +/* event flag sets on this group */ +/* gets Destination for the number of */ +/* event flag gets on this group */ +/* suspensions Destination for the number of */ +/* event flag suspensions on this */ +/* group */ +/* timeouts Destination for number of timeouts*/ +/* on this event flag group */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG *sets, ULONG *gets, + ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Determine if this is a legal request. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the event group ID is invalid. */ + else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID) + { + + /* Event flags group pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_PERFORMANCE_INFO_GET, group_ptr, 0, 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS) + + /* Log this kernel call. */ + TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the number of set operations on this event flag group. */ + if (sets != TX_NULL) + { + + *sets = group_ptr -> tx_event_flags_group_performance_set_count; + } + + /* Retrieve the number of get operations on this event flag group. */ + if (gets != TX_NULL) + { + + *gets = group_ptr -> tx_event_flags_group__performance_get_count; + } + + /* Retrieve the number of thread suspensions on this event flag group. */ + if (suspensions != TX_NULL) + { + + *suspensions = group_ptr -> tx_event_flags_group___performance_suspension_count; + } + + /* Retrieve the number of thread timeouts on this event flag group. */ + if (timeouts != TX_NULL) + { + + *timeouts = group_ptr -> tx_event_flags_group____performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + status = TX_SUCCESS; + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (group_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (sets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (gets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_event_flags_performance_system_info_get.c b/common/src/tx_event_flags_performance_system_info_get.c new file mode 100644 index 0000000..3f1570d --- /dev/null +++ b/common/src/tx_event_flags_performance_system_info_get.c @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves system event flag performance information. */ +/* */ +/* INPUT */ +/* */ +/* sets Destination for total number of */ +/* event flag sets */ +/* gets Destination for total number of */ +/* event flag gets */ +/* suspensions Destination for total number of */ +/* event flag suspensions */ +/* timeouts Destination for total number of */ +/* timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *sets, ULONG *gets, ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_EVENT_FLAGS_EVENTS) + + /* Log this kernel call. */ + TX_EL_EVENT_FLAGS__PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the total number of event flag set operations. */ + if (sets != TX_NULL) + { + + *sets = _tx_event_flags_performance_set_count; + } + + /* Retrieve the total number of event flag get operations. */ + if (gets != TX_NULL) + { + + *gets = _tx_event_flags_performance_get_count; + } + + /* Retrieve the total number of event flag thread suspensions. */ + if (suspensions != TX_NULL) + { + + *suspensions = _tx_event_flags_performance_suspension_count; + } + + /* Retrieve the total number of event flag thread timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_event_flags_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (sets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (gets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_event_flags_set.c b/common/src/tx_event_flags_set.c new file mode 100644 index 0000000..8309be1 --- /dev/null +++ b/common/src/tx_event_flags_set.c @@ -0,0 +1,624 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_event_flags_set_notify.c b/common/src/tx_event_flags_set_notify.c new file mode 100644 index 0000000..ab2b9a1 --- /dev/null +++ b/common/src/tx_event_flags_set_notify.c @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_initialize_high_level.c b/common/src/tx_initialize_high_level.c new file mode 100644 index 0000000..b722455 --- /dev/null +++ b/common/src/tx_initialize_high_level.c @@ -0,0 +1,151 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_initialize_kernel_enter.c b/common/src/tx_initialize_kernel_enter.c new file mode 100644 index 0000000..e5eda61 --- /dev/null +++ b/common/src/tx_initialize_kernel_enter.c @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_initialize_kernel_setup.c b/common/src/tx_initialize_kernel_setup.c new file mode 100644 index 0000000..d61e931 --- /dev/null +++ b/common/src/tx_initialize_kernel_setup.c @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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; +} + diff --git a/common/src/tx_misra.c b/common/src/tx_misra.c new file mode 100644 index 0000000..90533b9 --- /dev/null +++ b/common/src/tx_misra.c @@ -0,0 +1,835 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX MISRA Compliance */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** _tx_version_id */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef TX_MISRA_ENABLE +#include "tx_api.h" +#else +#define TX_THREAD_INIT +//CHAR _tx_version_id[100] = "Copyright (c) 2024 Microsoft Corporation. * ThreadX 6.1 MISRA C Compliant *"; + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size) +{ + memset(ptr, (INT)value, size); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount) +{ + ptr = ptr + amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount) +{ + ptr = ptr - amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2) +{ + +ULONG value; + + value = (ULONG)(ptr1 - ptr2); + return(value); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr) +{ + return((ULONG) ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount) +{ + ptr = ptr + amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount) +{ + + ptr = ptr - amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2) +{ +ULONG value; + + value = (ULONG)(ptr1 - ptr2); + return(value); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID *_tx_misra_ulong_to_pointer_convert(ULONG input) +{ + + return((VOID *) input); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */ +/** UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, UINT size) +{ + +ULONG *s, *d; +UINT z; + + s = *source; + d = *destination; + z = size; + + *(d) = *(s); + (d)++; + (s)++; + if ((z) > ((UINT) 1)) + { + (z)--; + while ((z)) + { + *(d) = *(s); + (d)++; + (s)++; + (z)--; + } + } + + *source = s; + *destination = d; +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */ +/** TX_TIMER_INTERNAL **ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, TX_TIMER_INTERNAL **ptr2) +{ + +ULONG value; + + value = (ULONG)(ptr1 - ptr2); + return(value); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */ +/** **ptr1, ULONG size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL **ptr1, ULONG amount) +{ + ptr1 = ptr1 + amount; + return(ptr1); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */ +/** *internal_timer, TX_TIMER **user_timer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL *internal_timer, TX_TIMER **user_timer) +{ + +UCHAR *working_ptr; +TX_TIMER *temp_timer; + + + working_ptr = (UCHAR *) internal_timer; + + temp_timer = (TX_TIMER *) working_ptr; + working_ptr = working_ptr - (((UCHAR *) &temp_timer -> tx_timer_internal) - ((UCHAR *) &temp_timer -> tx_timer_id)); + *user_timer = (TX_TIMER *) working_ptr; +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */ +/** VOID **highest_stack); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, VOID **highest_stack) +{ + +TX_INTERRUPT_SAVE_AREA + + TX_DISABLE + if (((thread_ptr)) && ((thread_ptr) -> tx_thread_id == TX_THREAD_ID)) + { + if (((ULONG *) (thread_ptr) -> tx_thread_stack_ptr) < ((ULONG *) *highest_stack)) + { + *highest_stack = (thread_ptr) -> tx_thread_stack_ptr; + } + if ((*((ULONG *) (thread_ptr) -> tx_thread_stack_start) != TX_STACK_FILL) || + (*((ULONG *) (((UCHAR *) (thread_ptr) -> tx_thread_stack_end) + 1)) != TX_STACK_FILL) || + (((ULONG *) *highest_stack) < ((ULONG *) (thread_ptr) -> tx_thread_stack_start))) + { + TX_RESTORE + _tx_thread_stack_error_handler((thread_ptr)); + TX_DISABLE + } + if (*(((ULONG *) *highest_stack) - 1) != TX_STACK_FILL) + { + TX_RESTORE + _tx_thread_stack_analyze((thread_ptr)); + TX_DISABLE + } + } + TX_RESTORE +} + + +#ifdef TX_ENABLE_EVENT_TRACE + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_trace_event_insert(ULONG event_id, */ +/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */ +/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_trace_event_insert(ULONG event_id, VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4, ULONG filter, ULONG time_stamp) +{ + +TX_TRACE_BUFFER_ENTRY *trace_event_ptr; +ULONG trace_system_state; +ULONG trace_priority; +TX_THREAD *trace_thread_ptr; + + + trace_event_ptr = _tx_trace_buffer_current_ptr; + if ((trace_event_ptr) && (_tx_trace_event_enable_bits & ((ULONG) (filter)))) + { + TX_TRACE_PORT_EXTENSION + trace_system_state = (ULONG) _tx_thread_system_state; + trace_thread_ptr = _tx_thread_current_ptr; + + if (trace_system_state == 0) + { + trace_priority = trace_thread_ptr -> tx_thread_priority; + trace_priority = trace_priority | 0x80000000UL | (trace_thread_ptr -> tx_thread_preempt_threshold << 16); + } + else if (trace_system_state < 0xF0F0F0F0UL) + { + trace_priority = (ULONG) trace_thread_ptr; + trace_thread_ptr = (TX_THREAD *) 0xFFFFFFFFUL; + } + else + { + trace_thread_ptr = (TX_THREAD *) 0xF0F0F0F0UL; + trace_priority = 0; + } + trace_event_ptr -> tx_trace_buffer_entry_thread_pointer = (ULONG) trace_thread_ptr; + trace_event_ptr -> tx_trace_buffer_entry_thread_priority = (ULONG) trace_priority; + trace_event_ptr -> tx_trace_buffer_entry_event_id = (ULONG) (event_id); + trace_event_ptr -> tx_trace_buffer_entry_time_stamp = (ULONG) (time_stamp); +#ifdef TX_MISRA_ENABLE + trace_event_ptr -> tx_trace_buffer_entry_info_1 = (ULONG) (info_field_1); + trace_event_ptr -> tx_trace_buffer_entry_info_2 = (ULONG) (info_field_2); + trace_event_ptr -> tx_trace_buffer_entry_info_3 = (ULONG) (info_field_3); + trace_event_ptr -> tx_trace_buffer_entry_info_4 = (ULONG) (info_field_4); +#else + trace_event_ptr -> tx_trace_buffer_entry_information_field_1 = (ULONG) (info_field_1); + trace_event_ptr -> tx_trace_buffer_entry_information_field_2 = (ULONG) (info_field_2); + trace_event_ptr -> tx_trace_buffer_entry_information_field_3 = (ULONG) (info_field_3); + trace_event_ptr -> tx_trace_buffer_entry_information_field_4 = (ULONG) (info_field_4); +#endif + trace_event_ptr++; + if (trace_event_ptr >= _tx_trace_buffer_end_ptr) + { + trace_event_ptr = _tx_trace_buffer_start_ptr; + _tx_trace_buffer_current_ptr = trace_event_ptr; + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr; + if (_tx_trace_full_notify_function) + (_tx_trace_full_notify_function)((VOID *) _tx_trace_header_ptr); + } + else + { + _tx_trace_buffer_current_ptr = trace_event_ptr; + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr; + } + } +} + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_time_stamp_get(VOID) +{ + + /* Return time stamp. */ + return(0); +} + +#endif + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UINT _tx_misra_always_true(void) +{ + return(TX_TRUE); +} + + +/******************************************************************************************/ +/******************************************************************************************/ +/** */ +/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */ +/** */ +/******************************************************************************************/ +/******************************************************************************************/ +UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr) +{ + + /* Return an indirect UCHAR pointer. */ + return((UCHAR **) ((VOID *) return_ptr)); +} + + +/***************************************************************************************/ +/***************************************************************************************/ +/** */ +/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */ +/** */ +/***************************************************************************************/ +/***************************************************************************************/ +UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer) +{ + + /* Return an indirect UCHAR pointer. */ + return((UCHAR **) ((VOID *) pointer)); +} + + +/***********************************************************************************/ +/***********************************************************************************/ +/** */ +/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */ +/** */ +/***********************************************************************************/ +/***********************************************************************************/ +UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pool)); +} + + +/******************************************************************************************/ +/******************************************************************************************/ +/** */ +/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */ +/** */ +/******************************************************************************************/ +/******************************************************************************************/ +TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer) +{ + + /* Return a block pool pointer. */ + return((TX_BLOCK_POOL *) ((VOID *) pointer)); +} + + +/*****************************************************************************/ +/*****************************************************************************/ +/** */ +/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */ +/** */ +/*****************************************************************************/ +/*****************************************************************************/ +UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + + +/************************************************************************************/ +/************************************************************************************/ +/** */ +/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */ +/** */ +/************************************************************************************/ +/************************************************************************************/ +TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer) +{ + + /* Return a UCHAR pointer. */ + return((TX_BLOCK_POOL *) ((VOID *) pointer)); +} + + +/**************************************************************************************/ +/**************************************************************************************/ +/** */ +/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */ +/** */ +/**************************************************************************************/ +/**************************************************************************************/ +UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR **) ((VOID *) pointer)); +} + + +/*****************************************************************************************/ +/*****************************************************************************************/ +/** */ +/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */ +/** */ +/*****************************************************************************************/ +/*****************************************************************************************/ +TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer) +{ + + /* Return a byte pool pointer. */ + return((TX_BYTE_POOL *) ((VOID *) pointer)); +} + + +/***************************************************************************************/ +/***************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */ +/** */ +/***************************************************************************************/ +/***************************************************************************************/ +UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pool)); +} + + +/*****************************************************************************************/ +/*****************************************************************************************/ +/** */ +/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */ +/** */ +/*****************************************************************************************/ +/*****************************************************************************************/ +ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer) +{ + + /* Return an align time pointer. */ + return((ALIGN_TYPE *) ((VOID *) pointer)); +} + + +/****************************************************************************************************/ +/****************************************************************************************************/ +/** */ +/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */ +/** */ +/****************************************************************************************************/ +/****************************************************************************************************/ +TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer) +{ + + /* Return a byte pool pointer. */ + return((TX_BYTE_POOL **) ((VOID *) pointer)); +} + + +/**************************************************************************************************/ +/**************************************************************************************************/ +/** */ +/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */ +/** */ +/**************************************************************************************************/ +/**************************************************************************************************/ +TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer) +{ + + /* Return event flags pointer. */ + return((TX_EVENT_FLAGS_GROUP *) ((VOID *) pointer)); +} + + +/*****************************************************************************/ +/*****************************************************************************/ +/** */ +/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */ +/** */ +/*****************************************************************************/ +/*****************************************************************************/ +ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer) +{ + + /* Return a ULONG pointer. */ + return((ULONG *) ((VOID *) pointer)); +} + + +/********************************************************************************/ +/********************************************************************************/ +/** */ +/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */ +/** */ +/********************************************************************************/ +/********************************************************************************/ +TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer) +{ + + /* Return a mutex pointer. */ + return((TX_MUTEX *) ((VOID *) pointer)); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UINT _tx_misra_status_get(UINT status) +{ + (VOID)status; + + /* Return a successful status. */ + return(TX_SUCCESS); +} + + +/********************************************************************************/ +/********************************************************************************/ +/** */ +/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */ +/** */ +/********************************************************************************/ +/********************************************************************************/ +TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer) +{ + + /* Return queue pointer. */ + return((TX_QUEUE *) ((VOID *) pointer)); +} + + +/****************************************************************************************/ +/****************************************************************************************/ +/** */ +/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */ +/** */ +/****************************************************************************************/ +/****************************************************************************************/ +TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer) +{ + + /* Return semaphore pointer. */ + return((TX_SEMAPHORE *) ((VOID *) pointer)); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer) +{ + + /* Return a VOID pointer. */ + return((VOID *) ((VOID *) pointer)); +} + + +/*********************************************************************************/ +/*********************************************************************************/ +/** */ +/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */ +/** */ +/*********************************************************************************/ +/*********************************************************************************/ +TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value) +{ + + /* Return a thread pointer. */ + return((TX_THREAD *) ((VOID *) value)); +} + + +/***************************************************************************************************/ +/***************************************************************************************************/ +/** */ +/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */ +/** */ +/***************************************************************************************************/ +/***************************************************************************************************/ +VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer) +{ + + /* Return a void pointer. */ + return((VOID *) ((VOID *) pointer)); +} + + +/***************************************************************************************/ +/***************************************************************************************/ +/** */ +/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */ +/** */ +/***************************************************************************************/ +/***************************************************************************************/ +CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer) +{ + + /* Return a CHAR pointer. */ + return((CHAR *) ((VOID *) pointer)); +} + + +/**********************************************************************************/ +/**********************************************************************************/ +/** */ +/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */ +/** */ +/**********************************************************************************/ +/**********************************************************************************/ +TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer) +{ + + /* Return thread pointer. */ + return((TX_THREAD *) ((VOID *) pointer)); +} + + +#ifdef TX_ENABLE_EVENT_TRACE + +/************************************************************************************************/ +/************************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */ +/** */ +/************************************************************************************************/ +/************************************************************************************************/ +UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + + +/************************************************************************************************/ +/************************************************************************************************/ +/** */ +/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */ +/** */ +/************************************************************************************************/ +/************************************************************************************************/ +TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer) +{ + + /* Return an object entry pointer. */ + return((TX_TRACE_OBJECT_ENTRY *) ((VOID *) pointer)); +} + + +/******************************************************************************************/ +/******************************************************************************************/ +/** */ +/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */ +/** */ +/******************************************************************************************/ +/******************************************************************************************/ +TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer) +{ + + /* Return a trace header pointer. */ + return((TX_TRACE_HEADER *) ((VOID *) pointer)); +} + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ +TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer) +{ + + /* Return a trace buffer entry pointer. */ + return((TX_TRACE_BUFFER_ENTRY *) ((VOID *) pointer)); +} + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ +UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + +#endif + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ +UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + + +#endif + diff --git a/common/src/tx_mutex_cleanup.c b/common/src/tx_mutex_cleanup.c new file mode 100644 index 0000000..09acbf4 --- /dev/null +++ b/common/src/tx_mutex_cleanup.c @@ -0,0 +1,316 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_mutex_create.c b/common/src/tx_mutex_create.c new file mode 100644 index 0000000..993bf34 --- /dev/null +++ b/common/src/tx_mutex_create.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_mutex_delete.c b/common/src/tx_mutex_delete.c new file mode 100644 index 0000000..ca5aeca --- /dev/null +++ b/common/src/tx_mutex_delete.c @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_mutex_get.c b/common/src/tx_mutex_get.c new file mode 100644 index 0000000..91e97f1 --- /dev/null +++ b/common/src/tx_mutex_get.c @@ -0,0 +1,410 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_mutex_info_get.c b/common/src/tx_mutex_info_get.c new file mode 100644 index 0000000..219bcc1 --- /dev/null +++ b/common/src/tx_mutex_info_get.c @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_mutex_initialize.c b/common/src/tx_mutex_initialize.c new file mode 100644 index 0000000..ea2ca45 --- /dev/null +++ b/common/src/tx_mutex_initialize.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_mutex_performance_info_get.c b/common/src/tx_mutex_performance_info_get.c new file mode 100644 index 0000000..501a417 --- /dev/null +++ b/common/src/tx_mutex_performance_info_get.c @@ -0,0 +1,231 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* mutex. */ +/* */ +/* INPUT */ +/* */ +/* mutex_ptr Pointer to mutex control block */ +/* puts Destination for the number of */ +/* puts on to this mutex */ +/* gets Destination for the number of */ +/* gets on this mutex */ +/* suspensions Destination for the number of */ +/* suspensions on this mutex */ +/* timeouts Destination for number of timeouts*/ +/* on this mutex */ +/* inversions Destination for number of priority*/ +/* inversions on this mutex */ +/* inheritances Destination for number of priority*/ +/* inheritances on this mutex */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_MUTEX *mutex_ptr, ULONG *puts, ULONG *gets, + ULONG *suspensions, ULONG *timeouts, ULONG *inversions, ULONG *inheritances) +{ + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Determine if this is a legal request. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the mutex ID is invalid. */ + else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Mutex pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PERFORMANCE_INFO_GET, mutex_ptr, 0, 0, 0, TX_TRACE_MUTEX_EVENTS) + + /* Log this kernel call. */ + TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the number of puts on this mutex. */ + if (puts != TX_NULL) + { + + *puts = mutex_ptr -> tx_mutex_performance_put_count; + } + + /* Retrieve the number of gets on this mutex. */ + if (gets != TX_NULL) + { + + *gets = mutex_ptr -> tx_mutex_performance_get_count; + } + + /* Retrieve the number of suspensions on this mutex. */ + if (suspensions != TX_NULL) + { + + *suspensions = mutex_ptr -> tx_mutex_performance_suspension_count; + } + + /* Retrieve the number of timeouts on this mutex. */ + if (timeouts != TX_NULL) + { + + *timeouts = mutex_ptr -> tx_mutex_performance_timeout_count; + } + + /* Retrieve the number of priority inversions on this mutex. */ + if (inversions != TX_NULL) + { + + *inversions = mutex_ptr -> tx_mutex_performance_priority_inversion_count; + } + + /* Retrieve the number of priority inheritances on this mutex. */ + if (inheritances != TX_NULL) + { + + *inheritances = mutex_ptr -> tx_mutex_performance__priority_inheritance_count; + } + + /* Restore interrupts. */ + TX_RESTORE + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (mutex_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (puts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (gets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (inversions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (inheritances != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_mutex_performance_system_info_get.c b/common/src/tx_mutex_performance_system_info_get.c new file mode 100644 index 0000000..9ca1719 --- /dev/null +++ b/common/src/tx_mutex_performance_system_info_get.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves system mutex performance information. */ +/* */ +/* INPUT */ +/* */ +/* puts Destination for total number of */ +/* mutex puts */ +/* gets Destination for total number of */ +/* mutex gets */ +/* suspensions Destination for total number of */ +/* mutex suspensions */ +/* timeouts Destination for total number of */ +/* mutex timeouts */ +/* inversions Destination for total number of */ +/* mutex priority inversions */ +/* inheritances Destination for total number of */ +/* mutex priority inheritances */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *puts, ULONG *gets, ULONG *suspensions, + ULONG *timeouts, ULONG *inversions, ULONG *inheritances) +{ + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_MUTEX_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_MUTEX_EVENTS) + + /* Log this kernel call. */ + TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the total number of mutex puts. */ + if (puts != TX_NULL) + { + + *puts = _tx_mutex_performance_put_count; + } + + /* Retrieve the total number of mutex gets. */ + if (gets != TX_NULL) + { + + *gets = _tx_mutex_performance_get_count; + } + + /* Retrieve the total number of mutex suspensions. */ + if (suspensions != TX_NULL) + { + + *suspensions = _tx_mutex_performance_suspension_count; + } + + /* Retrieve the total number of mutex timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_mutex_performance_timeout_count; + } + + /* Retrieve the total number of mutex priority inversions. */ + if (inversions != TX_NULL) + { + + *inversions = _tx_mutex_performance_priority_inversion_count; + } + + /* Retrieve the total number of mutex priority inheritances. */ + if (inheritances != TX_NULL) + { + + *inheritances = _tx_mutex_performance__priority_inheritance_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (puts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (gets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (inversions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (inheritances != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_mutex_prioritize.c b/common/src/tx_mutex_prioritize.c new file mode 100644 index 0000000..3006b7d --- /dev/null +++ b/common/src/tx_mutex_prioritize.c @@ -0,0 +1,266 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_mutex_priority_change.c b/common/src/tx_mutex_priority_change.c new file mode 100644 index 0000000..4f9679e --- /dev/null +++ b/common/src/tx_mutex_priority_change.c @@ -0,0 +1,338 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 + } +} + diff --git a/common/src/tx_mutex_put.c b/common/src/tx_mutex_put.c new file mode 100644 index 0000000..6ac5065 --- /dev/null +++ b/common/src/tx_mutex_put.c @@ -0,0 +1,655 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_cleanup.c b/common/src/tx_queue_cleanup.c new file mode 100644 index 0000000..82d02f4 --- /dev/null +++ b/common/src/tx_queue_cleanup.c @@ -0,0 +1,226 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_queue_create.c b/common/src/tx_queue_create.c new file mode 100644 index 0000000..00edbad --- /dev/null +++ b/common/src/tx_queue_create.c @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_delete.c b/common/src/tx_queue_delete.c new file mode 100644 index 0000000..9887b16 --- /dev/null +++ b/common/src/tx_queue_delete.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_flush.c b/common/src/tx_queue_flush.c new file mode 100644 index 0000000..5120c89 --- /dev/null +++ b/common/src/tx_queue_flush.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_front_send.c b/common/src/tx_queue_front_send.c new file mode 100644 index 0000000..5e8b410 --- /dev/null +++ b/common/src/tx_queue_front_send.c @@ -0,0 +1,422 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_info_get.c b/common/src/tx_queue_info_get.c new file mode 100644 index 0000000..3b37b37 --- /dev/null +++ b/common/src/tx_queue_info_get.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_initialize.c b/common/src/tx_queue_initialize.c new file mode 100644 index 0000000..7a81123 --- /dev/null +++ b/common/src/tx_queue_initialize.c @@ -0,0 +1,141 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_queue_performance_info_get.c b/common/src/tx_queue_performance_info_get.c new file mode 100644 index 0000000..721a7e5 --- /dev/null +++ b/common/src/tx_queue_performance_info_get.c @@ -0,0 +1,230 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* queue. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block */ +/* messages_sent Destination for messages sent */ +/* messages_received Destination for messages received */ +/* empty_suspensions Destination for number of empty */ +/* queue suspensions */ +/* full_suspensions Destination for number of full */ +/* queue suspensions */ +/* full_errors Destination for queue full errors */ +/* returned - no suspension */ +/* timeouts Destination for number of timeouts*/ +/* on this queue */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_QUEUE *queue_ptr, ULONG *messages_sent, ULONG *messages_received, + ULONG *empty_suspensions, ULONG *full_suspensions, ULONG *full_errors, ULONG *timeouts) +{ + +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Determine if this is a legal request. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the queue ID is invalid. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_PERFORMANCE_INFO_GET, queue_ptr, 0, 0, 0, TX_TRACE_QUEUE_EVENTS) + + /* Log this kernel call. */ + TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the number of messages sent to this queue. */ + if (messages_sent != TX_NULL) + { + + *messages_sent = queue_ptr -> tx_queue_performance_messages_sent_count; + } + + /* Retrieve the number of messages received from this queue. */ + if (messages_received != TX_NULL) + { + + *messages_received = queue_ptr -> tx_queue_performance_messages_received_count; + } + + /* Retrieve the number of empty queue suspensions on this queue. */ + if (empty_suspensions != TX_NULL) + { + + *empty_suspensions = queue_ptr -> tx_queue_performance_empty_suspension_count; + } + + /* Retrieve the number of full queue suspensions on this queue. */ + if (full_suspensions != TX_NULL) + { + + *full_suspensions = queue_ptr -> tx_queue_performance_full_suspension_count; + } + + /* Retrieve the number of full errors (no suspension!) on this queue. */ + if (full_errors != TX_NULL) + { + + *full_errors = queue_ptr -> tx_queue_performance_full_error_count; + } + + /* Retrieve the number of timeouts on this queue. */ + if (timeouts != TX_NULL) + { + + *timeouts = queue_ptr -> tx_queue_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + status = TX_SUCCESS; + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (queue_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (messages_sent != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (messages_received != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (empty_suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (full_suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (full_errors != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_queue_performance_system_info_get.c b/common/src/tx_queue_performance_system_info_get.c new file mode 100644 index 0000000..87cfb4a --- /dev/null +++ b/common/src/tx_queue_performance_system_info_get.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves queue system performance information. */ +/* */ +/* INPUT */ +/* */ +/* messages_sent Destination for total messages */ +/* sent */ +/* messages_received Destination for total messages */ +/* received */ +/* empty_suspensions Destination for total empty */ +/* queue suspensions */ +/* full_suspensions Destination for total full */ +/* queue suspensions */ +/* full_errors Destination for total queue full */ +/* errors returned - no suspension */ +/* timeouts Destination for total number of */ +/* timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *messages_sent, ULONG *messages_received, + ULONG *empty_suspensions, ULONG *full_suspensions, ULONG *full_errors, ULONG *timeouts) +{ + +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_QUEUE_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_QUEUE_EVENTS) + + /* Log this kernel call. */ + TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the total number of queue messages sent. */ + if (messages_sent != TX_NULL) + { + + *messages_sent = _tx_queue_performance_messages_sent_count; + } + + /* Retrieve the total number of queue messages received. */ + if (messages_received != TX_NULL) + { + + *messages_received = _tx_queue_performance__messages_received_count; + } + + /* Retrieve the total number of empty queue suspensions. */ + if (empty_suspensions != TX_NULL) + { + + *empty_suspensions = _tx_queue_performance_empty_suspension_count; + } + + /* Retrieve the total number of full queue suspensions. */ + if (full_suspensions != TX_NULL) + { + + *full_suspensions = _tx_queue_performance_full_suspension_count; + } + + /* Retrieve the total number of full errors. */ + if (full_errors != TX_NULL) + { + + *full_errors = _tx_queue_performance_full_error_count; + } + + /* Retrieve the total number of queue timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_queue_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (messages_sent != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (messages_received != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (empty_suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (full_suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (full_errors != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_queue_prioritize.c b/common/src/tx_queue_prioritize.c new file mode 100644 index 0000000..4f87507 --- /dev/null +++ b/common/src/tx_queue_prioritize.c @@ -0,0 +1,250 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_receive.c b/common/src/tx_queue_receive.c new file mode 100644 index 0000000..31a22f9 --- /dev/null +++ b/common/src/tx_queue_receive.c @@ -0,0 +1,487 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_send.c b/common/src/tx_queue_send.c new file mode 100644 index 0000000..3ca970a --- /dev/null +++ b/common/src/tx_queue_send.c @@ -0,0 +1,427 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_queue_send_notify.c b/common/src/tx_queue_send_notify.c new file mode 100644 index 0000000..f46d153 --- /dev/null +++ b/common/src/tx_queue_send_notify.c @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_semaphore_ceiling_put.c b/common/src/tx_semaphore_ceiling_put.c new file mode 100644 index 0000000..a72b094 --- /dev/null +++ b/common/src/tx_semaphore_ceiling_put.c @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_cleanup.c b/common/src/tx_semaphore_cleanup.c new file mode 100644 index 0000000..512f6c6 --- /dev/null +++ b/common/src/tx_semaphore_cleanup.c @@ -0,0 +1,216 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_semaphore_create.c b/common/src/tx_semaphore_create.c new file mode 100644 index 0000000..3acf3f4 --- /dev/null +++ b/common/src/tx_semaphore_create.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_delete.c b/common/src/tx_semaphore_delete.c new file mode 100644 index 0000000..eee1975 --- /dev/null +++ b/common/src/tx_semaphore_delete.c @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_get.c b/common/src/tx_semaphore_get.c new file mode 100644 index 0000000..5a47199 --- /dev/null +++ b/common/src/tx_semaphore_get.c @@ -0,0 +1,233 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_info_get.c b/common/src/tx_semaphore_info_get.c new file mode 100644 index 0000000..70e98a7 --- /dev/null +++ b/common/src/tx_semaphore_info_get.c @@ -0,0 +1,140 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_initialize.c b/common/src/tx_semaphore_initialize.c new file mode 100644 index 0000000..84358cc --- /dev/null +++ b/common/src/tx_semaphore_initialize.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_semaphore_performance_info_get.c b/common/src/tx_semaphore_performance_info_get.c new file mode 100644 index 0000000..a623705 --- /dev/null +++ b/common/src/tx_semaphore_performance_info_get.c @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* semaphore. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore control block*/ +/* puts Destination for the number of */ +/* puts on to this semaphore */ +/* gets Destination for the number of */ +/* gets on this semaphore */ +/* suspensions Destination for the number of */ +/* suspensions on this semaphore */ +/* timeouts Destination for number of timeouts*/ +/* on this semaphore */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_SEMAPHORE *semaphore_ptr, ULONG *puts, ULONG *gets, + ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Determine if this is a legal request. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the semaphore ID is invalid. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE_PERFORMANCE_INFO_GET, semaphore_ptr, 0, 0, 0, TX_TRACE_SEMAPHORE_EVENTS) + + /* Log this kernel call. */ + TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the number of puts on this semaphore. */ + if (puts != TX_NULL) + { + + *puts = semaphore_ptr -> tx_semaphore_performance_put_count; + } + + /* Retrieve the number of gets on this semaphore. */ + if (gets != TX_NULL) + { + + *gets = semaphore_ptr -> tx_semaphore_performance_get_count; + } + + /* Retrieve the number of suspensions on this semaphore. */ + if (suspensions != TX_NULL) + { + + *suspensions = semaphore_ptr -> tx_semaphore_performance_suspension_count; + } + + /* Retrieve the number of timeouts on this semaphore. */ + if (timeouts != TX_NULL) + { + + *timeouts = semaphore_ptr -> tx_semaphore_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + status = TX_SUCCESS; + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (semaphore_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (puts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (gets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_semaphore_performance_system_info_get.c b/common/src/tx_semaphore_performance_system_info_get.c new file mode 100644 index 0000000..5245d00 --- /dev/null +++ b/common/src/tx_semaphore_performance_system_info_get.c @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves system semaphore performance information. */ +/* */ +/* INPUT */ +/* */ +/* puts Destination for total number of */ +/* semaphore puts */ +/* gets Destination for total number of */ +/* semaphore gets */ +/* suspensions Destination for total number of */ +/* semaphore suspensions */ +/* timeouts Destination for total number of */ +/* timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *puts, ULONG *gets, ULONG *suspensions, ULONG *timeouts) +{ + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_SEMAPHORE__PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_SEMAPHORE_EVENTS) + + /* Log this kernel call. */ + TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve the total number of semaphore puts. */ + if (puts != TX_NULL) + { + + *puts = _tx_semaphore_performance_put_count; + } + + /* Retrieve the total number of semaphore gets. */ + if (gets != TX_NULL) + { + + *gets = _tx_semaphore_performance_get_count; + } + + /* Retrieve the total number of semaphore suspensions. */ + if (suspensions != TX_NULL) + { + + *suspensions = _tx_semaphore_performance_suspension_count; + } + + /* Retrieve the total number of semaphore timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_semaphore_performance_timeout_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (puts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (gets != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_semaphore_prioritize.c b/common/src/tx_semaphore_prioritize.c new file mode 100644 index 0000000..56245df --- /dev/null +++ b/common/src/tx_semaphore_prioritize.c @@ -0,0 +1,252 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_put.c b/common/src/tx_semaphore_put.c new file mode 100644 index 0000000..dacd0db --- /dev/null +++ b/common/src/tx_semaphore_put.c @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_semaphore_put_notify.c b/common/src/tx_semaphore_put_notify.c new file mode 100644 index 0000000..b1abe3b --- /dev/null +++ b/common/src/tx_semaphore_put_notify.c @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_thread_create.c b/common/src/tx_thread_create.c new file mode 100644 index 0000000..2f4d011 --- /dev/null +++ b/common/src/tx_thread_create.c @@ -0,0 +1,390 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_delete.c b/common/src/tx_thread_delete.c new file mode 100644 index 0000000..69626c5 --- /dev/null +++ b/common/src/tx_thread_delete.c @@ -0,0 +1,167 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_entry_exit_notify.c b/common/src/tx_thread_entry_exit_notify.c new file mode 100644 index 0000000..7d5919d --- /dev/null +++ b/common/src/tx_thread_entry_exit_notify.c @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_thread_identify.c b/common/src/tx_thread_identify.c new file mode 100644 index 0000000..7808d05 --- /dev/null +++ b/common/src/tx_thread_identify.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_info_get.c b/common/src/tx_thread_info_get.c new file mode 100644 index 0000000..d906945 --- /dev/null +++ b/common/src/tx_thread_info_get.c @@ -0,0 +1,164 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_initialize.c b/common/src/tx_thread_initialize.c new file mode 100644 index 0000000..11ddcc6 --- /dev/null +++ b/common/src/tx_thread_initialize.c @@ -0,0 +1,455 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 + ; +} + diff --git a/common/src/tx_thread_performance_info_get.c b/common/src/tx_thread_performance_info_get.c new file mode 100644 index 0000000..92c0e02 --- /dev/null +++ b/common/src/tx_thread_performance_info_get.c @@ -0,0 +1,298 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* thread. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control block */ +/* resumptions Destination for number of times */ +/* thread was resumed */ +/* suspensions Destination for number of times */ +/* thread was suspended */ +/* solicited_preemptions Destination for number of times */ +/* thread called another service */ +/* that resulted in preemption */ +/* interrupt_preemptions Destination for number of times */ +/* thread was preempted by another */ +/* thread made ready in Interrupt */ +/* Service Routine (ISR) */ +/* priority_inversions Destination for number of times */ +/* a priority inversion was */ +/* detected for this thread */ +/* time_slices Destination for number of times */ +/* thread was time-sliced */ +/* relinquishes Destination for number of thread */ +/* relinquishes */ +/* timeouts Destination for number of timeouts*/ +/* for thread */ +/* wait_aborts Destination for number of wait */ +/* aborts for thread */ +/* last_preempted_by Destination for pointer of the */ +/* thread that last preempted this */ +/* thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_info_get(TX_THREAD *thread_ptr, ULONG *resumptions, ULONG *suspensions, + ULONG *solicited_preemptions, ULONG *interrupt_preemptions, ULONG *priority_inversions, + ULONG *time_slices, ULONG *relinquishes, ULONG *timeouts, ULONG *wait_aborts, TX_THREAD **last_preempted_by) +{ + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Determine if this is a legal request. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the thread ID is invalid. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PERFORMANCE_INFO_GET, thread_ptr, thread_ptr -> tx_thread_state, 0, 0, TX_TRACE_THREAD_EVENTS) + + /* Log this kernel call. */ + TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve number of resumptions for this thread. */ + if (resumptions != TX_NULL) + { + + *resumptions = thread_ptr -> tx_thread_performance_resume_count; + } + + /* Retrieve number of suspensions for this thread. */ + if (suspensions != TX_NULL) + { + + *suspensions = thread_ptr -> tx_thread_performance_suspend_count; + } + + /* Retrieve number of solicited preemptions for this thread. */ + if (solicited_preemptions != TX_NULL) + { + + *solicited_preemptions = thread_ptr -> tx_thread_performance_solicited_preemption_count; + } + + /* Retrieve number of interrupt preemptions for this thread. */ + if (interrupt_preemptions != TX_NULL) + { + + *interrupt_preemptions = thread_ptr -> tx_thread_performance_interrupt_preemption_count; + } + + /* Retrieve number of priority inversions for this thread. */ + if (priority_inversions != TX_NULL) + { + + *priority_inversions = thread_ptr -> tx_thread_performance_priority_inversion_count; + } + + /* Retrieve number of time-slices for this thread. */ + if (time_slices != TX_NULL) + { + + *time_slices = thread_ptr -> tx_thread_performance_time_slice_count; + } + + /* Retrieve number of relinquishes for this thread. */ + if (relinquishes != TX_NULL) + { + + *relinquishes = thread_ptr -> tx_thread_performance_relinquish_count; + } + + /* Retrieve number of timeouts for this thread. */ + if (timeouts != TX_NULL) + { + + *timeouts = thread_ptr -> tx_thread_performance_timeout_count; + } + + /* Retrieve number of wait aborts for this thread. */ + if (wait_aborts != TX_NULL) + { + + *wait_aborts = thread_ptr -> tx_thread_performance_wait_abort_count; + } + + /* Retrieve the pointer of the last thread that preempted this thread. */ + if (last_preempted_by != TX_NULL) + { + + *last_preempted_by = thread_ptr -> tx_thread_performance_last_preempting_thread; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + status = TX_SUCCESS; + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (thread_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (resumptions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (solicited_preemptions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (interrupt_preemptions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (priority_inversions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (time_slices != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (relinquishes != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (wait_aborts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (last_preempted_by != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_thread_performance_system_info_get.c b/common/src/tx_thread_performance_system_info_get.c new file mode 100644 index 0000000..a6c300a --- /dev/null +++ b/common/src/tx_thread_performance_system_info_get.c @@ -0,0 +1,288 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves thread system performance information. */ +/* */ +/* INPUT */ +/* */ +/* resumptions Destination for total number of */ +/* thread resumptions */ +/* suspensions Destination for total number of */ +/* thread suspensions */ +/* solicited_preemptions Destination for total number of */ +/* thread preemption from thread */ +/* API calls */ +/* interrupt_preemptions Destination for total number of */ +/* thread preemptions as a result */ +/* of threads made ready inside of */ +/* Interrupt Service Routines */ +/* priority_inversions Destination for total number of */ +/* priority inversions */ +/* time_slices Destination for total number of */ +/* time-slices */ +/* relinquishes Destination for total number of */ +/* relinquishes */ +/* timeouts Destination for total number of */ +/* timeouts */ +/* wait_aborts Destination for total number of */ +/* wait aborts */ +/* non_idle_returns Destination for total number of */ +/* times threads return when */ +/* another thread is ready */ +/* idle_returns Destination for total number of */ +/* times threads return when no */ +/* other thread is ready */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_performance_system_info_get(ULONG *resumptions, ULONG *suspensions, + ULONG *solicited_preemptions, ULONG *interrupt_preemptions, ULONG *priority_inversions, + ULONG *time_slices, ULONG *relinquishes, ULONG *timeouts, ULONG *wait_aborts, + ULONG *non_idle_returns, ULONG *idle_returns) +{ + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_THREAD_EVENTS) + + /* Log this kernel call. */ + TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve all the pertinent information and return it in the supplied + destinations. */ + + /* Retrieve total number of thread resumptions. */ + if (resumptions != TX_NULL) + { + + *resumptions = _tx_thread_performance_resume_count; + } + + /* Retrieve total number of thread suspensions. */ + if (suspensions != TX_NULL) + { + + *suspensions = _tx_thread_performance_suspend_count; + } + + /* Retrieve total number of solicited thread preemptions. */ + if (solicited_preemptions != TX_NULL) + { + + *solicited_preemptions = _tx_thread_performance_solicited_preemption_count; + } + + /* Retrieve total number of interrupt thread preemptions. */ + if (interrupt_preemptions != TX_NULL) + { + + *interrupt_preemptions = _tx_thread_performance_interrupt_preemption_count; + } + + /* Retrieve total number of thread priority inversions. */ + if (priority_inversions != TX_NULL) + { + + *priority_inversions = _tx_thread_performance_priority_inversion_count; + } + + /* Retrieve total number of thread time-slices. */ + if (time_slices != TX_NULL) + { + + *time_slices = _tx_thread_performance_time_slice_count; + } + + /* Retrieve total number of thread relinquishes. */ + if (relinquishes != TX_NULL) + { + + *relinquishes = _tx_thread_performance_relinquish_count; + } + + /* Retrieve total number of thread timeouts. */ + if (timeouts != TX_NULL) + { + + *timeouts = _tx_thread_performance_timeout_count; + } + + /* Retrieve total number of thread wait aborts. */ + if (wait_aborts != TX_NULL) + { + + *wait_aborts = _tx_thread_performance_wait_abort_count; + } + + /* Retrieve total number of thread non-idle system returns. */ + if (non_idle_returns != TX_NULL) + { + + *non_idle_returns = _tx_thread_performance_non_idle_return_count; + } + + /* Retrieve total number of thread idle system returns. */ + if (idle_returns != TX_NULL) + { + + *idle_returns = _tx_thread_performance_idle_return_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (resumptions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (suspensions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (solicited_preemptions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (interrupt_preemptions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (priority_inversions != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (time_slices != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (relinquishes != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (timeouts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (wait_aborts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (non_idle_returns != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (idle_returns != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_thread_preemption_change.c b/common/src/tx_thread_preemption_change.c new file mode 100644 index 0000000..cafb579 --- /dev/null +++ b/common/src/tx_thread_preemption_change.c @@ -0,0 +1,281 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_priority_change.c b/common/src/tx_thread_priority_change.c new file mode 100644 index 0000000..9e8da18 --- /dev/null +++ b/common/src/tx_thread_priority_change.c @@ -0,0 +1,286 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_relinquish.c b/common/src/tx_thread_relinquish.c new file mode 100644 index 0000000..6f3a33a --- /dev/null +++ b/common/src/tx_thread_relinquish.c @@ -0,0 +1,170 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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(); + } +} + diff --git a/common/src/tx_thread_reset.c b/common/src/tx_thread_reset.c new file mode 100644 index 0000000..1fea78b --- /dev/null +++ b/common/src/tx_thread_reset.c @@ -0,0 +1,164 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_resume.c b/common/src/tx_thread_resume.c new file mode 100644 index 0000000..b97bdb4 --- /dev/null +++ b/common/src/tx_thread_resume.c @@ -0,0 +1,582 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_shell_entry.c b/common/src/tx_thread_shell_entry.c new file mode 100644 index 0000000..161ea80 --- /dev/null +++ b/common/src/tx_thread_shell_entry.c @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_thread_sleep.c b/common/src/tx_thread_sleep.c new file mode 100644 index 0000000..6d6c92c --- /dev/null +++ b/common/src/tx_thread_sleep.c @@ -0,0 +1,199 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_stack_analyze.c b/common/src/tx_thread_stack_analyze.c new file mode 100644 index 0000000..bdadab0 --- /dev/null +++ b/common/src/tx_thread_stack_analyze.c @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_thread_stack_error_handler.c b/common/src/tx_thread_stack_error_handler.c new file mode 100644 index 0000000..6e2422e --- /dev/null +++ b/common/src/tx_thread_stack_error_handler.c @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_thread_stack_error_notify.c b/common/src/tx_thread_stack_error_notify.c new file mode 100644 index 0000000..796ff46 --- /dev/null +++ b/common/src/tx_thread_stack_error_notify.c @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} diff --git a/common/src/tx_thread_suspend.c b/common/src/tx_thread_suspend.c new file mode 100644 index 0000000..ccf3ebc --- /dev/null +++ b/common/src/tx_thread_suspend.c @@ -0,0 +1,848 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_thread_system_preempt_check.c b/common/src/tx_thread_system_preempt_check.c new file mode 100644 index 0000000..7511a02 --- /dev/null +++ b/common/src/tx_thread_system_preempt_check.c @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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(); + } + } +} + diff --git a/common/src/tx_thread_system_resume.c b/common/src/tx_thread_system_resume.c new file mode 100644 index 0000000..7b9f557 --- /dev/null +++ b/common/src/tx_thread_system_resume.c @@ -0,0 +1,1003 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + +/* Include necessary system files. */ +#include "tx_api.h" +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO +#include "tx_initialize.h" +#endif +#include "tx_trace.h" +#include "tx_timer.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_resume PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the specified thread on the list of ready */ +/* threads at the thread's specific priority. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to resume */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_return Return to the system */ +/* _tx_thread_system_ni_resume Noninterruptable thread resume*/ +/* _tx_timer_system_deactivate Timer deactivate */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Thread create function */ +/* _tx_thread_priority_change Thread priority change */ +/* _tx_thread_resume Application resume service */ +/* _tx_thread_timeout Thread timeout */ +/* _tx_thread_wait_abort Thread wait abort */ +/* Other ThreadX Components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 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_resume(TX_THREAD *thread_ptr) +#ifndef TX_NOT_INTERRUPTABLE +{ + +TX_INTERRUPT_SAVE_AREA + +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 + + /* Lockout interrupts while the thread is being resumed. */ + TX_DISABLE + +#ifndef TX_NO_TIMER + + /* Deactivate the timeout timer if necessary. */ + if (thread_ptr -> tx_thread_timer.tx_timer_internal_list_head != TX_NULL) + { + + /* Deactivate the thread's timeout timer. */ + _tx_timer_system_deactivate(&(thread_ptr -> tx_thread_timer)); + } + else + { + + /* Clear the remaining time to ensure timer doesn't get activated. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((ULONG) 0); + } +#endif + +#ifdef TX_ENABLE_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 + + /* Decrease the preempt disabled count. */ + _tx_thread_preempt_disable--; + + /* Determine if the thread is in the process of suspending. If so, the thread + control block is already on the linked list so nothing needs to be done. */ + if (thread_ptr -> tx_thread_suspending == TX_FALSE) + { + + /* Thread is not in the process of suspending. Now check to make sure the thread + has not already been resumed. */ + if (thread_ptr -> tx_thread_state != TX_READY) + { + + /* No, now check to see if the delayed suspension flag is set. */ + if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE) + { + + /* Resume the thread! */ + + /* 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. */ + +#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; +#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; + } + } + + /* Else, delayed suspend flag was set. */ + else + { + + /* Clear the delayed suspend flag and change the state. */ + thread_ptr -> tx_thread_delayed_suspend = TX_FALSE; + thread_ptr -> tx_thread_state = TX_SUSPENDED; + } + } + } + else + { + + /* A resumption occurred in the middle of a previous thread suspension. */ + + /* Make sure the type of suspension under way is not a terminate or + thread completion. In either of these cases, do not void the + interrupted suspension processing. */ + if (thread_ptr -> tx_thread_state != TX_COMPLETED) + { + + /* Make sure the thread isn't terminated. */ + if (thread_ptr -> tx_thread_state != TX_TERMINATED) + { + + /* No, now check to see if the delayed suspension flag is set. */ + if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE) + { + + /* Clear the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_FALSE; + + /* Restore the state to ready. */ + thread_ptr -> tx_thread_state = TX_READY; + + /* Thread state change. */ + TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY) + + /* Log the thread status change. */ + TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY) + } + else + { + + /* Clear the delayed suspend flag and change the state. */ + thread_ptr -> tx_thread_delayed_suspend = TX_FALSE; + thread_ptr -> tx_thread_state = TX_SUSPENDED; + } + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + + /* Increment the total number of thread resumptions. */ + _tx_thread_performance_resume_count++; + + /* Increment this thread's resume count. */ + thread_ptr -> tx_thread_performance_resume_count++; +#endif + } + } + } + +#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. */ +#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 + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(current_thread) + + /* 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 + + /* 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(); + } + } +} +#else +{ + +TX_INTERRUPT_SAVE_AREA +#ifdef TX_ENABLE_EVENT_TRACE +UINT temp_state; +#endif +UINT state; + + + /* Lockout interrupts while the thread is being resumed. */ + TX_DISABLE + + /* Decrease the preempt disabled count. */ + _tx_thread_preempt_disable--; + + /* Determine if the thread is in the process of suspending. If so, the thread + control block is already on the linked list so nothing needs to be done. */ + if (thread_ptr -> tx_thread_suspending == TX_FALSE) + { + + /* Call the non-interruptable thread system resume function. */ + _tx_thread_system_ni_resume(thread_ptr); + } + else + { + + /* A resumption occurred in the middle of a previous thread suspension. */ + + /* Pickup the current thread state. */ + state = thread_ptr -> tx_thread_state; + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Move the state into a different variable for MISRA compliance. */ + temp_state = state; +#endif + + /* Log the thread status change. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_RESUME, thread_ptr, ((ULONG) state), TX_POINTER_TO_ULONG_CONVERT(&temp_state), TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr), TX_TRACE_INTERNAL_EVENTS) + + /* Make sure the type of suspension under way is not a terminate or + thread completion. In either of these cases, do not void the + interrupted suspension processing. */ + if (state != TX_COMPLETED) + { + + /* Check for terminated thread. */ + if (state != TX_TERMINATED) + { + + /* Clear the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_FALSE; + + /* Restore the state to ready. */ + thread_ptr -> tx_thread_state = TX_READY; + + /* Thread state change. */ + TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY) + + /* Log the thread status change. */ + TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY) + +#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 + } + } + } + + /* Restore interrupts. */ + TX_RESTORE +} + +/* Define the non-interruptable version of thread resume. It is assumed at this point that + all interrupts are disabled and will remain so during this function. */ + +VOID _tx_thread_system_ni_resume(TX_THREAD *thread_ptr) +{ + +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_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, ((ULONG) 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 + + +#ifndef TX_NO_TIMER + + /* Deactivate the timeout timer if necessary. */ + if (thread_ptr -> tx_thread_timer.tx_timer_internal_list_head != TX_NULL) + { + + /* Deactivate the thread's timeout timer. */ + _tx_timer_system_deactivate(&(thread_ptr -> tx_thread_timer)); + } +#endif + +#ifdef TX_ENABLE_STACK_CHECKING + + /* Check this thread's stack. */ + TX_THREAD_STACK_CHECK(thread_ptr) +#endif + + /* Thread is not in the process of suspending. Now check to make sure the thread + has not already been resumed. */ + if (thread_ptr -> tx_thread_state != TX_READY) + { + + /* No, now check to see if the delayed suspension flag is set. */ + if (thread_ptr -> tx_thread_delayed_suspend == TX_FALSE) + { + + /* Resume the thread! */ + + /* Make this thread ready. */ + + /* Change the state to ready. */ + thread_ptr -> tx_thread_state = TX_READY; + + /* Thread state change. */ + TX_THREAD_STATE_CHANGE(thread_ptr, TX_READY) + + /* Log the thread status change. */ + TX_EL_THREAD_STATUS_CHANGE_INSERT(thread_ptr, TX_READY) + + /* Pickup priority of thread. */ + priority = thread_ptr -> tx_thread_priority; + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + + /* Increment the total number of thread resumptions. */ + _tx_thread_performance_resume_count++; + + /* Increment this thread's resume count. */ + thread_ptr -> tx_thread_performance_resume_count++; +#endif + + /* Determine if there are other threads at this priority that are + ready. */ + head_ptr = _tx_thread_priority_list[priority]; + if (head_ptr == TX_NULL) + { + + /* 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 + { + + /* 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. */ + +#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 + +#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; +#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; + } + } + + /* Else, delayed suspend flag was set. */ + else + { + + /* Clear the delayed suspend flag and change the state. */ + thread_ptr -> tx_thread_delayed_suspend = TX_FALSE; + thread_ptr -> tx_thread_state = TX_SUSPENDED; + } + } + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + + /* 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) + { + + /* Does the timestamp match? */ + 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 + + /* 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 diff --git a/common/src/tx_thread_system_suspend.c b/common/src/tx_thread_system_suspend.c new file mode 100644 index 0000000..33f8cac --- /dev/null +++ b/common/src/tx_thread_system_suspend.c @@ -0,0 +1,1219 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_timer.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_suspend PORTABLE C */ +/* 6.1 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends the specified thread and changes the thread */ +/* state to the value specified. Note: delayed suspension processing */ +/* is handled outside of this routine. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to suspend */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_return Return to system */ +/* _tx_thread_system_preempt_check System preemption check */ +/* _tx_timer_system_activate Activate timer for timeout */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_priority_change Thread priority change */ +/* _tx_thread_shell_entry Thread shell function */ +/* _tx_thread_sleep Thread sleep */ +/* _tx_thread_suspend Application thread suspend */ +/* _tx_thread_terminate Thread terminate */ +/* 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_suspend(TX_THREAD *thread_ptr) +#ifndef TX_NOT_INTERRUPTABLE +{ + +TX_INTERRUPT_SAVE_AREA + +UINT priority; +UINT base_priority; +ULONG priority_map; +ULONG priority_bit; +ULONG combined_flags; +TX_THREAD *ready_next; +TX_THREAD *ready_previous; +TX_THREAD *current_thread; + +#if TX_MAX_PRIORITIES > 32 +UINT map_index; +#endif + +#ifndef TX_NO_TIMER +ULONG timeout; +#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 + + /* Is the current thread suspending? */ + if (thread_ptr == current_thread) + { + + /* Pickup the wait option. */ + timeout = thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks; + + /* Determine if an activation is needed. */ + if (timeout != TX_NO_WAIT) + { + + /* Make sure the suspension is not a wait-forever. */ + if (timeout != TX_WAIT_FOREVER) + { + + /* Activate the thread timer with the timeout value setup in the caller. */ + _tx_timer_system_activate(&(thread_ptr -> tx_thread_timer)); + } + } + + /* Yes, reset time slice for current thread. */ + _tx_timer_time_slice = thread_ptr -> tx_thread_new_time_slice; + } +#endif + + /* Decrease the preempt disabled count. */ + _tx_thread_preempt_disable--; + +#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 + + /* Check to make sure the thread suspending flag is still set. If not, it + has already been resumed. */ + if (thread_ptr -> tx_thread_suspending == TX_TRUE) + { + + /* Thread state change. */ + TX_THREAD_STATE_CHANGE(thread_ptr, thread_ptr -> tx_thread_state) + + /* 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, 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 + + /* Actually suspend this thread. But first, clear the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_FALSE; + + /* Pickup priority of thread. */ + priority = thread_ptr -> tx_thread_priority; + + /* Pickup the next ready thread pointer. */ + ready_next = thread_ptr -> tx_thread_ready_next; + + /* 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. */ + + /* Pickup the previous ready thread pointer. */ + ready_previous = thread_ptr -> tx_thread_ready_previous; + + /* 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; +#endif + } + else + { + + /* Other threads at different priority levels are ready to run. */ + + /* 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 + ((UINT) priority_bit); + } + } + + /* Determine if the suspending 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. */ + + /* 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--; + + /* 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 + ((UINT) 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]; + + /* 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 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_ptr); + } + } +#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; +#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(); + } + } + + /* Return to caller. */ + return; +} +#else +/* Define the entry function for modules assuming the interruptable version of system suspend. */ +{ + +TX_INTERRUPT_SAVE_AREA + +ULONG wait_option; + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the thread is still suspending. */ + if (thread_ptr -> tx_thread_suspending == TX_TRUE) + { + + /* Yes, prepare to call the non-interruptable system suspend function. */ + + /* Clear the thread suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_FALSE; + + /* Pickup the wait option. */ + wait_option = thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks; + + /* Decrement the preempt disable count. */ + _tx_thread_preempt_disable--; + + /* Call actual non-interruptable thread suspension routine. */ + _tx_thread_system_ni_suspend(thread_ptr, wait_option); + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); +} + +/* Define the system suspend function that is not interruptable, i.e., it is assumed that + interrupts are disabled upon calling this function. */ + +VOID _tx_thread_system_ni_suspend(TX_THREAD *thread_ptr, ULONG wait_option) +{ + +UINT priority; +UINT base_priority; +ULONG priority_map; +ULONG priority_bit; +ULONG combined_flags; +TX_THREAD *ready_next; +TX_THREAD *ready_previous; +TX_THREAD *current_thread; + +#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) + +#ifndef TX_NO_TIMER + + + /* Determine if a timeout needs to be activated. */ + if (thread_ptr == current_thread) + { + + /* Is there a wait option? */ + if (wait_option != TX_NO_WAIT) + { + + /* Make sure it is not a wait-forever option. */ + if (wait_option != TX_WAIT_FOREVER) + { + + /* Setup the wait option. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Activate the thread timer with the timeout value setup in the caller. */ + _tx_timer_system_activate(&(thread_ptr -> tx_thread_timer)); + } + } + + /* Reset time slice for current thread. */ + _tx_timer_time_slice = thread_ptr -> tx_thread_new_time_slice; + } +#endif + +#ifdef TX_ENABLE_STACK_CHECKING + + /* Check this thread's stack. */ + TX_THREAD_STACK_CHECK(thread_ptr) +#endif + +#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 + + /* Thread state change. */ + TX_THREAD_STATE_CHANGE(thread_ptr, thread_ptr -> tx_thread_state) + + /* 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, 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 next ready thread pointer. */ + ready_next = thread_ptr -> tx_thread_ready_next; + + /* 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. */ + + /* Pickup the previous ready thread pointer. */ + ready_previous = thread_ptr -> tx_thread_ready_previous; + + /* 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 + + /* 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; +#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 + ((UINT) priority_bit); + } + } + + /* Determine if the suspending 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. */ + + /* Disable preemption. */ + _tx_thread_preempt_disable++; + + /* Decrement the preemption disable variable. */ + _tx_thread_preempt_disable--; + + /* 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 + ((UINT) 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]; + + /* 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 = TX_POINTER_TO_ULONG_CONVERT(_tx_thread_execute_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 + + /* 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; +#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 + + /* 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(); + } + } + + /* Return to caller. */ + return; +} +#endif + diff --git a/common/src/tx_thread_terminate.c b/common/src/tx_thread_terminate.c new file mode 100644 index 0000000..1e30687 --- /dev/null +++ b/common/src/tx_thread_terminate.c @@ -0,0 +1,311 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_time_slice.c b/common/src/tx_thread_time_slice.c new file mode 100644 index 0000000..31bc45a --- /dev/null +++ b/common/src/tx_thread_time_slice.c @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_thread_time_slice_change.c b/common/src/tx_thread_time_slice_change.c new file mode 100644 index 0000000..c15c9ae --- /dev/null +++ b/common/src/tx_thread_time_slice_change.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_thread_timeout.c b/common/src/tx_thread_timeout.c new file mode 100644 index 0000000..33ea535 --- /dev/null +++ b/common/src/tx_thread_timeout.c @@ -0,0 +1,166 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 + } +} + diff --git a/common/src/tx_thread_wait_abort.c b/common/src/tx_thread_wait_abort.c new file mode 100644 index 0000000..372a72b --- /dev/null +++ b/common/src/tx_thread_wait_abort.c @@ -0,0 +1,246 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_time_get.c b/common/src/tx_time_get.c new file mode 100644 index 0000000..1636114 --- /dev/null +++ b/common/src/tx_time_get.c @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_time_set.c b/common/src/tx_time_set.c new file mode 100644 index 0000000..613274a --- /dev/null +++ b/common/src/tx_time_set.c @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_timer_activate.c b/common/src/tx_timer_activate.c new file mode 100644 index 0000000..d860957 --- /dev/null +++ b/common/src/tx_timer_activate.c @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_timer_change.c b/common/src/tx_timer_change.c new file mode 100644 index 0000000..420ff26 --- /dev/null +++ b/common/src/tx_timer_change.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_timer_create.c b/common/src/tx_timer_create.c new file mode 100644 index 0000000..707e743 --- /dev/null +++ b/common/src/tx_timer_create.c @@ -0,0 +1,168 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_timer_deactivate.c b/common/src/tx_timer_deactivate.c new file mode 100644 index 0000000..97c786b --- /dev/null +++ b/common/src/tx_timer_deactivate.c @@ -0,0 +1,251 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_timer_delete.c b/common/src/tx_timer_delete.c new file mode 100644 index 0000000..7baef6d --- /dev/null +++ b/common/src/tx_timer_delete.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_timer_expiration_process.c b/common/src/tx_timer_expiration_process.c new file mode 100644 index 0000000..72faed1 --- /dev/null +++ b/common/src/tx_timer_expiration_process.c @@ -0,0 +1,482 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_timer_info_get.c b/common/src/tx_timer_info_get.c new file mode 100644 index 0000000..ca04c4e --- /dev/null +++ b/common/src/tx_timer_info_get.c @@ -0,0 +1,249 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/tx_timer_initialize.c b/common/src/tx_timer_initialize.c new file mode 100644 index 0000000..1ae442d --- /dev/null +++ b/common/src/tx_timer_initialize.c @@ -0,0 +1,305 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 +} + diff --git a/common/src/tx_timer_performance_info_get.c b/common/src/tx_timer_performance_info_get.c new file mode 100644 index 0000000..05e332c --- /dev/null +++ b/common/src/tx_timer_performance_info_get.c @@ -0,0 +1,215 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_performance_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves performance information from the specified */ +/* timer. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control block */ +/* activates Destination for the number of */ +/* activations of this timer */ +/* reactivates Destination for the number of */ +/* reactivations of this timer */ +/* deactivates Destination for the number of */ +/* deactivations of this timer */ +/* expirations Destination for the number of */ +/* expirations of this timer */ +/* expiration_adjusts Destination for the number of */ +/* expiration adjustments of this */ +/* timer */ +/* */ +/* 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_performance_info_get(TX_TIMER *timer_ptr, ULONG *activates, ULONG *reactivates, + ULONG *deactivates, ULONG *expirations, ULONG *expiration_adjusts) +{ + +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA +UINT status; + + + /* Determine if this is a legal request. */ + if (timer_ptr == TX_NULL) + { + + /* Timer pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + + /* Determine if the timer ID is invalid. */ + else if (timer_ptr -> tx_timer_id != TX_TIMER_ID) + { + + /* Timer pointer is illegal, return error. */ + status = TX_PTR_ERROR; + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_PERFORMANCE_INFO_GET, timer_ptr, 0, 0, 0, TX_TRACE_TIMER_EVENTS) + + /* Log this kernel call. */ + TX_EL_TIMER_PERFORMANCE_INFO_GET_INSERT + + /* Retrieve the number of activations of this timer. */ + if (activates != TX_NULL) + { + + *activates = timer_ptr -> tx_timer_performance_activate_count; + } + + /* Retrieve the number of reactivations of this timer. */ + if (reactivates != TX_NULL) + { + + *reactivates = timer_ptr -> tx_timer_performance_reactivate_count; + } + + /* Retrieve the number of deactivations of this timer. */ + if (deactivates != TX_NULL) + { + + *deactivates = timer_ptr -> tx_timer_performance_deactivate_count; + } + + /* Retrieve the number of expirations of this timer. */ + if (expirations != TX_NULL) + { + + *expirations = timer_ptr -> tx_timer_performance_expiration_count; + } + + /* Retrieve the number of expiration adjustments of this timer. */ + if (expiration_adjusts != TX_NULL) + { + + *expiration_adjusts = timer_ptr -> tx_timer_performance__expiration_adjust_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + status = TX_SUCCESS; + } +#else +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (timer_ptr != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (activates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (reactivates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (deactivates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (expirations != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (expiration_adjusts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } +#endif + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/tx_timer_performance_system_info_get.c b/common/src/tx_timer_performance_system_info_get.c new file mode 100644 index 0000000..367e114 --- /dev/null +++ b/common/src/tx_timer_performance_system_info_get.c @@ -0,0 +1,188 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_performance_system_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves timer performance information. */ +/* */ +/* INPUT */ +/* */ +/* activates Destination for total number of */ +/* activations */ +/* reactivates Destination for total number of */ +/* reactivations */ +/* deactivates Destination for total number of */ +/* deactivations */ +/* expirations Destination for total number of */ +/* expirations */ +/* expiration_adjusts Destination for total number of */ +/* expiration adjustments */ +/* */ +/* 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_performance_system_info_get(ULONG *activates, ULONG *reactivates, + ULONG *deactivates, ULONG *expirations, ULONG *expiration_adjusts) +{ + +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_TIMER_PERFORMANCE_SYSTEM_INFO_GET, 0, 0, 0, 0, TX_TRACE_TIMER_EVENTS) + + /* Log this kernel call. */ + TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + /* Retrieve the total number of timer activations. */ + if (activates != TX_NULL) + { + + *activates = _tx_timer_performance_activate_count; + } + + /* Retrieve the total number of timer reactivations. */ + if (reactivates != TX_NULL) + { + + *reactivates = _tx_timer_performance_reactivate_count; + } + + /* Retrieve the total number of timer deactivations. */ + if (deactivates != TX_NULL) + { + + *deactivates = _tx_timer_performance_deactivate_count; + } + + /* Retrieve the total number of timer expirations. */ + if (expirations != TX_NULL) + { + + *expirations = _tx_timer_performance_expiration_count; + } + + /* Retrieve the total number of timer expiration adjustments. */ + if (expiration_adjusts != TX_NULL) + { + + *expiration_adjusts = _tx_timer_performance__expiration_adjust_count; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (activates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (reactivates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (deactivates != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (expirations != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (expiration_adjusts != TX_NULL) + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Not enabled, return error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_timer_system_activate.c b/common/src/tx_timer_system_activate.c new file mode 100644 index 0000000..4c6f7b0 --- /dev/null +++ b/common/src/tx_timer_system_activate.c @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 diff --git a/common/src/tx_timer_system_deactivate.c b/common/src/tx_timer_system_deactivate.c new file mode 100644 index 0000000..487ead9 --- /dev/null +++ b/common/src/tx_timer_system_deactivate.c @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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; + } +} + diff --git a/common/src/tx_timer_thread_entry.c b/common/src/tx_timer_thread_entry.c new file mode 100644 index 0000000..3307423 --- /dev/null +++ b/common/src/tx_timer_thread_entry.c @@ -0,0 +1,481 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 + diff --git a/common/src/tx_trace_buffer_full_notify.c b/common/src/tx_trace_buffer_full_notify.c new file mode 100644 index 0000000..9e07c0a --- /dev/null +++ b/common/src/tx_trace_buffer_full_notify.c @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef TX_SOURCE_CODE +#define TX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_buffer_full_notify PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the application callback function that is */ +/* called whenever the trace buffer becomes full. The application */ +/* can then swap to a new trace buffer in order not to lose any */ +/* events. */ +/* */ +/* INPUT */ +/* */ +/* full_buffer_callback Full trace buffer processing */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* 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_trace_buffer_full_notify(VOID (*full_buffer_callback)(VOID *buffer)) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Setup the callback function pointer. */ + _tx_trace_full_notify_function = full_buffer_callback; + + /* Return success. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (full_buffer_callback != TX_NULL) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_trace_disable.c b/common/src/tx_trace_disable.c new file mode 100644 index 0000000..1ef211e --- /dev/null +++ b/common/src/tx_trace_disable.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_disable PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables trace inside of ThreadX. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* 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_trace_disable(VOID) +{ + +#ifdef TX_ENABLE_EVENT_TRACE +UINT status; + + + /* Determine if trace is already disabled. */ + if (_tx_trace_buffer_current_ptr == TX_NULL) + { + + /* Yes, trace is already disabled. */ + status = TX_NOT_DONE; + } + else + { + + /* Otherwise, simply clear the current pointer and registery start pointer to disable the trace. */ + _tx_trace_buffer_current_ptr = TX_NULL; + _tx_trace_registry_start_ptr = TX_NULL; + + /* Successful completion. */ + status = TX_SUCCESS; + } + + /* Return completion status. */ + return(status); + +#else + + /* Trace not enabled, return an error. */ + return(TX_FEATURE_NOT_ENABLED); +#endif +} + diff --git a/common/src/tx_trace_enable.c b/common/src/tx_trace_enable.c new file mode 100644 index 0000000..aa372e8 --- /dev/null +++ b/common/src/tx_trace_enable.c @@ -0,0 +1,443 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_event_flags.h" +#include "tx_queue.h" +#include "tx_semaphore.h" +#include "tx_mutex.h" +#include "tx_block_pool.h" +#include "tx_byte_pool.h" +#endif +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_enable PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the ThreadX trace buffer and the */ +/* associated control variables, enabling it for operation. */ +/* */ +/* INPUT */ +/* */ +/* trace_buffer_start Start of trace buffer */ +/* trace_buffer_size Size (bytes) of trace buffer */ +/* registry_entries Number of object registry */ +/* entries. */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* _tx_trace_object_register Register existing objects */ +/* */ +/* 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_trace_enable(VOID *trace_buffer_start, ULONG trace_buffer_size, ULONG registry_entries) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; +TX_TIMER *timer_ptr; +TX_EVENT_FLAGS_GROUP *event_flags_ptr; +TX_QUEUE *queue_ptr; +TX_SEMAPHORE *semaphore_ptr; +TX_MUTEX *mutex_ptr; +TX_BLOCK_POOL *block_pool_ptr; +TX_BYTE_POOL *byte_pool_ptr; +UCHAR *work_ptr; +UCHAR *event_start_ptr; +TX_TRACE_OBJECT_ENTRY *entry_ptr; +TX_TRACE_BUFFER_ENTRY *event_ptr; +ULONG i; +UINT status; + + + /* First, see if there is enough room for the control header, the registry entries, and at least one event in + memory supplied to this call. */ + if (trace_buffer_size < ((sizeof(TX_TRACE_HEADER)) + ((sizeof(TX_TRACE_OBJECT_ENTRY)) * registry_entries) + (sizeof(TX_TRACE_BUFFER_ENTRY)))) + { + + /* No, the memory isn't big enough to hold one trace buffer entry. Return an error. */ + status = TX_SIZE_ERROR; + } + + /* Determine if trace is already enabled. */ + else if (_tx_trace_buffer_current_ptr != TX_NULL) + { + + /* Yes, trace is already enabled. */ + status = TX_NOT_DONE; + } + else + { + + /* Set the enable bits for all events enabled. */ + _tx_trace_event_enable_bits = 0xFFFFFFFFUL; + + /* Setup working pointer to the supplied memory. */ + work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(trace_buffer_start); + + /* Setup pointer to the trace control area. */ + _tx_trace_header_ptr = TX_UCHAR_TO_HEADER_POINTER_CONVERT(work_ptr); + + /* Move the working pointer past the control area. */ + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(TX_TRACE_HEADER))); + + /* Save the start of the trace object registry. */ + _tx_trace_registry_start_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + /* Setup the end of the trace object registry. */ + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(TX_TRACE_OBJECT_ENTRY))*registry_entries); + _tx_trace_registry_end_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + /* Loop to make all trace object registry entries empty and valid. */ + for (i = ((ULONG) 0); i < registry_entries; i++) + { + + /* Setup the work pointer. */ + work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (sizeof(TX_TRACE_OBJECT_ENTRY))*i); + + /* Convert to a registry entry pointer. */ + entry_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + /* Initialize object registry entry. */ + entry_ptr -> tx_trace_object_entry_available = (UCHAR) TX_TRUE; + entry_ptr -> tx_trace_object_entry_type = (UCHAR) TX_TRACE_OBJECT_TYPE_NOT_VALID; + entry_ptr -> tx_trace_object_entry_reserved1 = (UCHAR) 0; + entry_ptr -> tx_trace_object_entry_reserved2 = (UCHAR) 0; + entry_ptr -> tx_trace_object_entry_thread_pointer = (ULONG) 0; + } + + /* Setup the total number of registry entries. */ + _tx_trace_total_registry_entries = registry_entries; + + /* Setup the object registry available count to the total number of registry entries. */ + _tx_trace_available_registry_entries = registry_entries; + + /* Setup the search starting index to the first entry. */ + _tx_trace_registry_search_start = ((ULONG) 0); + + /* Setup the work pointer to after the trace object registry. */ + work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_end_ptr); + + /* Adjust the remaining trace buffer size. */ + trace_buffer_size = trace_buffer_size - ((sizeof(TX_TRACE_OBJECT_ENTRY)) * registry_entries) - (sizeof(TX_TRACE_HEADER)); + + /* Setup pointer to the start of the actual event trace log. */ + _tx_trace_buffer_start_ptr = TX_UCHAR_TO_ENTRY_POINTER_CONVERT(work_ptr); + + /* Save the event trace log start address. */ + event_start_ptr = work_ptr; + + /* Calculate the end of the trace buffer. */ + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, ((trace_buffer_size/(sizeof(TX_TRACE_BUFFER_ENTRY)))*(sizeof(TX_TRACE_BUFFER_ENTRY)))); + _tx_trace_buffer_end_ptr = TX_UCHAR_TO_ENTRY_POINTER_CONVERT(work_ptr); + + /* Loop to mark all entries in the trace buffer as invalid. */ + for (i = ((ULONG) 0); i < (trace_buffer_size/(sizeof(TX_TRACE_BUFFER_ENTRY))); i++) + { + + /* Setup the work pointer. */ + work_ptr = TX_UCHAR_POINTER_ADD(event_start_ptr, (sizeof(TX_TRACE_BUFFER_ENTRY))*i); + + /* Convert to a trace event pointer. */ + event_ptr = TX_UCHAR_TO_ENTRY_POINTER_CONVERT(work_ptr); + + /* Mark this trace event as invalid. */ + event_ptr -> tx_trace_buffer_entry_thread_pointer = ((ULONG) 0); + } + + /* Now, fill in the event trace control header. */ + _tx_trace_header_ptr -> tx_trace_header_id = TX_TRACE_VALID; + _tx_trace_header_ptr -> tx_trace_header_timer_valid_mask = TX_TRACE_TIME_MASK; + _tx_trace_header_ptr -> tx_trace_header_trace_base_address = TX_POINTER_TO_ULONG_CONVERT(trace_buffer_start); + _tx_trace_header_ptr -> tx_trace_header_registry_start_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_registry_start_ptr); + _tx_trace_header_ptr -> tx_trace_header_reserved1 = ((USHORT) 0); + _tx_trace_header_ptr -> tx_trace_header_object_name_size = ((USHORT) TX_TRACE_OBJECT_REGISTRY_NAME); + _tx_trace_header_ptr -> tx_trace_header_registry_end_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_registry_end_ptr); + _tx_trace_header_ptr -> tx_trace_header_buffer_start_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_buffer_start_ptr); + _tx_trace_header_ptr -> tx_trace_header_buffer_end_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_buffer_end_ptr); + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = TX_POINTER_TO_ULONG_CONVERT(_tx_trace_buffer_start_ptr); + _tx_trace_header_ptr -> tx_trace_header_reserved2 = 0xAAAAAAAAUL; + _tx_trace_header_ptr -> tx_trace_header_reserved3 = 0xBBBBBBBBUL; + _tx_trace_header_ptr -> tx_trace_header_reserved4 = 0xCCCCCCCCUL; + + /* Now, loop through all existing ThreadX objects and register them in the newly setup trace buffer. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* First, disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Pickup the first thread and the number of created threads. */ + thread_ptr = _tx_thread_created_ptr; + i = _tx_thread_created_count; + + /* Loop to register all threads. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this thread. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_THREAD, thread_ptr, thread_ptr -> tx_thread_name, + TX_POINTER_TO_ULONG_CONVERT(thread_ptr -> tx_thread_stack_start), (ULONG) thread_ptr -> tx_thread_stack_size); + + /* Move to the next thread. */ + thread_ptr = thread_ptr -> tx_thread_created_next; + } + + /* Pickup the first timer and the number of created timers. */ + timer_ptr = _tx_timer_created_ptr; + i = _tx_timer_created_count; + + /* Loop to register all timers. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this timer. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_TIMER, timer_ptr, timer_ptr -> tx_timer_name, + ((ULONG) 0), timer_ptr -> tx_timer_internal.tx_timer_internal_re_initialize_ticks); + + /* Move to the next timer. */ + timer_ptr = timer_ptr -> tx_timer_created_next; + } + + + /* Pickup the first event flag group and the number of created groups. */ + event_flags_ptr = _tx_event_flags_created_ptr; + i = _tx_event_flags_created_count; + + /* Loop to register all event flags groups. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this event flags group. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_EVENT_FLAGS, event_flags_ptr, event_flags_ptr -> tx_event_flags_group_name, ((ULONG) 0), ((ULONG) 0)); + + /* Move to the next event flags group. */ + event_flags_ptr = event_flags_ptr -> tx_event_flags_group_created_next; + } + + /* Pickup the first queue and the number of created queues. */ + queue_ptr = _tx_queue_created_ptr; + i = _tx_queue_created_count; + + /* Loop to register all queues. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this queue. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_QUEUE, queue_ptr, queue_ptr -> tx_queue_name, + (queue_ptr -> tx_queue_capacity * (sizeof(ULONG))), ((ULONG) 0)); + + /* Move to the next queue. */ + queue_ptr = queue_ptr -> tx_queue_created_next; + } + + /* Pickup the first semaphore and the number of created semaphores. */ + semaphore_ptr = _tx_semaphore_created_ptr; + i = _tx_semaphore_created_count; + + /* Loop to register all semaphores. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this semaphore. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_SEMAPHORE, semaphore_ptr, semaphore_ptr -> tx_semaphore_name, ((ULONG) 0), ((ULONG) 0)); + + /* Move to the next semaphore. */ + semaphore_ptr = semaphore_ptr -> tx_semaphore_created_next; + } + + /* Pickup the first mutex and the number of created mutexes. */ + mutex_ptr = _tx_mutex_created_ptr; + i = _tx_mutex_created_count; + + /* Loop to register all mutexes. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this mutex. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_MUTEX, mutex_ptr, mutex_ptr -> tx_mutex_name, + (ULONG) mutex_ptr -> tx_mutex_inherit, ((ULONG) 0)); + + /* Move to the next mutex. */ + mutex_ptr = mutex_ptr -> tx_mutex_created_next; + } + + /* Pickup the first block pool and the number of created block pools. */ + block_pool_ptr = _tx_block_pool_created_ptr; + i = _tx_block_pool_created_count; + + /* Loop to register all block pools. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this block pool. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_BLOCK_POOL, block_pool_ptr, block_pool_ptr -> tx_block_pool_name, + block_pool_ptr -> tx_block_pool_size, ((ULONG) 0)); + + /* Move to the next block pool. */ + block_pool_ptr = block_pool_ptr -> tx_block_pool_created_next; + } + + /* Pickup the first byte pool and the number of created byte pools. */ + byte_pool_ptr = _tx_byte_pool_created_ptr; + i = _tx_byte_pool_created_count; + + /* Loop to register all byte pools. */ + while (i != ((ULONG) 0)) + { + + /* Decrement the counter. */ + i--; + + /* Register this byte pool. */ + _tx_trace_object_register(TX_TRACE_OBJECT_TYPE_BYTE_POOL, byte_pool_ptr, byte_pool_ptr -> tx_byte_pool_name, + byte_pool_ptr -> tx_byte_pool_size, ((ULONG) 0)); + + /* Move to the next byte pool. */ + byte_pool_ptr = byte_pool_ptr -> tx_byte_pool_created_next; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Release the preeemption. */ + _tx_thread_preempt_disable--; + + /* Finally, setup the current buffer pointer, which effectively enables the trace! */ + _tx_trace_buffer_current_ptr = (TX_TRACE_BUFFER_ENTRY *) _tx_trace_buffer_start_ptr; + + /* Insert two RUNNING events so the buffer is not empty. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_RUNNING, 0, 0, 0, 0, TX_TRACE_INTERNAL_EVENTS) + TX_TRACE_IN_LINE_INSERT(TX_TRACE_RUNNING, 0, 0, 0, 0, TX_TRACE_INTERNAL_EVENTS) + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Return successful completion. */ + status = TX_SUCCESS; + } + + /* Return completion status. */ + return(status); +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (trace_buffer_start != TX_NULL) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (trace_buffer_size == ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (registry_entries == ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + + + diff --git a/common/src/tx_trace_event_filter.c b/common/src/tx_trace_event_filter.c new file mode 100644 index 0000000..3afb8ed --- /dev/null +++ b/common/src/tx_trace_event_filter.c @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef TX_SOURCE_CODE +#define TX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_event_filter PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the event filter, which allows the */ +/* application to filter various trace events during run-time. */ +/* */ +/* INPUT */ +/* */ +/* event_filter_bits Trace filter event bit(s) */ +/* */ +/* OUTPUT */ +/* */ +/* 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_trace_event_filter(ULONG event_filter_bits) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Apply the specified filter by clearing the enable bits. */ + _tx_trace_event_enable_bits = _tx_trace_event_enable_bits & (~event_filter_bits); + + /* Return success. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (event_filter_bits != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_trace_event_unfilter.c b/common/src/tx_trace_event_unfilter.c new file mode 100644 index 0000000..f9d054d --- /dev/null +++ b/common/src/tx_trace_event_unfilter.c @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef TX_SOURCE_CODE +#define TX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_event_unfilter PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes the event filter, which allows the */ +/* application to un-filter various trace events during run-time. */ +/* */ +/* INPUT */ +/* */ +/* event_unfilter_bits Trace un-filter event bit(s) */ +/* */ +/* OUTPUT */ +/* */ +/* 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_trace_event_unfilter(ULONG event_unfilter_bits) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Make sure the specified bits are set in the event enable variable. */ + _tx_trace_event_enable_bits = _tx_trace_event_enable_bits | event_unfilter_bits; + + /* Return success. */ + return(TX_SUCCESS); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (event_unfilter_bits != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/tx_trace_initialize.c b/common/src/tx_trace_initialize.c new file mode 100644 index 0000000..14877b9 --- /dev/null +++ b/common/src/tx_trace_initialize.c @@ -0,0 +1,153 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#ifdef TX_ENABLE_EVENT_TRACE + + +/* Define the pointer to the start of the trace buffer control structure. */ + +TX_TRACE_HEADER *_tx_trace_header_ptr; + + +/* Define the pointer to the start of the trace object registry area in the trace buffer. */ + +TX_TRACE_OBJECT_ENTRY *_tx_trace_registry_start_ptr; + + +/* Define the pointer to the end of the trace object registry area in the trace buffer. */ + +TX_TRACE_OBJECT_ENTRY *_tx_trace_registry_end_ptr; + + +/* Define the pointer to the starting entry of the actual trace event area of the trace buffer. */ + +TX_TRACE_BUFFER_ENTRY *_tx_trace_buffer_start_ptr; + + +/* Define the pointer to the ending entry of the actual trace event area of the trace buffer. */ + +TX_TRACE_BUFFER_ENTRY *_tx_trace_buffer_end_ptr; + + +/* Define the pointer to the current entry of the actual trace event area of the trace buffer. */ + +TX_TRACE_BUFFER_ENTRY *_tx_trace_buffer_current_ptr; + + +/* Define the trace event enable bits, where each bit represents a type of event that can be enabled + or disabled dynamically by the application. */ + +ULONG _tx_trace_event_enable_bits; + + +/* Define a counter that is used in environments that don't have a timer source. This counter + is incremented on each use giving each event a unique timestamp. */ + +ULONG _tx_trace_simulated_time; + + +/* Define the function pointer used to call the application when the trace buffer wraps. If NULL, + the application has not registered a callback function. */ + +VOID (*_tx_trace_full_notify_function)(VOID *buffer); + + +/* Define the total number of registry entries. */ + +ULONG _tx_trace_total_registry_entries; + + +/* Define a counter that is used to track the number of available registry entries. */ + +ULONG _tx_trace_available_registry_entries; + + +/* Define an index that represents the start of the registry search. */ + +ULONG _tx_trace_registry_search_start; + +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_initialize PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the various control data structures for */ +/* the trace 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 */ +/* */ +/**************************************************************************/ +VOID _tx_trace_initialize(VOID) +{ + +#ifdef TX_ENABLE_EVENT_TRACE +#ifndef TX_DISABLE_REDUNDANT_CLEARING + + /* Initialize all the pointers to the trace buffer to NULL. */ + _tx_trace_header_ptr = TX_NULL; + _tx_trace_registry_start_ptr = TX_NULL; + _tx_trace_registry_end_ptr = TX_NULL; + _tx_trace_buffer_start_ptr = TX_NULL; + _tx_trace_buffer_end_ptr = TX_NULL; + _tx_trace_buffer_current_ptr = TX_NULL; +#endif +#endif +} + diff --git a/common/src/tx_trace_interrupt_control.c b/common/src/tx_trace_interrupt_control.c new file mode 100644 index 0000000..595dff7 --- /dev/null +++ b/common/src/tx_trace_interrupt_control.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_interrupt_control PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function provides a shell for the tx_interrupt_control */ +/* function so that a trace event can be logged for its use. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* Previous Interrupt Posture */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_interrupt_control Interrupt control 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 _tx_trace_interrupt_control(UINT new_posture) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + +TX_INTERRUPT_SAVE_AREA +UINT saved_posture; + + /* Disable interrupts. */ + TX_DISABLE + + /* Insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_INTERRUPT_CONTROL, TX_ULONG_TO_POINTER_CONVERT(new_posture), TX_POINTER_TO_ULONG_CONVERT(&saved_posture), 0, 0, TX_TRACE_INTERRUPT_CONTROL_EVENT) + + /* Restore interrupts. */ + TX_RESTORE + + /* Perform the interrupt service. */ + saved_posture = _tx_thread_interrupt_control(new_posture); + + /* Return saved posture. */ + return(saved_posture); +#else + +UINT saved_posture; + + /* Perform the interrupt service. */ + saved_posture = _tx_thread_interrupt_control(new_posture); + + /* Return saved posture. */ + return(saved_posture); +#endif +} + diff --git a/common/src/tx_trace_isr_enter_insert.c b/common/src/tx_trace_isr_enter_insert.c new file mode 100644 index 0000000..628cc8f --- /dev/null +++ b/common/src/tx_trace_isr_enter_insert.c @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_thread.h" +#endif +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_isr_enter_insert PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function provides inserts an ISR entry event into the trace */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* isr_id User defined ISR ID */ +/* */ +/* 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_trace_isr_enter_insert(ULONG isr_id) +{ + +TX_INTERRUPT_SAVE_AREA + + +#ifdef TX_ENABLE_EVENT_TRACE + +UINT stack_address; +ULONG system_state; +UINT preempt_disable; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Insert this event into the trace buffer. */ + system_state = TX_THREAD_GET_SYSTEM_STATE(); + preempt_disable = _tx_thread_preempt_disable; + TX_TRACE_IN_LINE_INSERT(TX_TRACE_ISR_ENTER, &stack_address, isr_id, system_state, preempt_disable, TX_TRACE_INTERNAL_EVENTS) + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (isr_id != ((ULONG) 0)) + { + + /* NOP code. */ + TX_DISABLE + TX_RESTORE + } +#endif +} + diff --git a/common/src/tx_trace_isr_exit_insert.c b/common/src/tx_trace_isr_exit_insert.c new file mode 100644 index 0000000..0d743c1 --- /dev/null +++ b/common/src/tx_trace_isr_exit_insert.c @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_thread.h" +#endif +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_isr_exit_insert PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function provides inserts an ISR exit event into the trace */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* isr_id User defined ISR ID */ +/* */ +/* 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_trace_isr_exit_insert(ULONG isr_id) +{ + +TX_INTERRUPT_SAVE_AREA + + +#ifdef TX_ENABLE_EVENT_TRACE + +UINT stack_address; +ULONG system_state; +UINT preempt_disable; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Insert this event into the trace buffer. */ + system_state = TX_THREAD_GET_SYSTEM_STATE(); + preempt_disable = _tx_thread_preempt_disable; + TX_TRACE_IN_LINE_INSERT(TX_TRACE_ISR_EXIT, &stack_address, isr_id, system_state, preempt_disable, TX_TRACE_INTERNAL_EVENTS) + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (isr_id != ((ULONG) 0)) + { + + /* NOP code. */ + TX_DISABLE + TX_RESTORE + } +#endif +} + diff --git a/common/src/tx_trace_object_register.c b/common/src/tx_trace_object_register.c new file mode 100644 index 0000000..0805063 --- /dev/null +++ b/common/src/tx_trace_object_register.c @@ -0,0 +1,301 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_object_register PORTABLE C */ +/* 6.1.12 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers a ThreadX system object in the trace */ +/* registry area. This provides a mapping between the object pointers */ +/* stored in each trace event to the actual ThreadX objects. */ +/* */ +/* INPUT */ +/* */ +/* object_type Type of system object */ +/* object_ptr Address of system object */ +/* object_name Name of system object */ +/* parameter_1 Supplemental parameter 1 */ +/* parameter_2 Supplemental parameter 2 */ +/* */ +/* 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 */ +/* 07-29-2022 Scott Larson Modified comment(s), */ +/* check for null name, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ +VOID _tx_trace_object_register(UCHAR object_type, VOID *object_ptr, CHAR *object_name, ULONG parameter_1, ULONG parameter_2) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + +UINT i, entries; +UINT found, loop_break; +TX_THREAD *thread_ptr; +UCHAR *work_ptr; +TX_TRACE_OBJECT_ENTRY *entry_ptr; + + + /* Determine if the registry area is setup. */ + if (_tx_trace_registry_start_ptr != TX_NULL) + { + + /* Trace buffer is enabled, proceed. */ + + /* Pickup the total entries. */ + entries = _tx_trace_total_registry_entries; + + /* Determine if there are available entries in the registry. */ + if (_tx_trace_available_registry_entries != ((ULONG) 0)) + { + + /* There are more available entries, proceed. */ + + /* Initialize found to the max entries... indicating no space was found. */ + found = entries; + loop_break = TX_FALSE; + + /* Loop to find available entry. */ + i = _tx_trace_registry_search_start; + do + { + + /* Setup the registry entry pointer. */ + work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*i)); + entry_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + /* Determine if this is the first pass building the registry. A NULL object value indicates this part + of the registry has never been used. */ + if (entry_ptr -> tx_trace_object_entry_thread_pointer == (ULONG) 0) + { + + /* Set found to this index and break out of the loop. */ + found = i; + loop_break = TX_TRUE; + } + + /* Determine if this entry matches the object pointer... we must reuse old entries left in the + registry. */ + if (entry_ptr -> tx_trace_object_entry_thread_pointer == TX_POINTER_TO_ULONG_CONVERT(object_ptr)) + { + + /* Set found to this index and break out of the loop. */ + found = i; + loop_break = TX_TRUE; + } + + /* Determine if we should break out of the loop. */ + if (loop_break == TX_TRUE) + { + + /* Yes, break out of the loop. */ + break; + } + + /* Is this entry available? */ + if (entry_ptr -> tx_trace_object_entry_available == TX_TRUE) + { + + /* Yes, determine if we have not already found an empty slot. */ + if (found == entries) + { + found = i; + } + else + { + + /* Setup a pointer to the found entry. */ + work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*found)); + entry_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + if (entry_ptr -> tx_trace_object_entry_type != ((UCHAR) 0)) + { + found = i; + } + } + } + + /* Move to the next entry. */ + i++; + + /* Determine if we have wrapped the list. */ + if (i >= entries) + { + + /* Yes, wrap to the beginning of the list. */ + i = ((ULONG) 0); + } + + } while (i != _tx_trace_registry_search_start); + + /* Now determine if an empty or reuse entry has been found. */ + if (found < entries) + { + + /* Decrement the number of available entries. */ + _tx_trace_available_registry_entries--; + + /* Adjust the search index to the next entry. */ + if ((found + ((ULONG) 1)) < entries) + { + + /* Start searching from the next index. */ + _tx_trace_registry_search_start = found + ((ULONG) 1); + } + else + { + + /* Reset the search to the beginning of the list. */ + _tx_trace_registry_search_start = ((ULONG) 0); + } + + /* Yes, an entry has been found... */ + + /* Build a pointer to the found entry. */ + work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*found)); + entry_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + /* Populate the found entry! */ + entry_ptr -> tx_trace_object_entry_available = ((UCHAR) TX_FALSE); + entry_ptr -> tx_trace_object_entry_type = object_type; + entry_ptr -> tx_trace_object_entry_thread_pointer = TX_POINTER_TO_ULONG_CONVERT(object_ptr); + entry_ptr -> tx_trace_object_entry_param_1 = parameter_1; + entry_ptr -> tx_trace_object_entry_param_2 = parameter_2; + + /* Loop to copy the object name string... */ + for (i = ((ULONG) 0); i < (((ULONG) TX_TRACE_OBJECT_REGISTRY_NAME)-((ULONG) 1)); i++) + { + + /* Setup work pointer to the object name character. */ + work_ptr = TX_CHAR_TO_UCHAR_POINTER_CONVERT(object_name); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, i); + + /* Determine if object_name (work_ptr) is null. */ + if (work_ptr == TX_NULL) + { + break; + } + + /* Copy a character of the name. */ + entry_ptr -> tx_trace_object_entry_name[i] = (UCHAR) *work_ptr; + + /* Determine if we are at the end. */ + if (*work_ptr == ((UCHAR) 0)) + { + break; + } + } + + /* Null terminate the object string. */ + entry_ptr -> tx_trace_object_entry_name[i] = (UCHAR) 0; + + /* Determine if a thread object type is present. */ + if (object_type == TX_TRACE_OBJECT_TYPE_THREAD) + { + + /* Yes, a thread object is present. */ + + /* Setup a pointer to the thread. */ + thread_ptr = TX_VOID_TO_THREAD_POINTER_CONVERT(object_ptr); + + /* Store the thread's priority in the reserved bits. */ + entry_ptr -> tx_trace_object_entry_reserved1 = ((UCHAR) 0x80) | ((UCHAR) (thread_ptr -> tx_thread_priority >> ((UCHAR) 8))); + entry_ptr -> tx_trace_object_entry_reserved2 = (UCHAR) (thread_ptr -> tx_thread_priority & ((UCHAR) 0xFF)); + } + else + { + + /* For all other objects, set the reserved bytes to 0. */ + entry_ptr -> tx_trace_object_entry_reserved1 = ((UCHAR) 0); + entry_ptr -> tx_trace_object_entry_reserved2 = ((UCHAR) 0); + } + } + } + } +#else + +TX_INTERRUPT_SAVE_AREA + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (object_type != ((UCHAR) 0)) + { + + if (object_ptr != TX_NULL) + { + + if (object_name != TX_NULL) + { + + if (parameter_1 != ((ULONG) 0)) + { + + if (parameter_2 != ((ULONG) 0)) + { + + /* NOP code. */ + TX_DISABLE + TX_RESTORE + } + } + } + } + } +#endif +} + diff --git a/common/src/tx_trace_object_unregister.c b/common/src/tx_trace_object_unregister.c new file mode 100644 index 0000000..a7fef27 --- /dev/null +++ b/common/src/tx_trace_object_unregister.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_object_unregister PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unregisters a ThreadX system object from the trace */ +/* registry area. */ +/* */ +/* INPUT */ +/* */ +/* object_pointer Address of system object */ +/* */ +/* 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_trace_object_unregister(VOID *object_ptr) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + +UINT i, entries; +UCHAR *work_ptr; +TX_TRACE_OBJECT_ENTRY *entry_ptr; + + + /* Determine if the registry area is setup. */ + if (_tx_trace_registry_start_ptr != TX_NULL) + { + + /* Registry is setup, proceed. */ + + /* Pickup the total entries. */ + entries = _tx_trace_total_registry_entries; + + /* Loop to find available entry. */ + for (i = ((ULONG) 0); i < entries; i++) + { + + /* Setup the registry entry pointer. */ + work_ptr = TX_OBJECT_TO_UCHAR_POINTER_CONVERT(_tx_trace_registry_start_ptr); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, ((sizeof(TX_TRACE_OBJECT_ENTRY))*i)); + entry_ptr = TX_UCHAR_TO_OBJECT_POINTER_CONVERT(work_ptr); + + /* Determine if this entry matches the object pointer... */ + if (entry_ptr -> tx_trace_object_entry_thread_pointer == TX_POINTER_TO_ULONG_CONVERT(object_ptr)) + { + + /* Mark this entry as available, but leave the other information so that old trace entries can + still find it - if necessary! */ + entry_ptr -> tx_trace_object_entry_available = ((UCHAR) TX_TRUE); + + /* Increment the number of available registry entries. */ + _tx_trace_available_registry_entries++; + + /* Adjust the search index to this position. */ + _tx_trace_registry_search_start = i; + + break; + } + } + } +#else + +TX_INTERRUPT_SAVE_AREA + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (object_ptr != TX_NULL) + { + + /* NOP code. */ + TX_DISABLE + TX_RESTORE + } +#endif +} + diff --git a/common/src/tx_trace_user_event_insert.c b/common/src/tx_trace_user_event_insert.c new file mode 100644 index 0000000..fda0961 --- /dev/null +++ b/common/src/tx_trace_user_event_insert.c @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_trace_user_event_insert PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a user-defined event into the trace buffer. */ +/* */ +/* INPUT */ +/* */ +/* event_id User Event ID */ +/* info_field_1 First information field */ +/* info_field_2 First information field */ +/* info_field_3 First information field */ +/* info_field_4 First information field */ +/* */ +/* OUTPUT */ +/* */ +/* 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_trace_user_event_insert(ULONG event_id, ULONG info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4) +{ + +#ifdef TX_ENABLE_EVENT_TRACE + +TX_INTERRUPT_SAVE_AREA + +UINT status; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if trace is disabled. */ + if (_tx_trace_buffer_current_ptr == TX_NULL) + { + + /* Yes, trace is already disabled. */ + status = TX_NOT_DONE; + } + else + { + + /* Insert this event into the trace buffer. */ +#ifdef TX_MISRA_ENABLE + TX_TRACE_IN_LINE_INSERT(event_id, TX_ULONG_TO_POINTER_CONVERT(info_field_1), info_field_2, info_field_3, info_field_4, ((ULONG) TX_TRACE_USER_EVENTS)) +#else + TX_TRACE_IN_LINE_INSERT(event_id, info_field_1, info_field_2, info_field_3, info_field_4, TX_TRACE_USER_EVENTS) +#endif + + /* Return successful status. */ + status = TX_SUCCESS; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(status); + +#else + +UINT status; + + + /* Access input arguments just for the sake of lint, MISRA, etc. */ + if (event_id != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (info_field_1 != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (info_field_2 != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (info_field_3 != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else if (info_field_4 != ((ULONG) 0)) + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Trace not enabled, return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#endif +} + diff --git a/common/src/txe_block_allocate.c b/common/src/txe_block_allocate.c new file mode 100644 index 0000000..5564354 --- /dev/null +++ b/common/src/txe_block_allocate.c @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/txe_block_pool_create.c b/common/src/txe_block_pool_create.c new file mode 100644 index 0000000..8cbeadb --- /dev/null +++ b/common/src/txe_block_pool_create.c @@ -0,0 +1,228 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/txe_block_pool_delete.c b/common/src/txe_block_pool_delete.c new file mode 100644 index 0000000..844ff57 --- /dev/null +++ b/common/src/txe_block_pool_delete.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/txe_block_pool_info_get.c b/common/src/txe_block_pool_info_get.c new file mode 100644 index 0000000..77d9df4 --- /dev/null +++ b/common/src/txe_block_pool_info_get.c @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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); +} + diff --git a/common/src/txe_block_pool_prioritize.c b/common/src/txe_block_pool_prioritize.c new file mode 100644 index 0000000..593ac6d --- /dev/null +++ b/common/src/txe_block_pool_prioritize.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.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 checks for errors in the block pool prioritize call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to pool control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_block_pool_prioritize Actual block pool prioritize */ +/* 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_prioritize(TX_BLOCK_POOL *pool_ptr) +{ + +UINT status; + + + /* Check for an invalid block memory pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Block memory pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Now check for invalid pool ID. */ + else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID) + { + + /* Block memory pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + else + { + + /* Call actual block pool prioritize function. */ + status = _tx_block_pool_prioritize(pool_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_block_release.c b/common/src/txe_block_release.c new file mode 100644 index 0000000..e7eaed2 --- /dev/null +++ b/common/src/txe_block_release.c @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_block_release PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the block release function call. */ +/* */ +/* INPUT */ +/* */ +/* block_ptr Pointer to memory block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_PTR_ERROR Invalid memory block pointer */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_block_release Actual block release 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_release(VOID *block_ptr) +{ + +UINT status; +TX_BLOCK_POOL *pool_ptr; +UCHAR **indirect_ptr; +UCHAR *work_ptr; + + + /* First check the supplied pointer. */ + if (block_ptr == TX_NULL) + { + + /* The block pointer is invalid, return appropriate status. */ + status = TX_PTR_ERROR; + } + else + { + + /* Pickup the pool pointer which is just previous to the starting + address of 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 *))); + indirect_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr); + work_ptr = *indirect_ptr; + pool_ptr = TX_UCHAR_TO_BLOCK_POOL_POINTER_CONVERT(work_ptr); + + /* Check for an invalid pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Pool pointer is invalid, return appropriate error code. */ + status = TX_PTR_ERROR; + } + + /* Now check for invalid pool ID. */ + else if (pool_ptr -> tx_block_pool_id != TX_BLOCK_POOL_ID) + { + + /* Pool pointer is invalid, return appropriate error code. */ + status = TX_PTR_ERROR; + } + else + { + + /* Call actual block release function. */ + status = _tx_block_release(block_ptr); + } + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_byte_allocate.c b/common/src/txe_byte_allocate.c new file mode 100644 index 0000000..dbb3937 --- /dev/null +++ b/common/src/txe_byte_allocate.c @@ -0,0 +1,200 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#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_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_allocate PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in allocate bytes function call. */ +/* */ +/* 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 */ +/* */ +/* TX_POOL_ERROR Invalid memory pool pointer */ +/* TX_PTR_ERROR Invalid destination pointer */ +/* TX_WAIT_ERROR Invalid wait option */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* TX_SIZE_ERROR Invalid size of memory request */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_allocate Actual byte 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_byte_allocate(TX_BYTE_POOL *pool_ptr, VOID **memory_ptr, + ULONG memory_size, ULONG wait_option) +{ + +UINT status; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid byte pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Now check for invalid pool ID. */ + else if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Check for an invalid destination for return pointer. */ + else if (memory_ptr == TX_NULL) + { + + /* Null destination pointer, return appropriate error. */ + status = TX_PTR_ERROR; + } + + /* Check for an invalid memory size. */ + else if (memory_size == ((ULONG) 0)) + { + + /* Error in size, return appropriate error. */ + status = TX_SIZE_ERROR; + } + + /* Determine if the size is greater than the pool size. */ + else if (memory_size > pool_ptr -> tx_byte_pool_size) + { + + /* Error in size, return appropriate error. */ + status = TX_SIZE_ERROR; + } + + else + { + + /* Check for a wait option error. Only threads are allowed any form of + suspension. */ + if (wait_option != TX_NO_WAIT) + { + + /* Is call from 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 + + /* Check for timer execution. */ + if (status == TX_SUCCESS) + { + + /* 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 + + /* Is everything still okay? */ + if (status == TX_SUCCESS) + { + + /* 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 byte memory allocate function. */ + status = _tx_byte_allocate(pool_ptr, memory_ptr, memory_size, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_byte_pool_create.c b/common/src/txe_byte_pool_create.c new file mode 100644 index 0000000..2f37d06 --- /dev/null +++ b/common/src/txe_byte_pool_create.c @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte 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_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_pool_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the create byte pool memory */ +/* function. */ +/* */ +/* 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 */ +/* pool_control_block_size Size of byte pool control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_POOL_ERROR Invalid byte pool pointer */ +/* TX_PTR_ERROR Invalid pool starting address */ +/* TX_SIZE_ERROR Invalid pool size */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_pool_create Actual byte 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_byte_pool_create(TX_BYTE_POOL *pool_ptr, CHAR *name_ptr, VOID *pool_start, ULONG pool_size, UINT pool_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +ULONG i; +TX_BYTE_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 byte pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Now see if the pool control block size is valid. */ + else if (pool_control_block_size != (sizeof(TX_BYTE_POOL))) + { + + /* Byte 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_byte_pool_created_ptr; + for (i = ((ULONG) 0); i < _tx_byte_pool_created_count; i++) + { + + /* Determine if this byte pool matches the pool in the list. */ + if (pool_ptr == next_pool) + { + + break; + } + else + { + + /* Move to the next pool. */ + next_pool = next_pool -> tx_byte_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; + } + + /* Check for invalid pool size. */ + else if (pool_size < TX_BYTE_POOL_MIN) + { + + /* Pool not big enough, 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 byte pool create function. */ + status = _tx_byte_pool_create(pool_ptr, name_ptr, pool_start, pool_size); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_byte_pool_delete.c b/common/src/txe_byte_pool_delete.c new file mode 100644 index 0000000..2a6baad --- /dev/null +++ b/common/src/txe_byte_pool_delete.c @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_pool_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the delete byte pool function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to pool control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_POOL_ERROR Invalid pool pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_pool_delete Actual byte 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_byte_pool_delete(TX_BYTE_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 byte pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Now check the pool ID. */ + else if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Check for interrupt 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) + + /* 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; + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { +#endif + + /* Call actual byte pool delete function. */ + status = _tx_byte_pool_delete(pool_ptr); + +#ifndef TX_TIMER_PROCESS_IN_ISR + } +#endif + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_byte_pool_info_get.c b/common/src/txe_byte_pool_info_get.c new file mode 100644 index 0000000..0a7536e --- /dev/null +++ b/common/src/txe_byte_pool_info_get.c @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_pool_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the byte pool information get */ +/* service. */ +/* */ +/* 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 */ +/* */ +/* TX_POOL_ERROR Invalid byte pool pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_pool_info_get Actual byte 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_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) +{ + +UINT status; + + + /* Check for an invalid byte pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Block pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Now check for invalid pool ID. */ + else if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID) + { + + /* Block pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + else + { + + /* Otherwise, call the actual byte pool information get service. */ + status = _tx_byte_pool_info_get(pool_ptr, name, available_bytes, + fragments, first_suspended, suspended_count, next_pool); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_byte_pool_prioritize.c b/common/src/txe_byte_pool_prioritize.c new file mode 100644 index 0000000..a0f0f1a --- /dev/null +++ b/common/src/txe_byte_pool_prioritize.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.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 checks for errors in the byte pool prioritize call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to pool control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_pool_prioritize Actual byte pool prioritize */ +/* 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_byte_pool_prioritize(TX_BYTE_POOL *pool_ptr) +{ + +UINT status; + + + /* Check for an invalid byte memory pool pointer. */ + if (pool_ptr == TX_NULL) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + + /* Now check for invalid pool ID. */ + else if (pool_ptr -> tx_byte_pool_id != TX_BYTE_POOL_ID) + { + + /* Byte pool pointer is invalid, return appropriate error code. */ + status = TX_POOL_ERROR; + } + else + { + + /* Call actual byte pool prioritize function. */ + status = _tx_byte_pool_prioritize(pool_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_byte_release.c b/common/src/txe_byte_release.c new file mode 100644 index 0000000..67f9190 --- /dev/null +++ b/common/src/txe_byte_release.c @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#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_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_release PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the release byte function call. */ +/* */ +/* INPUT */ +/* */ +/* memory_ptr Pointer to allocated memory */ +/* */ +/* OUTPUT */ +/* */ +/* TX_PTR_ERROR Invalid memory pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_byte_release Actual byte release 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_byte_release(VOID *memory_ptr) +{ + +UINT status; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* First check the supplied memory pointer. */ + if (memory_ptr == TX_NULL) + { + + /* The byte memory pointer is invalid, return appropriate status. */ + status = TX_PTR_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 byte release function. */ + status = _tx_byte_release(memory_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_event_flags_create.c b/common/src/txe_event_flags_create.c new file mode 100644 index 0000000..4c71bd9 --- /dev/null +++ b/common/src/txe_event_flags_create.c @@ -0,0 +1,204 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#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_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the event flag creation function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* group_ptr Pointer to event flags group */ +/* control block */ +/* name_ptr Pointer to event flags name */ +/* event_control_block_size Size of event flags control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_GROUP_ERROR Invalid event flag group pointer */ +/* TX_CALLER_ERROR Invalid calling function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_event_flags_create Actual 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_event_flags_create(TX_EVENT_FLAGS_GROUP *group_ptr, CHAR *name_ptr, UINT event_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +ULONG i; +TX_EVENT_FLAGS_GROUP *next_group; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid event flags group pointer. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Now check for proper control block size. */ + else if (event_control_block_size != (sizeof(TX_EVENT_FLAGS_GROUP))) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_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_group = _tx_event_flags_created_ptr; + for (i = ((ULONG) 0); i < _tx_event_flags_created_count; i++) + { + + /* Determine if this group matches the event flags group in the list. */ + if (group_ptr == next_group) + { + + break; + } + else + { + + /* Move to the next group. */ + next_group = next_group -> tx_event_flags_group_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 event flag group. */ + if (group_ptr == next_group) + { + + /* Group is already created, return appropriate error code. */ + status = TX_GROUP_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 event flags create function. */ + status = _tx_event_flags_create(group_ptr, name_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_event_flags_delete.c b/common/src/txe_event_flags_delete.c new file mode 100644 index 0000000..6606627 --- /dev/null +++ b/common/src/txe_event_flags_delete.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the delete event flags group */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* group_ptr Pointer to group control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_GROUP_ERROR Invalid event flag group pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_event_flags_delete Actual delete event flags 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_event_flags_delete(TX_EVENT_FLAGS_GROUP *group_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 event flag group pointer. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Now check for invalid event flag group ID. */ + else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Check for invalid caller of this function. */ + + /* Is the caller 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 caller 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 event flag group delete function. */ + status = _tx_event_flags_delete(group_ptr); + +#ifndef TX_TIMER_PROCESS_IN_ISR + } +#endif + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_event_flags_get.c b/common/src/txe_event_flags_get.c new file mode 100644 index 0000000..2376763 --- /dev/null +++ b/common/src/txe_event_flags_get.c @@ -0,0 +1,178 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the event flags get function */ +/* call. */ +/* */ +/* 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 */ +/* */ +/* TX_GROUP_ERROR Invalid event flags group pointer */ +/* TX_PTR_ERROR Invalid actual flags pointer */ +/* TX_WAIT_ERROR Invalid wait option */ +/* TX_OPTION_ERROR Invalid get option */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_event_flags_get Actual event flags get 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_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, + UINT get_option, ULONG *actual_flags_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 event flag group pointer. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Now check for invalid event group ID. */ + else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Check for an invalid destination for actual flags. */ + else if (actual_flags_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 + } + } + + /* Is everything still okay? */ + if (status == TX_SUCCESS) + { + + /* Check for invalid get option. */ + if (get_option > TX_AND_CLEAR) + { + + /* Invalid get events option, return appropriate error. */ + status = TX_OPTION_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual event flags get function. */ + status = _tx_event_flags_get(group_ptr, requested_flags, get_option, actual_flags_ptr, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_event_flags_info_get.c b/common/src/txe_event_flags_info_get.c new file mode 100644 index 0000000..3400c55 --- /dev/null +++ b/common/src/txe_event_flags_info_get.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the event flag information get */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* group_ptr Pointer to event flag group */ +/* name Destination for the event flags */ +/* 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 */ +/* */ +/* TX_GROUP_ERROR Invalid event flag group pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_event_flags_info_get Actual event flags group 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_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) +{ + +UINT status; + + + /* Check for an invalid event flag group pointer. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Now check for invalid event flag group ID. */ + else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + else + { + + /* Otherwise, call the actual event flags group information get service. */ + status = _tx_event_flags_info_get(group_ptr, name, current_flags, first_suspended, + suspended_count, next_group); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_event_flags_set.c b/common/src/txe_event_flags_set.c new file mode 100644 index 0000000..03d309a --- /dev/null +++ b/common/src/txe_event_flags_set.c @@ -0,0 +1,127 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_set PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the set event flags function */ +/* call. */ +/* */ +/* 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_GROUP_ERROR Invalid event flags group pointer */ +/* TX_OPTION_ERROR Invalid set option */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_event_flags_set Actual set event flags 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_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, UINT set_option) +{ + +UINT status; + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid event flag group pointer. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Now check for invalid event flag group ID. */ + else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + else + { + + /* Check for invalid set option. */ + if (set_option != TX_AND) + { + + if (set_option != TX_OR) + { + + /* Invalid set events option, return appropriate error. */ + status = TX_OPTION_ERROR; + } + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual event flags set function. */ + status = _tx_event_flags_set(group_ptr, flags_to_set, set_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_event_flags_set_notify.c b/common/src/txe_event_flags_set_notify.c new file mode 100644 index 0000000..f93963d --- /dev/null +++ b/common/src/txe_event_flags_set_notify.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_set_notify PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the event flags set notify */ +/* callback function call. */ +/* */ +/* INPUT */ +/* */ +/* group_ptr Pointer to group control block*/ +/* group_put_notify Application callback function */ +/* (TX_NULL disables notify) */ +/* */ +/* OUTPUT */ +/* */ +/* status Service return status */ +/* */ +/* CALLS */ +/* */ +/* _tx_event_flags_set_notify Actual event flags set notify */ +/* call */ +/* */ +/* 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_event_flags_set_notify(TX_EVENT_FLAGS_GROUP *group_ptr, VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)) +{ + +UINT status; + + + /* Check for an invalid group pointer. */ + if (group_ptr == TX_NULL) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + + /* Now check for invalid event group ID. */ + else if (group_ptr -> tx_event_flags_group_id != TX_EVENT_FLAGS_ID) + { + + /* Event flags group pointer is invalid, return appropriate error code. */ + status = TX_GROUP_ERROR; + } + else + { + + /* Call actual event flags set notify function. */ + status = _tx_event_flags_set_notify(group_ptr, events_set_notify); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_mutex_create.c b/common/src/txe_mutex_create.c new file mode 100644 index 0000000..fb65a5b --- /dev/null +++ b/common/src/txe_mutex_create.c @@ -0,0 +1,222 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#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_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the create mutex function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* mutex_ptr Pointer to mutex control block */ +/* name_ptr Pointer to mutex name */ +/* inherit Initial mutex count */ +/* mutex_control_block_size Size of mutex control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_MUTEX_ERROR Invalid mutex pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* TX_INHERIT_ERROR Invalid inherit option */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_mutex_create Actual create mutex 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_mutex_create(TX_MUTEX *mutex_ptr, CHAR *name_ptr, UINT inherit, UINT mutex_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +ULONG i; +TX_MUTEX *next_mutex; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid mutex pointer. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Now check to make sure the control block is the correct size. */ + else if (mutex_control_block_size != (sizeof(TX_MUTEX))) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_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_mutex = _tx_mutex_created_ptr; + for (i = ((ULONG) 0); i < _tx_mutex_created_count; i++) + { + + /* Determine if this mutex matches the mutex in the list. */ + if (mutex_ptr == next_mutex) + { + + break; + } + else + { + + /* Move to the next mutex. */ + next_mutex = next_mutex -> tx_mutex_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 mutex. */ + if (mutex_ptr == next_mutex) + { + + /* Mutex is already created, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + else + { + + /* Check for a valid inherit option. */ + if (inherit != TX_INHERIT) + { + + if (inherit != TX_NO_INHERIT) + { + + /* Inherit option is illegal. */ + status = TX_INHERIT_ERROR; + } + } + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + +#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 mutex create function. */ + status = _tx_mutex_create(mutex_ptr, name_ptr, inherit); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_mutex_delete.c b/common/src/txe_mutex_delete.c new file mode 100644 index 0000000..b2a3fd2 --- /dev/null +++ b/common/src/txe_mutex_delete.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mutex delete function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* mutex_ptr Pointer to mutex control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_MUTEX_ERROR Invalid mutex pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_mutex_delete Actual delete mutex 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_mutex_delete(TX_MUTEX *mutex_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 mutex pointer. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Now check for a valid mutex ID. */ + else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Check for invalid caller of this function. */ + + /* Is the caller 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 caller 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 mutex delete function. */ + status = _tx_mutex_delete(mutex_ptr); + +#ifndef TX_TIMER_PROCESS_IN_ISR + } +#endif + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_mutex_get.c b/common/src/txe_mutex_get.c new file mode 100644 index 0000000..7ef04ee --- /dev/null +++ b/common/src/txe_mutex_get.c @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#ifndef TX_TIMER_PROCESS_IN_ISR +#include "tx_timer.h" +#endif +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mutex get function call. */ +/* */ +/* INPUT */ +/* */ +/* mutex_ptr Pointer to mutex control block */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* TX_MUTEX_ERROR Invalid mutex pointer */ +/* TX_WAIT_ERROR Invalid wait option */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_mutex_get Actual get mutex 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_mutex_get(TX_MUTEX *mutex_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 mutex pointer. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Now check for a valid mutex ID. */ + else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_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) + { + + /* 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) + { + + /* Yes, invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual get mutex function. */ + status = _tx_mutex_get(mutex_ptr, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_mutex_info_get.c b/common/src/txe_mutex_info_get.c new file mode 100644 index 0000000..826fead --- /dev/null +++ b/common/src/txe_mutex_info_get.c @@ -0,0 +1,115 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mutex information get */ +/* service. */ +/* */ +/* 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 */ +/* */ +/* TX_MUTEX_ERROR Invalid mutex pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_mutex_info_get Actual mutex 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_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) +{ + +UINT status; + + + /* Check for an invalid mutex pointer. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Now check for invalid mutex ID. */ + else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + else + { + + /* Otherwise, call the actual mutex information get service. */ + status = _tx_mutex_info_get(mutex_ptr, name, count, owner, first_suspended, + suspended_count, next_mutex); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_mutex_prioritize.c b/common/src/txe_mutex_prioritize.c new file mode 100644 index 0000000..9ae4b86 --- /dev/null +++ b/common/src/txe_mutex_prioritize.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_prioritize PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mutex prioritize call. */ +/* */ +/* INPUT */ +/* */ +/* mutex_ptr Pointer to mutex control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_mutex_prioritize Actual mutex prioritize */ +/* 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_mutex_prioritize(TX_MUTEX *mutex_ptr) +{ + +UINT status; + + + /* Check for an invalid mutex pointer. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Now check for invalid mutex ID. */ + else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + else + { + + /* Call actual mutex prioritize function. */ + status = _tx_mutex_prioritize(mutex_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_mutex_put.c b/common/src/txe_mutex_put.c new file mode 100644 index 0000000..85d5929 --- /dev/null +++ b/common/src/txe_mutex_put.c @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_put PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mutex put function call. */ +/* */ +/* INPUT */ +/* */ +/* mutex_ptr Pointer to mutex control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_MUTEX_ERROR Invalid mutex pointer */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_mutex_put Actual put mutex 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_mutex_put(TX_MUTEX *mutex_ptr) +{ + +UINT status; + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid mutex pointer. */ + if (mutex_ptr == TX_NULL) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + + /* Now check for invalid mutex ID. */ + else if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Mutex pointer is invalid, return appropriate error code. */ + status = TX_MUTEX_ERROR; + } + else + { + + /* 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 put mutex function. */ + status = _tx_mutex_put(mutex_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_create.c b/common/src/txe_queue_create.c new file mode 100644 index 0000000..68d3540 --- /dev/null +++ b/common/src/txe_queue_create.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue create function call. */ +/* */ +/* 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 */ +/* queue_control_block_size Size of queue control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* TX_PTR_ERROR Invalid starting address of queue */ +/* TX_SIZE_ERROR Invalid message queue size */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_create Actual queue 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_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size, + VOID *queue_start, ULONG queue_size, UINT queue_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +ULONG i; +TX_QUEUE *next_queue; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for a valid control block size. */ + else if (queue_control_block_size != (sizeof(TX_QUEUE))) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_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_queue = _tx_queue_created_ptr; + for (i = ((ULONG) 0); i < _tx_queue_created_count; i++) + { + + /* Determine if this queue matches the queue in the list. */ + if (queue_ptr == next_queue) + { + + break; + } + else + { + + /* Move to the next queue. */ + next_queue = next_queue -> tx_queue_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 queue. */ + if (queue_ptr == next_queue) + { + + /* Queue is already created, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Check the starting address of the queue. */ + else if (queue_start == TX_NULL) + { + + /* Invalid starting address of queue. */ + status = TX_PTR_ERROR; + } + + /* Check for an invalid message size - less than 1. */ + else if (message_size < TX_1_ULONG) + { + + /* Invalid message size specified. */ + status = TX_SIZE_ERROR; + } + + /* Check for an invalid message size - greater than 16. */ + else if (message_size > TX_16_ULONG) + { + + /* Invalid message size specified. */ + status = TX_SIZE_ERROR; + } + + /* Check on the queue size. */ + else if ((queue_size/(sizeof(ULONG))) < message_size) + { + + /* Invalid queue size specified. */ + 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 queue create function. */ + status = _tx_queue_create(queue_ptr, name_ptr, message_size, queue_start, queue_size); + } + + /* Return completion status. */ + return(status); +} diff --git a/common/src/txe_queue_delete.c b/common/src/txe_queue_delete.c new file mode 100644 index 0000000..3062ede --- /dev/null +++ b/common/src/txe_queue_delete.c @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue delete function call. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_delete Actual queue 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_queue_delete(TX_QUEUE *queue_ptr) +{ + +UINT status; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for a valid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + else + { + + /* Check for invalid caller of this function. */ + + /* Is the caller an ISR or Initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + +#ifndef TX_TIMER_PROCESS_IN_ISR + else + { + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(thread_ptr) + + /* Is the caller the system timer thread? */ + if (thread_ptr == &_tx_timer_thread) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } +#endif + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual queue delete function. */ + status = _tx_queue_delete(queue_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_flush.c b/common/src/txe_queue_flush.c new file mode 100644 index 0000000..348de23 --- /dev/null +++ b/common/src/txe_queue_flush.c @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_flush PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue flush function call. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_flush Actual queue flush 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_queue_flush(TX_QUEUE *queue_ptr) +{ + +UINT status; + + + /* Check for an invalid queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for invalid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + else + { + + /* Call actual queue flush function. */ + status = _tx_queue_flush(queue_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_front_send.c b/common/src/txe_queue_front_send.c new file mode 100644 index 0000000..21c254a --- /dev/null +++ b/common/src/txe_queue_front_send.c @@ -0,0 +1,159 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_front_send PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue send function call. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block */ +/* source_ptr Pointer to message source */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* TX_PTR_ERROR Invalid source pointer - NULL */ +/* TX_WAIT_ERROR Invalid wait option - non thread */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_front_send Actual queue send 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_queue_front_send(TX_QUEUE *queue_ptr, VOID *source_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 queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for invalid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Check for an invalid source for message. */ + else if (source_ptr == TX_NULL) + { + + /* Null source 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 queue front send function. */ + status = _tx_queue_front_send(queue_ptr, source_ptr, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_info_get.c b/common/src/txe_queue_info_get.c new file mode 100644 index 0000000..b4507b0 --- /dev/null +++ b/common/src/txe_queue_info_get.c @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue information get */ +/* service. */ +/* */ +/* 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 */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_info_get Actual information 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_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) +{ + +UINT status; + + + /* Check for an invalid queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for a valid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + else + { + + /* Otherwise, call the actual queue information get service. */ + status = _tx_queue_info_get(queue_ptr, name, enqueued, available_storage, first_suspended, + suspended_count, next_queue); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_prioritize.c b/common/src/txe_queue_prioritize.c new file mode 100644 index 0000000..f74809a --- /dev/null +++ b/common/src/txe_queue_prioritize.c @@ -0,0 +1,99 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_prioritize PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue prioritize call. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_prioritize Actual queue prioritize 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_queue_prioritize(TX_QUEUE *queue_ptr) +{ + +UINT status; + + + /* Check for an invalid queue pointer. */ + if (queue_ptr == TX_NULL) + { + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for invalid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + else + { + + /* Call actual queue prioritize function. */ + status = _tx_queue_prioritize(queue_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_receive.c b/common/src/txe_queue_receive.c new file mode 100644 index 0000000..b40e6a5 --- /dev/null +++ b/common/src/txe_queue_receive.c @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_receive PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue receive function call. */ +/* */ +/* 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 */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* TX_PTR_ERROR Invalid destination pointer (NULL)*/ +/* TX_WAIT_ERROR Invalid wait option */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_receive Actual queue receive 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_queue_receive(TX_QUEUE *queue_ptr, VOID *destination_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 queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for invalid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Check for an invalid destination for message. */ + else if (destination_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 queue receive function. */ + status = _tx_queue_receive(queue_ptr, destination_ptr, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_send.c b/common/src/txe_queue_send.c new file mode 100644 index 0000000..5873f02 --- /dev/null +++ b/common/src/txe_queue_send.c @@ -0,0 +1,159 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_send PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue send function call. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block */ +/* source_ptr Pointer to message source */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* TX_QUEUE_ERROR Invalid queue pointer */ +/* TX_PTR_ERROR Invalid source pointer - NULL */ +/* TX_WAIT_ERROR Invalid wait option */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_send Actual queue send 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_queue_send(TX_QUEUE *queue_ptr, VOID *source_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 queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for invalid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Check for an invalid source for message. */ + else if (source_ptr == TX_NULL) + { + + /* Null source 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 queue send function. */ + status = _tx_queue_send(queue_ptr, source_ptr, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_queue_send_notify.c b/common/src/txe_queue_send_notify.c new file mode 100644 index 0000000..9ffb0a9 --- /dev/null +++ b/common/src/txe_queue_send_notify.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_send_notify PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the queue send notify */ +/* callback function call. */ +/* */ +/* INPUT */ +/* */ +/* queue_ptr Pointer to queue control block*/ +/* queue_send_notify Application callback function */ +/* (TX_NULL disables notify) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_queue_send_notify Actual queue send notify call */ +/* */ +/* 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_queue_send_notify(TX_QUEUE *queue_ptr, VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)) +{ + +UINT status; + + + /* Check for an invalid queue pointer. */ + if (queue_ptr == TX_NULL) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + + /* Now check for a valid queue ID. */ + else if (queue_ptr -> tx_queue_id != TX_QUEUE_ID) + { + + /* Queue pointer is invalid, return appropriate error code. */ + status = TX_QUEUE_ERROR; + } + else + { + + /* Call actual queue send notify function. */ + status = _tx_queue_send_notify(queue_ptr, queue_send_notify); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_ceiling_put.c b/common/src/txe_semaphore_ceiling_put.c new file mode 100644 index 0000000..51fee9d --- /dev/null +++ b/common/src/txe_semaphore_ceiling_put.c @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_ceiling_put PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore ceiling put */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore */ +/* ceiling Maximum value of semaphore */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SEMAPHORE_ERROR Invalid semaphore pointer */ +/* TX_INVALID_CEILING Invalid semaphore ceiling */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_ceiling_put Actual semaphore ceiling put */ +/* 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_semaphore_ceiling_put(TX_SEMAPHORE *semaphore_ptr, ULONG ceiling) +{ + +UINT status; + + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for a valid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Determine if the ceiling is valid - must be greater than 1. */ + else if (ceiling == ((ULONG) 0)) + { + + /* Invalid ceiling, return error. */ + status = TX_INVALID_CEILING; + } + else + { + + /* Call actual semaphore ceiling put function. */ + status = _tx_semaphore_ceiling_put(semaphore_ptr, ceiling); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_create.c b/common/src/txe_semaphore_create.c new file mode 100644 index 0000000..3390491 --- /dev/null +++ b/common/src/txe_semaphore_create.c @@ -0,0 +1,209 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#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_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the create semaphore function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore control block*/ +/* name_ptr Pointer to semaphore name */ +/* initial_count Initial semaphore count */ +/* semaphore_control_block_size Size of semaphore control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SEMAPHORE_ERROR Invalid semaphore pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_create Actual create semaphore 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_semaphore_create(TX_SEMAPHORE *semaphore_ptr, CHAR *name_ptr, ULONG initial_count, UINT semaphore_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +ULONG i; +TX_SEMAPHORE *next_semaphore; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for a valid semaphore ID. */ + else if (semaphore_control_block_size != (sizeof(TX_SEMAPHORE))) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_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_semaphore = _tx_semaphore_created_ptr; + for (i = ((ULONG) 0); i < _tx_semaphore_created_count; i++) + { + + /* Determine if this semaphore matches the current semaphore in the list. */ + if (semaphore_ptr == next_semaphore) + { + + break; + } + else + { + + /* Move to next semaphore. */ + next_semaphore = next_semaphore -> tx_semaphore_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 semaphore. */ + if (semaphore_ptr == next_semaphore) + { + + /* Semaphore is already created, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + +#ifndef TX_TIMER_PROCESS_IN_ISR + else + { + + /* 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 + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* 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 semaphore create function. */ + status = _tx_semaphore_create(semaphore_ptr, name_ptr, initial_count); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_delete.c b/common/src/txe_semaphore_delete.c new file mode 100644 index 0000000..2083a22 --- /dev/null +++ b/common/src/txe_semaphore_delete.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore delete function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore control block*/ +/* */ +/* OUTPUT */ +/* */ +/* TX_SEMAPHORE_ERROR Invalid semaphore pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_delete Actual delete semaphore 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_semaphore_delete(TX_SEMAPHORE *semaphore_ptr) +{ + +UINT status; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for invalid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + else + { + + /* Check for invalid caller of this function. */ + + /* Is the caller an ISR or Initialization? */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + +#ifndef TX_TIMER_PROCESS_IN_ISR + else + { + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(thread_ptr) + + /* Is the caller the system timer thread? */ + if (thread_ptr == &_tx_timer_thread) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } +#endif + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual semaphore delete function. */ + status = _tx_semaphore_delete(semaphore_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_get.c b/common/src/txe_semaphore_get.c new file mode 100644 index 0000000..403d43b --- /dev/null +++ b/common/src/txe_semaphore_get.c @@ -0,0 +1,149 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore get function call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore control block*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SEMAPHORE_ERROR Invalid semaphore pointer */ +/* TX_WAIT_ERROR Invalid wait option */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_get Actual get semaphore 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_semaphore_get(TX_SEMAPHORE *semaphore_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 semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for invalid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_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 get semaphore function. */ + status = _tx_semaphore_get(semaphore_ptr, wait_option); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_info_get.c b/common/src/txe_semaphore_info_get.c new file mode 100644 index 0000000..142bad3 --- /dev/null +++ b/common/src/txe_semaphore_info_get.c @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore information get */ +/* service. */ +/* */ +/* 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 */ +/* */ +/* TX_SEMAPHORE_ERROR Invalid semaphore pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_info_get Actual semaphore 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_semaphore_info_get(TX_SEMAPHORE *semaphore_ptr, CHAR **name, ULONG *current_value, + TX_THREAD **first_suspended, ULONG *suspended_count, + TX_SEMAPHORE **next_semaphore) +{ + +UINT status; + + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for a valid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + else + { + + /* Otherwise, call the actual semaphore information get service. */ + status = _tx_semaphore_info_get(semaphore_ptr, name, current_value, first_suspended, + suspended_count, next_semaphore); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_prioritize.c b/common/src/txe_semaphore_prioritize.c new file mode 100644 index 0000000..52525de --- /dev/null +++ b/common/src/txe_semaphore_prioritize.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_prioritize PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore prioritize call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_prioritize Actual semaphore prioritize */ +/* 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_semaphore_prioritize(TX_SEMAPHORE *semaphore_ptr) +{ + +UINT status; + + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for a valid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + else + { + + /* Call actual semaphore prioritize function. */ + status = _tx_semaphore_prioritize(semaphore_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_put.c b/common/src/txe_semaphore_put.c new file mode 100644 index 0000000..4a26fbd --- /dev/null +++ b/common/src/txe_semaphore_put.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_put PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore put function call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore control block*/ +/* */ +/* OUTPUT */ +/* */ +/* TX_SEMAPHORE_ERROR Invalid semaphore pointer */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_put Actual put semaphore 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_semaphore_put(TX_SEMAPHORE *semaphore_ptr) +{ + +UINT status; + + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for invalid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + else + { + + /* Call actual put semaphore function. */ + status = _tx_semaphore_put(semaphore_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_semaphore_put_notify.c b/common/src/txe_semaphore_put_notify.c new file mode 100644 index 0000000..646c293 --- /dev/null +++ b/common/src/txe_semaphore_put_notify.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_put_notify PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the semaphore put notify */ +/* callback function call. */ +/* */ +/* INPUT */ +/* */ +/* semaphore_ptr Pointer to semaphore */ +/* semaphore_put_notify Application callback function */ +/* (TX_NULL disables notify) */ +/* */ +/* OUTPUT */ +/* */ +/* status Service return status */ +/* */ +/* CALLS */ +/* */ +/* _tx_semaphore_put_notify Actual semaphore put notify */ +/* call */ +/* */ +/* 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_semaphore_put_notify(TX_SEMAPHORE *semaphore_ptr, VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)) +{ + +UINT status; + + + /* Check for an invalid semaphore pointer. */ + if (semaphore_ptr == TX_NULL) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + + /* Now check for invalid semaphore ID. */ + else if (semaphore_ptr -> tx_semaphore_id != TX_SEMAPHORE_ID) + { + + /* Semaphore pointer is invalid, return appropriate error code. */ + status = TX_SEMAPHORE_ERROR; + } + else + { + + /* Call actual semaphore put notify function. */ + status = _tx_semaphore_put_notify(semaphore_ptr, semaphore_put_notify); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_create.c b/common/src/txe_thread_create.c new file mode 100644 index 0000000..c3902cd --- /dev/null +++ b/common/src/txe_thread_create.c @@ -0,0 +1,312 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_create PORTABLE C */ +/* 6.1 */ +/* 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 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 entry point or stack */ +/* address */ +/* TX_SIZE_ERROR Invalid stack size -too small */ +/* TX_PRIORITY_ERROR Invalid thread priority */ +/* TX_THRESH_ERROR Invalid preemption threshold */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_create Actual thread 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_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, UINT thread_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +UINT break_flag; +ULONG i; +TX_THREAD *next_thread; +VOID *stack_end; +UCHAR *work_ptr; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *current_thread; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread control block size. */ + else if (thread_control_block_size != (sizeof(TX_THREAD))) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_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. */ + break_flag = TX_FALSE; + next_thread = _tx_thread_created_ptr; + work_ptr = TX_VOID_TO_UCHAR_POINTER_CONVERT(stack_start); + work_ptr = TX_UCHAR_POINTER_ADD(work_ptr, (stack_size - ((ULONG) 1))); + stack_end = TX_UCHAR_TO_VOID_POINTER_CONVERT(work_ptr); + for (i = ((ULONG) 0); i < _tx_thread_created_count; i++) + { + + /* Determine if this thread matches the thread in the list. */ + if (thread_ptr == next_thread) + { + + /* Set the break flag. */ + break_flag = TX_TRUE; + } + + /* Determine if we need to break the loop. */ + if (break_flag == TX_TRUE) + { + + /* Yes, break out of the loop. */ + break; + } + + /* Check the stack pointer to see if it overlaps with this thread's stack. */ + if (stack_start >= next_thread -> tx_thread_stack_start) + { + + if (stack_start < next_thread -> tx_thread_stack_end) + { + + /* This stack overlaps with an existing thread, clear the stack pointer to + force a stack error below. */ + stack_start = TX_NULL; + + /* Set the break flag. */ + break_flag = TX_TRUE; + } + } + + /* Check the end of the stack to see if it is inside this thread's stack area as well. */ + if (stack_end >= next_thread -> tx_thread_stack_start) + { + + if (stack_end < next_thread -> tx_thread_stack_end) + { + + /* This stack overlaps with an existing thread, clear the stack pointer to + force a stack error below. */ + stack_start = TX_NULL; + + /* Set the break flag. */ + break_flag = TX_TRUE; + } + } + + /* Move to the next thread. */ + next_thread = next_thread -> tx_thread_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 thread. */ + if (thread_ptr == next_thread) + { + + /* Thread is already created, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for invalid starting address of stack. */ + else if (stack_start == TX_NULL) + { + + /* Invalid stack or entry point, return appropriate error code. */ + status = TX_PTR_ERROR; + } + + /* Check for invalid thread entry point. */ + else if (entry_function == TX_NULL) + { + + /* Invalid stack or entry point, return appropriate error code. */ + status = TX_PTR_ERROR; + } + + /* Check the stack size. */ + else if (stack_size < ((ULONG) TX_MINIMUM_STACK)) + { + + /* Stack is not big enough, return appropriate error code. */ + status = TX_SIZE_ERROR; + } + + /* Check the priority specified. */ + else if (priority >= ((UINT) TX_MAX_PRIORITIES)) + { + + /* Invalid priority selected, return appropriate error code. */ + status = TX_PRIORITY_ERROR; + } + + /* Check preemption threshold. */ + else if (preempt_threshold > priority) + { + + /* Invalid preempt threshold, return appropriate error code. */ + status = TX_THRESH_ERROR; + } + + /* Check the start selection. */ + else if (auto_start > TX_AUTO_START) + { + + /* Invalid auto start selection, return appropriate error code. */ + status = TX_START_ERROR; + } + else + { + +#ifndef TX_TIMER_PROCESS_IN_ISR + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(current_thread) + + /* Check for invalid caller of this function. First check for a calling thread. */ + if (current_thread == &_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 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); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_delete.c b/common/src/txe_thread_delete.c new file mode 100644 index 0000000..6e2d1d2 --- /dev/null +++ b/common/src/txe_thread_delete.c @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread delete function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to suspend */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_delete Actual thread 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_thread_delete(TX_THREAD *thread_ptr) +{ + +UINT status; + + + /* Check for invalid caller of this function. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + + /* Check for an invalid thread pointer. */ + else if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + + /* Call actual thread delete function. */ + status = _tx_thread_delete(thread_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_entry_exit_notify.c b/common/src/txe_thread_entry_exit_notify.c new file mode 100644 index 0000000..ab4e835 --- /dev/null +++ b/common/src/txe_thread_entry_exit_notify.c @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_entry_exit_notify PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread entry/exit notify */ +/* callback function call. */ +/* */ +/* 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 */ +/* */ +/* _tx_thread_entry_exit_notify Actual entry/exit notify */ +/* 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_thread_entry_exit_notify(TX_THREAD *thread_ptr, VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT type)) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + + /* Call actual thread entry/exit notify function. */ + status = _tx_thread_entry_exit_notify(thread_ptr, thread_entry_exit_notify); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_info_get.c b/common/src/txe_thread_info_get.c new file mode 100644 index 0000000..17f9155 --- /dev/null +++ b/common/src/txe_thread_info_get.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread information get */ +/* service. */ +/* */ +/* 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 */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_info_get Actual thread information 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_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) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + + /* Call the actual thread information get service. */ + status = _tx_thread_info_get(thread_ptr, name, state, run_count, priority, preemption_threshold, + time_slice, next_thread, next_suspended_thread); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_preemption_change.c b/common/src/txe_thread_preemption_change.c new file mode 100644 index 0000000..c0cfa91 --- /dev/null +++ b/common/src/txe_thread_preemption_change.c @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_preemption_change PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the preemption threshold change */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread */ +/* new_threshold New preemption threshold */ +/* old_threshold Old preemption threshold */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_PTR_ERROR Invalid old threshold pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_preemption_change Actual preempt change 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_thread_preemption_change(TX_THREAD *thread_ptr, UINT new_threshold, UINT *old_threshold) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for a valid old threshold pointer. */ + else if (old_threshold == TX_NULL) + { + + /* Invalid destination pointer, return appropriate error code. */ + status = TX_PTR_ERROR; + } + + /* Check for invalid caller of this function. */ + else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + + /* Determine if the preemption-threshold is valid. */ + else if (new_threshold > thread_ptr -> tx_thread_user_priority) + { + + /* Return an error status. */ + status = TX_THRESH_ERROR; + } + else + { + + /* Call actual change thread preemption function. */ + status = _tx_thread_preemption_change(thread_ptr, new_threshold, old_threshold); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_priority_change.c b/common/src/txe_thread_priority_change.c new file mode 100644 index 0000000..b4a1224 --- /dev/null +++ b/common/src/txe_thread_priority_change.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_priority_change PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the change priority function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to suspend */ +/* new_priority New thread priority */ +/* old_priority Old thread priority */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_PTR_ERROR Invalid old priority pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_priority_change Actual priority change */ +/* 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_thread_priority_change(TX_THREAD *thread_ptr, UINT new_priority, UINT *old_priority) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for a valid old priority pointer. */ + else if (old_priority == TX_NULL) + { + + /* Invalid destination pointer, return appropriate error code. */ + status = TX_PTR_ERROR; + } + + /* Determine if the priority is legal. */ + else if (new_priority >= ((UINT) TX_MAX_PRIORITIES)) + { + + /* Return an error status. */ + status = TX_PRIORITY_ERROR; + } + + /* Check for invalid caller of this function. */ + else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + else + { + + /* Call actual change thread priority function. */ + status = _tx_thread_priority_change(thread_ptr, new_priority, old_priority); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_relinquish.c b/common/src/txe_thread_relinquish.c new file mode 100644 index 0000000..1c5ab21 --- /dev/null +++ b/common/src/txe_thread_relinquish.c @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_relinquish PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks to make sure a thread is executing before the */ +/* relinquish is executed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_relinquish Actual thread relinquish call */ +/* */ +/* 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 _txe_thread_relinquish(VOID) +{ + +TX_THREAD *current_thread; + + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(current_thread) + + /* Make sure a thread is executing. */ + if (current_thread != TX_NULL) + { + + /* Now make sure the call is not from an ISR or Initialization. */ + if (TX_THREAD_GET_SYSTEM_STATE() == ((ULONG) 0)) + { + + /* Okay to call the real relinquish function. */ + _tx_thread_relinquish(); + } + } +} + diff --git a/common/src/txe_thread_reset.c b/common/src/txe_thread_reset.c new file mode 100644 index 0000000..4fed5e7 --- /dev/null +++ b/common/src/txe_thread_reset.c @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 */ +/* */ +/* _txe_thread_reset PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread reset function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to reset */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Service return status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_reset Actual thread reset 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_thread_reset(TX_THREAD *thread_ptr) +{ + +UINT status; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *current_thread; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for an invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + +#ifndef TX_TIMER_PROCESS_IN_ISR + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(current_thread) + + /* Check for invalid caller of this function. First check for a calling thread. */ + if (current_thread == &_tx_timer_thread) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } +#endif + + /* Check for interrupt or initialization call. */ + if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + + /* Call actual thread reset function. */ + status = _tx_thread_reset(thread_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_resume.c b/common/src/txe_thread_resume.c new file mode 100644 index 0000000..e8a341d --- /dev/null +++ b/common/src/txe_thread_resume.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_resume PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the resume thread function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to resume */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_resume Actual thread resume 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_thread_resume(TX_THREAD *thread_ptr) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + + /* Call actual thread resume function. */ + status = _tx_thread_resume(thread_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_suspend.c b/common/src/txe_thread_suspend.c new file mode 100644 index 0000000..951d35e --- /dev/null +++ b/common/src/txe_thread_suspend.c @@ -0,0 +1,104 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_suspend PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread suspend function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to suspend */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_suspend Actual thread suspension */ +/* */ +/* 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_thread_suspend(TX_THREAD *thread_ptr) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + + /* Call actual thread suspend function. */ + status = _tx_thread_suspend(thread_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_terminate.c b/common/src/txe_thread_terminate.c new file mode 100644 index 0000000..aa54501 --- /dev/null +++ b/common/src/txe_thread_terminate.c @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_terminate PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread terminate function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to suspend */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_terminate Actual thread terminate */ +/* 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_thread_terminate(TX_THREAD *thread_ptr) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for invalid caller of this function. */ + else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + else + { + + /* Call actual thread terminate function. */ + status = _tx_thread_terminate(thread_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_time_slice_change.c b/common/src/txe_thread_time_slice_change.c new file mode 100644 index 0000000..d01137d --- /dev/null +++ b/common/src/txe_thread_time_slice_change.c @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_time_slice_change PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the time slice change function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread */ +/* new_time_slice New time slice */ +/* old_time_slice Old time slice */ +/* */ +/* OUTPUT */ +/* */ +/* TX_THREAD_ERROR Invalid thread pointer */ +/* TX_CALLER_ERROR Invalid caller of function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_time_slice_change Actual time-slice change */ +/* 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_thread_time_slice_change(TX_THREAD *thread_ptr, ULONG new_time_slice, ULONG *old_time_slice) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Check for a valid old time-slice pointer. */ + else if (old_time_slice == TX_NULL) + { + + /* Invalid destination pointer, return appropriate error code. */ + status = TX_PTR_ERROR; + } + + /* Check for invalid caller of this function. */ + else if (TX_THREAD_GET_SYSTEM_STATE() != ((ULONG) 0)) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + else + { + + /* Call actual change time slice function. */ + status = _tx_thread_time_slice_change(thread_ptr, new_time_slice, old_time_slice); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_thread_wait_abort.c b/common/src/txe_thread_wait_abort.c new file mode 100644 index 0000000..8132c59 --- /dev/null +++ b/common/src/txe_thread_wait_abort.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_wait_abort PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread wait abort function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread to abort the wait on */ +/* */ +/* OUTPUT */ +/* */ +/* status Return completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_wait_abort Actual wait abort 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_thread_wait_abort(TX_THREAD *thread_ptr) +{ + +UINT status; + + + /* Check for an invalid thread pointer. */ + if (thread_ptr == TX_NULL) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + + /* Now check for invalid thread ID. */ + else if (thread_ptr -> tx_thread_id != TX_THREAD_ID) + { + + /* Thread pointer is invalid, return appropriate error code. */ + status = TX_THREAD_ERROR; + } + else + { + + /* Call actual thread wait abort function. */ + status = _tx_thread_wait_abort(thread_ptr); + } + + /* Return status to the caller. */ + return(status); +} + diff --git a/common/src/txe_timer_activate.c b/common/src/txe_timer_activate.c new file mode 100644 index 0000000..9bd6234 --- /dev/null +++ b/common/src/txe_timer_activate.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_activate PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the activate application timer */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid application timer */ +/* TX_ACTIVATE_ERROR Application timer already active */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_activate Actual application timer activate */ +/* */ +/* 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_timer_activate(TX_TIMER *timer_ptr) +{ + +UINT status; + + + /* Check for an invalid timer pointer. */ + if (timer_ptr == TX_NULL) + { + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Now check for invalid timer ID. */ + else if (timer_ptr -> tx_timer_id != TX_TIMER_ID) + { + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + else + { + + /* Call actual application timer activate function. */ + status = _tx_timer_activate(timer_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_timer_change.c b/common/src/txe_timer_change.c new file mode 100644 index 0000000..70a7ed0 --- /dev/null +++ b/common/src/txe_timer_change.c @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_change PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the application timer change */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control block */ +/* initial_ticks Initial expiration ticks */ +/* reschedule_ticks Reschedule ticks */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid application timer pointer */ +/* TX_TICK_ERROR Invalid initial tick value of 0 */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_change Actual timer change 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_timer_change(TX_TIMER *timer_ptr, ULONG initial_ticks, ULONG reschedule_ticks) +{ + +UINT status; + + + /* Check for an invalid timer pointer. */ + if (timer_ptr == TX_NULL) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Now check for invalid timer ID. */ + else if (timer_ptr -> tx_timer_id != TX_TIMER_ID) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Check for an illegal initial tick value. */ + else if (initial_ticks == ((ULONG) 0)) + { + + /* Invalid initial tick value, return appropriate error code. */ + status = TX_TICK_ERROR; + } + + /* Check for invalid caller of this function. */ + else if (TX_THREAD_GET_SYSTEM_STATE() >= TX_INITIALIZE_IN_PROGRESS) + { + + /* Invalid caller of this function, return appropriate error code. */ + status = TX_CALLER_ERROR; + } + else + { + + /* Call actual application timer function. */ + status = _tx_timer_change(timer_ptr, initial_ticks, reschedule_ticks); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_timer_create.c b/common/src/txe_timer_create.c new file mode 100644 index 0000000..553418b --- /dev/null +++ b/common/src/txe_timer_create.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_create PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the create application timer */ +/* function call. */ +/* */ +/* 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 */ +/* timer_control_block_size Size of timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid timer control block */ +/* TX_TICK_ERROR Invalid initial expiration count */ +/* TX_ACTIVATE_ERROR Invalid timer activation option */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* _tx_timer_create Actual timer create 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_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, UINT timer_control_block_size) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +ULONG i; +TX_TIMER *next_timer; +#ifndef TX_TIMER_PROCESS_IN_ISR +TX_THREAD *thread_ptr; +#endif + + + /* Default status to success. */ + status = TX_SUCCESS; + + /* Check for a NULL timer pointer. */ + if (timer_ptr == TX_NULL) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Now check for invalid control block size. */ + else if (timer_control_block_size != (sizeof(TX_TIMER))) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_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_timer = _tx_timer_created_ptr; + for (i = ((ULONG) 0); i < _tx_timer_created_count; i++) + { + + /* Determine if this timer matches the current timer in the list. */ + if (timer_ptr == next_timer) + { + + break; + } + else + { + + /* Move to next timer. */ + next_timer = next_timer -> tx_timer_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 timer. */ + if (timer_ptr == next_timer) + { + + /* Timer is already created, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Check for an illegal initial tick value. */ + else if (initial_ticks == ((ULONG) 0)) + { + + /* Invalid initial tick value, return appropriate error code. */ + status = TX_TICK_ERROR; + } + else + { + + /* Check for an illegal activation. */ + if (auto_activate != TX_AUTO_ACTIVATE) + { + + /* And activation is not the other value. */ + if (auto_activate != TX_NO_ACTIVATE) + { + + /* Invalid activation selected, return appropriate error code. */ + status = TX_ACTIVATE_ERROR; + } + } + } + } + + /* Determine if everything is okay. */ + if (status == TX_SUCCESS) + { + +#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 application timer create function. */ + status = _tx_timer_create(timer_ptr, name_ptr, expiration_function, expiration_input, + initial_ticks, reschedule_ticks, auto_activate); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_timer_deactivate.c b/common/src/txe_timer_deactivate.c new file mode 100644 index 0000000..a573691 --- /dev/null +++ b/common/src/txe_timer_deactivate.c @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_deactivate PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the deactivate application timer */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid application timer pointer */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_deactivate Actual 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 _txe_timer_deactivate(TX_TIMER *timer_ptr) +{ + +UINT status; + + + /* Check for an invalid timer pointer. */ + if (timer_ptr == TX_NULL) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Now check for invalid timer ID. */ + else if (timer_ptr -> tx_timer_id != TX_TIMER_ID) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + else + { + + /* Call actual application timer deactivate function. */ + status = _tx_timer_deactivate(timer_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_timer_delete.c b/common/src/txe_timer_delete.c new file mode 100644 index 0000000..3a1bf33 --- /dev/null +++ b/common/src/txe_timer_delete.c @@ -0,0 +1,144 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_delete PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the delete application timer */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* timer_ptr Pointer to timer control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_TIMER_ERROR Invalid application timer pointer */ +/* TX_CALLER_ERROR Invalid caller of this function */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_delete Actual timer 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_timer_delete(TX_TIMER *timer_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 timer pointer. */ + if (timer_ptr == TX_NULL) + { + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Now check for invalid timer ID. */ + else if (timer_ptr -> tx_timer_id != TX_TIMER_ID) + { + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Check for invalid caller of this function. */ + + /* Is the caller 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 caller 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 application timer delete function. */ + status = _tx_timer_delete(timer_ptr); + +#ifndef TX_TIMER_PROCESS_IN_ISR + } +#endif + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/txe_timer_info_get.c b/common/src/txe_timer_info_get.c new file mode 100644 index 0000000..a227f13 --- /dev/null +++ b/common/src/txe_timer_info_get.c @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_info_get PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the timer information get */ +/* service. */ +/* */ +/* 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 */ +/* */ +/* TX_TIMER_ERROR Invalid timer pointer */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_info_get Actual info get call */ +/* */ +/* 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_timer_info_get(TX_TIMER *timer_ptr, CHAR **name, UINT *active, ULONG *remaining_ticks, + ULONG *reschedule_ticks, TX_TIMER **next_timer) +{ + +UINT status; + + + /* Check for an invalid timer pointer. */ + if (timer_ptr == TX_NULL) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + + /* Now check for invalid timer ID. */ + else if (timer_ptr -> tx_timer_id != TX_TIMER_ID) + { + + /* Timer pointer is invalid, return appropriate error code. */ + status = TX_TIMER_ERROR; + } + else + { + + /* Otherwise, call the actual timer information get service. */ + status = _tx_timer_info_get(timer_ptr, name, active, remaining_ticks, reschedule_ticks, next_timer); + } + + /* Return completion status. */ + return(status); +} + diff --git a/ports/cortex_m3/ac5/inc/tx_port.h b/ports/cortex_m3/ac5/inc/tx_port.h new file mode 100644 index 0000000..2e67b64 --- /dev/null +++ b/ports/cortex_m3/ac5/inc/tx_port.h @@ -0,0 +1,728 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/AC5 */ +/* 6.1.12 */ +/* */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */ +/* the ARMv7-M architecture and compilers into one common file. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comments, updated */ +/* typedef to fix misra */ +/* violation, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#include "tx_ghs.h" +#endif /* __ghs__ */ + + +#if !defined(__GNUC__) && !defined(__CC_ARM) +#define __get_control_value __get_CONTROL +#define __set_control_value __set_CONTROL +#endif + +#ifndef __GNUC__ +#define __get_ipsr_value __get_IPSR +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long long ULONG64; +typedef short SHORT; +typedef unsigned short USHORT; +#define ULONG64_DEFINED + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + +/* By default, ThreadX for Cortex-M uses the PRIMASK register to enable/disable interrupts. +If using BASEPRI is desired, define the following two symbols for both c and assembly files: +TX_PORT_USE_BASEPRI - This tells ThreadX to use BASEPRI instead of PRIMASK. +TX_PORT_BASEPRI = (priority_mask << (8 - number_priority_bits)) - this defines the maximum priority level to mask. +Any interrupt with a higher priority than priority_mask will not be masked, thus the interrupt will run. +*/ + +/* Define various constants for the ThreadX Cortex-M port. */ + +#define TX_INT_DISABLE 1 /* Disable interrupts */ +#define TX_INT_ENABLE 0 /* Enable interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0xE0001004) +#endif +#else +ULONG _tx_misra_time_stamp_get(VOID); +#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get() +#endif + +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#ifdef TX_MISRA_ENABLE +#define TX_DISABLE_INLINE +#else +#define TX_INLINE_INITIALIZATION +#endif + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifndef TX_MISRA_ENABLE +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#elif defined(__ghs__) +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#else +#define TX_THREAD_EXTENSION_2 +#endif + + +#define TX_THREAD_EXTENSION_3 + + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#if (__VER__ < 8000000) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0); +#else +void *_tx_iar_create_per_thread_tls_area(void); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); +void __iar_Initlocks(void); + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0); +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); +#endif +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + +#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) + +#ifdef TX_MISRA_ENABLE + +ULONG _tx_misra_control_get(void); +void _tx_misra_control_set(ULONG value); +ULONG _tx_misra_fpccr_get(void); +void _tx_misra_vfp_touch(void); + +#else /* TX_MISRA_ENABLE not defined */ + +/* Define some helper functions (these are intrinsics in some compilers). */ +#ifdef __GNUC__ /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + +__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value) +{ + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); + +#elif defined(__CC_ARM) /* ARM Compiler 5 */ + +__attribute__( ( always_inline ) ) ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm volatile ("MRS control_value,CONTROL"); + return(control_value); +} + +__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value) +{ + __asm__ volatile ("MSR CONTROL,control_value"); +} +/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */ +void _tx_vfp_access(void); +#define TX_VFP_TOUCH() _tx_vfp_access(); + +#elif defined(__ICCARM__) /* IAR */ +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); +#endif /* Helper functions for different compilers */ + +#endif /* TX_MISRA_ENABLE */ + + +/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA + in order to ensure no lazy stacking will occur. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } +#else + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } + +#endif + +/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR. + If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating + this one, so if the FPCCR.LSPACT bit is set, we need to save the CONTROL.FPCA state, touch the FPU to flush + the lazy FPU save, then restore the CONTROL.FPCA state. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((volatile ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + TX_VFP_TOUCH(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + } \ + } \ + } +#else + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = _tx_misra_fpccr_get(); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + _tx_misra_vfp_touch(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + } \ + } \ + } +#endif + +#else /* No VFP in use */ + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */ + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define the get system state macro. */ + +#ifndef TX_THREAD_GET_SYSTEM_STATE +#ifndef TX_MISRA_ENABLE + +#ifdef __CC_ARM /* ARM Compiler 5 */ + +register unsigned int _ipsr __asm("ipsr"); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr) + +#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void) +{ +unsigned int ipsr_value; + __asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) ); + return(ipsr_value); +} + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value()) + +#elif defined(__ICCARM__) /* IAR */ + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR()) + +#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */ + +#else /* TX_MISRA_ENABLE is defined, use MISRA function. */ +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif /* TX_MISRA_ENABLE */ +#endif /* TX_THREAD_GET_SYSTEM_STATE */ + + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h + for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always + zero after initialization for Cortex-M ports. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable); +#endif + +/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to + prevent early scheduling on Cortex-M parts. */ + +#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++; + + + + +#ifndef TX_DISABLE_INLINE + +/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */ +#ifdef __ICCARM__ /* IAR Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m))); +#elif defined(__CC_ARM) /* AC5 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m))); +#elif defined(__GNUC__) /* GCC and AC6 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); +#endif + + + +/* Define the interrupt disable/restore macros for each compiler. */ + +#if defined(__GNUC__) || defined(__ICCARM__) + +/*** GCC/AC6 and IAR ***/ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture)); +#else + __asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture)); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +__attribute__( ( always_inline ) ) static inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value)); +} +#else +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + __asm__ volatile ("CPSIE i": : : "memory"); +} +#endif + +__attribute__( ( always_inline ) ) static inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); + //__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory"); +#else + __asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory"); +#endif +} + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i" : : : "memory"); +#endif + return(int_posture); +} + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_interrupt_posture(); +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(0); +#else + __enable_interrupts(); +#endif + __restore_interrupt(interrupt_save); + } +} + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End GCC/AC6 and IAR ***/ + +#elif defined(__CC_ARM) + +/*** AC5 ***/ + +static __inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS #posture, BASEPRI"); +#else + __asm__ volatile ("MRS #posture, PRIMASK"); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +static __inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI, #basepri_value"); +} +#endif + +static __inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i"); +#endif + return(int_posture); +} + +static __inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); +#else + __asm__ volatile ("MSR PRIMASK, #int_posture"); +#endif +} + +static void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (_ipsr == 0) + { +#ifdef TX_PORT_USE_BASEPRI + interrupt_save = __get_interrupt_posture(); + __set_basepri_value(0); + __set_basepri_value(interrupt_save); +#else + interrupt_save = __disable_irq(); + __enable_irq(); + if (interrupt_save != 0) + __disable_irq(); +#endif + } +} + + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End AC5 ***/ + +#endif /* Interrupt disable/restore macros for each compiler. */ + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else /* TX_DISABLE_INLINE is defined */ + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); +#endif /* TX_DISABLE_INLINE */ + + +/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing + thread. These are no longer needed, but are preserved for backward compatibility only. */ + +void tx_thread_fpu_enable(void); +void tx_thread_fpu_disable(void); + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) 2024 Microsoft Corporation. * ThreadX Cortex-M3/AC5 Version 6.4.2 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + + +#endif diff --git a/ports/cortex_m3/ac5/src/tx_thread_context_restore.s b/ports/cortex_m3/ac5/src/tx_thread_context_restore.s new file mode 100644 index 0000000..2350327 --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_context_restore.s @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + IMPORT _tx_execution_isr_exit +#endif + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + EXPORT _tx_thread_context_restore +_tx_thread_context_restore + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + ALIGN + LTORG + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_context_save.s b/ports/cortex_m3/ac5/src/tx_thread_context_save.s new file mode 100644 index 0000000..75a6886 --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_context_save.s @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + IMPORT _tx_execution_isr_enter +#endif + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + EXPORT _tx_thread_context_save +_tx_thread_context_save + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } + ALIGN + LTORG + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_interrupt_control.s b/ports/cortex_m3/ac5/src/tx_thread_interrupt_control.s new file mode 100644 index 0000000..050d349 --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_interrupt_control.s @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + EXPORT _tx_thread_interrupt_control +_tx_thread_interrupt_control +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_interrupt_disable.s b/ports/cortex_m3/ac5/src/tx_thread_interrupt_disable.s new file mode 100644 index 0000000..0164201 --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_interrupt_disable.s @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + EXPORT _tx_thread_interrupt_disable +_tx_thread_interrupt_disable + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_interrupt_restore.s b/ports/cortex_m3/ac5/src/tx_thread_interrupt_restore.s new file mode 100644 index 0000000..d5b937f --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_interrupt_restore.s @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + EXPORT _tx_thread_interrupt_restore +_tx_thread_interrupt_restore + + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_schedule.s b/ports/cortex_m3/ac5/src/tx_thread_schedule.s new file mode 100644 index 0000000..4444938 --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_schedule.s @@ -0,0 +1,330 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_execute_ptr + IMPORT _tx_timer_time_slice + IMPORT _tx_thread_system_stack_ptr + IMPORT _tx_thread_preempt_disable +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + IMPORT _tx_execution_thread_enter + IMPORT _tx_execution_thread_exit +#endif + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* _tx_thread_system_return Return to system from thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + EXPORT _tx_thread_schedule +_tx_thread_schedule + + /* This function should only ever be called on Cortex-M + from the first schedule request. Subsequent scheduling occurs + from the PendSV handling routine below. */ + + /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */ + + MOV r0, #0 // Build value for TX_FALSE + LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag + STR r0, [r2, #0] // Clear preempt disable flag + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __TARGET_FPU_VFP + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* Enable interrupts */ + CPSIE i + + /* Enter the scheduler for the first time. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + DSB // Complete all memory accesses + ISB // Flush pipeline + + /* Wait here for the PendSV to take place. */ + +__tx_wait_here + B __tx_wait_here // Wait for the PendSV to happen +// } + + /* Generic context switching PendSV handler. */ + + EXPORT __tx_PendSVHandler + EXPORT PendSV_Handler +__tx_PendSVHandler +PendSV_Handler + + /* Get current thread value and new thread pointer. */ + +__tx_ts_handler + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread exit function to indicate the thread is no longer executing. */ +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif /* TX_PORT_USE_BASEPRI */ + PUSH {r0, lr} // Save LR (and r0 just for alignment) + BL _tx_execution_thread_exit // Call the thread exit function + POP {r0, lr} // Recover LR +#ifdef TX_PORT_USE_BASEPRI + MOV r0, 0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r0 +#else + CPSIE i // Enable interrupts +#endif /* TX_PORT_USE_BASEPRI */ +#endif /* EXECUTION PROFILE */ + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + MOV r3, #0 // Build NULL value + LDR r1, [r0] // Pickup current thread pointer + + /* Determine if there is a current thread to finish preserving. */ + + CBZ r1, __tx_ts_new // If NULL, skip preservation + + /* Recover PSP and preserve current thread context. */ + + STR r3, [r0] // Set _tx_thread_current_ptr to NULL + MRS r12, PSP // Pickup PSP pointer (thread's stack pointer) + STMDB r12!, {r4-r11} // Save its remaining registers +#ifdef __TARGET_FPU_VFP + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_save + VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers +_skip_vfp_save +#endif + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + STMDB r12!, {LR} // Save LR on the stack + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + STR r12, [r1, #8] // Save the thread stack pointer + CBZ r5, __tx_ts_new // If not active, skip processing + + /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */ + + STR r5, [r1, #24] // Save current time-slice + + /* Clear the global time-slice. */ + + STR r3, [r4] // Clear time-slice + + /* Executing thread is now completely preserved!!! */ + +__tx_ts_new + + /* Now we are looking for a new thread to execute! */ + +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Is there another thread ready to execute? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + STR r1, [r0] // Setup the current thread pointer to the new thread +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + + /* Increment the thread run count. */ + +__tx_ts_restore + LDR r7, [r1, #4] // Pickup the current thread run count + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + LDR r5, [r1, #24] // Pickup thread's current time-slice + ADD r7, r7, #1 // Increment the thread run count + STR r7, [r1, #4] // Store the new run count + + /* Setup global time-slice with thread's current time-slice. */ + + STR r5, [r4] // Setup global time-slice + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread entry function to indicate the thread is executing. */ + PUSH {r0, r1} // Save r0 and r1 + BL _tx_execution_thread_enter // Call the thread execution enter function + POP {r0, r1} // Recover r0 and r1 +#endif + + /* Restore the thread context and PSP. */ + + LDR r12, [r1, #8] // Pickup thread's stack pointer + LDMIA r12!, {LR} // Pickup LR +#ifdef __TARGET_FPU_VFP + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_restore // If not, skip VFP restore + VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers +_skip_vfp_restore +#endif + LDMIA r12!, {r4-r11} // Recover thread's registers + MSR PSP, r12 // Setup the thread's stack pointer + + /* Return to thread. */ + + BX lr // Return to thread! + + /* The following is the idle wait processing... in this case, no threads are ready for execution and the + system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts + are disabled to allow use of WFI for waiting for a thread to arrive. */ + +__tx_ts_wait +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Pickup the next thread to execute pointer + STR r1, [r0] // Store it in the current pointer + CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready! + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_enter // Possibly enter low power mode + POP {r0-r3} +#endif + +#ifdef TX_ENABLE_WFI + DSB // Ensure no outstanding memory transactions + WFI // Wait for interrupt + ISB // Ensure pipeline is flushed +#endif + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_exit // Exit low power mode + POP {r0-r3} +#endif + +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_wait // Loop to continue waiting + + /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are + already in the handler! */ + +__tx_ts_ready + MOV r7, #0x08000000 // Build clear PendSV value + MOV r8, #0xE000E000 // Build base NVIC address + STR r7, [r8, #0xD04] // Clear any PendSV + + /* Re-enable interrupts and restore new thread. */ +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_restore // Restore the thread +// } + +#ifdef __TARGET_FPU_VFP + EXPORT tx_thread_fpu_enable +tx_thread_fpu_enable + EXPORT tx_thread_fpu_disable +tx_thread_fpu_disable + + /* Automatic VPF logic is supported, this function is present only for + backward compatibility purposes and therefore simply returns. */ + + BX LR // Return to caller + + EXPORT _tx_vfp_access +_tx_vfp_access + VMOV.F32 s0, s0 // Simply access the VFP + BX lr // Return to caller + +#endif + + ALIGN + LTORG + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_stack_build.s b/ports/cortex_m3/ac5/src/tx_thread_stack_build.s new file mode 100644 index 0000000..fa77e2d --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_stack_build.s @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + EXPORT _tx_thread_stack_build +_tx_thread_stack_build + + /* Build a fake interrupt frame. The form of the fake interrupt stack + on the Cortex-M should look like the following after it is built: + + Stack Top: + LR Interrupted LR (LR at time of PENDSV) + r4 Initial value for r4 + r5 Initial value for r5 + r6 Initial value for r6 + r7 Initial value for r7 + r8 Initial value for r8 + r9 Initial value for r9 + r10 Initial value for r10 + r11 Initial value for r11 + r0 Initial value for r0 (Hardware stack starts here!!) + r1 Initial value for r1 + r2 Initial value for r2 + r3 Initial value for r3 + r12 Initial value for r12 + lr Initial value for lr + pc Initial value for pc + xPSR Initial value for xPSR + + Stack Bottom: (higher memory address) */ + + LDR r2, [r0, #16] // Pickup end of stack area + BIC r2, r2, #0x7 // Align frame for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size + LDR r3, =0xFFFFFFFD // Build initial LR value + STR r3, [r2, #0] // Save on the stack + + /* Actually build the stack frame. */ + + MOV r3, #0 // Build initial register value + STR r3, [r2, #4] // Store initial r4 + STR r3, [r2, #8] // Store initial r5 + STR r3, [r2, #12] // Store initial r6 + STR r3, [r2, #16] // Store initial r7 + STR r3, [r2, #20] // Store initial r8 + STR r3, [r2, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + STR r3, [r2, #44] // Store initial r2 + STR r3, [r2, #48] // Store initial r3 + STR r3, [r2, #52] // Store initial r12 + MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value + STR r3, [r2, #56] // Store initial lr + STR r1, [r2, #60] // Store initial pc + MOV r3, #0x01000000 // Only T-bit need be set + STR r3, [r2, #64] // Store initial xPSR + + /* Setup stack pointer. */ + // thread_ptr -> tx_thread_stack_ptr = r2; + + STR r2, [r0, #8] // Save stack pointer in thread's + // control block + BX lr // Return to caller +// } + END diff --git a/ports/cortex_m3/ac5/src/tx_thread_system_return.s b/ports/cortex_m3/ac5/src/tx_thread_system_return.s new file mode 100644 index 0000000..53d4804 --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_thread_system_return.s @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + AREA ||.text||, CODE, READONLY +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + EXPORT _tx_thread_system_return +_tx_thread_system_return + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context + BX lr // Return to caller +// } + END diff --git a/ports/cortex_m3/ac5/src/tx_timer_interrupt.s b/ports/cortex_m3/ac5/src/tx_timer_interrupt.s new file mode 100644 index 0000000..b87639d --- /dev/null +++ b/ports/cortex_m3/ac5/src/tx_timer_interrupt.s @@ -0,0 +1,264 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + IMPORT _tx_timer_time_slice + IMPORT _tx_timer_system_clock + IMPORT _tx_timer_current_ptr + IMPORT _tx_timer_list_start + IMPORT _tx_timer_list_end + IMPORT _tx_timer_expired_time_slice + IMPORT _tx_timer_expired + IMPORT _tx_thread_time_slice + IMPORT _tx_timer_expiration_process + IMPORT _tx_thread_preempt_disable + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_execute_ptr + + AREA ||.text||, CODE, READONLY + PRESERVE8 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-M3/AC5 */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + EXPORT _tx_timer_interrupt +_tx_timer_interrupt + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice + + // } + +__tx_timer_not_ts_expiration + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif + ALIGN + LTORG + END diff --git a/ports/cortex_m3/ac6/inc/tx_port.h b/ports/cortex_m3/ac6/inc/tx_port.h new file mode 100644 index 0000000..592cecf --- /dev/null +++ b/ports/cortex_m3/ac6/inc/tx_port.h @@ -0,0 +1,728 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/AC6 */ +/* 6.1.12 */ +/* */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */ +/* the ARMv7-M architecture and compilers into one common file. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comments, updated */ +/* typedef to fix misra */ +/* violation, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#include "tx_ghs.h" +#endif /* __ghs__ */ + + +#if !defined(__GNUC__) && !defined(__CC_ARM) +#define __get_control_value __get_CONTROL +#define __set_control_value __set_CONTROL +#endif + +#ifndef __GNUC__ +#define __get_ipsr_value __get_IPSR +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long long ULONG64; +typedef short SHORT; +typedef unsigned short USHORT; +#define ULONG64_DEFINED + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + +/* By default, ThreadX for Cortex-M uses the PRIMASK register to enable/disable interrupts. +If using BASEPRI is desired, define the following two symbols for both c and assembly files: +TX_PORT_USE_BASEPRI - This tells ThreadX to use BASEPRI instead of PRIMASK. +TX_PORT_BASEPRI = (priority_mask << (8 - number_priority_bits)) - this defines the maximum priority level to mask. +Any interrupt with a higher priority than priority_mask will not be masked, thus the interrupt will run. +*/ + +/* Define various constants for the ThreadX Cortex-M port. */ + +#define TX_INT_DISABLE 1 /* Disable interrupts */ +#define TX_INT_ENABLE 0 /* Enable interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0xE0001004) +#endif +#else +ULONG _tx_misra_time_stamp_get(VOID); +#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get() +#endif + +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#ifdef TX_MISRA_ENABLE +#define TX_DISABLE_INLINE +#else +#define TX_INLINE_INITIALIZATION +#endif + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifndef TX_MISRA_ENABLE +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#elif defined(__ghs__) +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#else +#define TX_THREAD_EXTENSION_2 +#endif + + +#define TX_THREAD_EXTENSION_3 + + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#if (__VER__ < 8000000) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0); +#else +void *_tx_iar_create_per_thread_tls_area(void); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); +void __iar_Initlocks(void); + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0); +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); +#endif +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + +#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) + +#ifdef TX_MISRA_ENABLE + +ULONG _tx_misra_control_get(void); +void _tx_misra_control_set(ULONG value); +ULONG _tx_misra_fpccr_get(void); +void _tx_misra_vfp_touch(void); + +#else /* TX_MISRA_ENABLE not defined */ + +/* Define some helper functions (these are intrinsics in some compilers). */ +#ifdef __GNUC__ /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + +__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value) +{ + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); + +#elif defined(__CC_ARM) /* ARM Compiler 5 */ + +__attribute__( ( always_inline ) ) ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm volatile ("MRS control_value,CONTROL"); + return(control_value); +} + +__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value) +{ + __asm__ volatile ("MSR CONTROL,control_value"); +} +/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */ +void _tx_vfp_access(void); +#define TX_VFP_TOUCH() _tx_vfp_access(); + +#elif defined(__ICCARM__) /* IAR */ +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); +#endif /* Helper functions for different compilers */ + +#endif /* TX_MISRA_ENABLE */ + + +/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA + in order to ensure no lazy stacking will occur. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } +#else + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } + +#endif + +/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR. + If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating + this one, so if the FPCCR.LSPACT bit is set, we need to save the CONTROL.FPCA state, touch the FPU to flush + the lazy FPU save, then restore the CONTROL.FPCA state. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((volatile ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + TX_VFP_TOUCH(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + } \ + } \ + } +#else + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = _tx_misra_fpccr_get(); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + _tx_misra_vfp_touch(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + } \ + } \ + } +#endif + +#else /* No VFP in use */ + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */ + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define the get system state macro. */ + +#ifndef TX_THREAD_GET_SYSTEM_STATE +#ifndef TX_MISRA_ENABLE + +#ifdef __CC_ARM /* ARM Compiler 5 */ + +register unsigned int _ipsr __asm("ipsr"); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr) + +#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void) +{ +unsigned int ipsr_value; + __asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) ); + return(ipsr_value); +} + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value()) + +#elif defined(__ICCARM__) /* IAR */ + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR()) + +#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */ + +#else /* TX_MISRA_ENABLE is defined, use MISRA function. */ +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif /* TX_MISRA_ENABLE */ +#endif /* TX_THREAD_GET_SYSTEM_STATE */ + + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h + for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always + zero after initialization for Cortex-M ports. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable); +#endif + +/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to + prevent early scheduling on Cortex-M parts. */ + +#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++; + + + + +#ifndef TX_DISABLE_INLINE + +/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */ +#ifdef __ICCARM__ /* IAR Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m))); +#elif defined(__CC_ARM) /* AC5 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m))); +#elif defined(__GNUC__) /* GCC and AC6 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); +#endif + + + +/* Define the interrupt disable/restore macros for each compiler. */ + +#if defined(__GNUC__) || defined(__ICCARM__) + +/*** GCC/AC6 and IAR ***/ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture)); +#else + __asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture)); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +__attribute__( ( always_inline ) ) static inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value)); +} +#else +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + __asm__ volatile ("CPSIE i": : : "memory"); +} +#endif + +__attribute__( ( always_inline ) ) static inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); + //__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory"); +#else + __asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory"); +#endif +} + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i" : : : "memory"); +#endif + return(int_posture); +} + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_interrupt_posture(); +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(0); +#else + __enable_interrupts(); +#endif + __restore_interrupt(interrupt_save); + } +} + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End GCC/AC6 and IAR ***/ + +#elif defined(__CC_ARM) + +/*** AC5 ***/ + +static __inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS #posture, BASEPRI"); +#else + __asm__ volatile ("MRS #posture, PRIMASK"); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +static __inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI, #basepri_value"); +} +#endif + +static __inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i"); +#endif + return(int_posture); +} + +static __inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); +#else + __asm__ volatile ("MSR PRIMASK, #int_posture"); +#endif +} + +static void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (_ipsr == 0) + { +#ifdef TX_PORT_USE_BASEPRI + interrupt_save = __get_interrupt_posture(); + __set_basepri_value(0); + __set_basepri_value(interrupt_save); +#else + interrupt_save = __disable_irq(); + __enable_irq(); + if (interrupt_save != 0) + __disable_irq(); +#endif + } +} + + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End AC5 ***/ + +#endif /* Interrupt disable/restore macros for each compiler. */ + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else /* TX_DISABLE_INLINE is defined */ + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); +#endif /* TX_DISABLE_INLINE */ + + +/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing + thread. These are no longer needed, but are preserved for backward compatibility only. */ + +void tx_thread_fpu_enable(void); +void tx_thread_fpu_disable(void); + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) 2024 Microsoft Corporation. * ThreadX Cortex-M3/AC6 Version 6.4.2 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + + +#endif diff --git a/ports/cortex_m3/ac6/src/tx_misra.S b/ports/cortex_m3/ac6/src/tx_misra.S new file mode 100644 index 0000000..8ac0c62 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_misra.S @@ -0,0 +1,722 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX MISRA Compliance */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + .global __aeabi_memset + .global _tx_thread_current_ptr + .global _tx_thread_interrupt_disable + .global _tx_thread_interrupt_restore + .global _tx_thread_stack_analyze + .global _tx_thread_stack_error_handler + .global _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_trace_buffer_current_ptr + .global _tx_trace_buffer_end_ptr + .global _tx_trace_buffer_start_ptr + .global _tx_trace_event_enable_bits + .global _tx_trace_full_notify_function + .global _tx_trace_header_ptr +#endif + + .global _tx_misra_always_true + .global _tx_misra_block_pool_to_uchar_pointer_convert + .global _tx_misra_byte_pool_to_uchar_pointer_convert + .global _tx_misra_char_to_uchar_pointer_convert + .global _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_entry_to_uchar_pointer_convert +#endif + .global _tx_misra_indirect_void_to_uchar_pointer_convert + .global _tx_misra_memset + .global _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_object_to_uchar_pointer_convert +#endif + .global _tx_misra_pointer_to_ulong_convert + .global _tx_misra_status_get + .global _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_time_stamp_get +#endif + .global _tx_misra_timer_indirect_to_void_pointer_convert + .global _tx_misra_timer_pointer_add + .global _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_trace_event_insert +#endif + .global _tx_misra_uchar_pointer_add + .global _tx_misra_uchar_pointer_dif + .global _tx_misra_uchar_pointer_sub + .global _tx_misra_uchar_to_align_type_pointer_convert + .global _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_entry_pointer_convert + .global _tx_misra_uchar_to_header_pointer_convert +#endif + .global _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + .global _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_object_pointer_convert +#endif + .global _tx_misra_uchar_to_void_pointer_convert + .global _tx_misra_ulong_pointer_add + .global _tx_misra_ulong_pointer_dif + .global _tx_misra_ulong_pointer_sub + .global _tx_misra_ulong_to_pointer_convert + .global _tx_misra_ulong_to_thread_pointer_convert + .global _tx_misra_user_timer_pointer_get + .global _tx_misra_void_to_block_pool_pointer_convert + .global _tx_misra_void_to_byte_pool_pointer_convert + .global _tx_misra_void_to_event_flags_pointer_convert + .global _tx_misra_void_to_indirect_uchar_pointer_convert + .global _tx_misra_void_to_mutex_pointer_convert + .global _tx_misra_void_to_queue_pointer_convert + .global _tx_misra_void_to_semaphore_pointer_convert + .global _tx_misra_void_to_thread_pointer_convert + .global _tx_misra_void_to_uchar_pointer_convert + .global _tx_misra_void_to_ulong_pointer_convert + .global _tx_misra_ipsr_get + .global _tx_misra_control_get + .global _tx_misra_control_set +#ifdef __ARM_FP + .global _tx_misra_fpccr_get + .global _tx_misra_vfp_touch +#endif + + .global _tx_misra_event_flags_group_not_used + .global _tx_misra_event_flags_set_notify_not_used + .global _tx_misra_queue_not_used + .global _tx_misra_queue_send_notify_not_used + .global _tx_misra_semaphore_not_used + .global _tx_misra_semaphore_put_notify_not_used + .global _tx_misra_thread_entry_exit_notify_not_used + .global _tx_misra_thread_not_used + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 + .syntax unified + .thumb_func +_tx_misra_memset: + PUSH {R4,LR} + MOVS R4,R0 + MOVS R0,R2 + MOVS R2,R1 + MOVS R1,R0 + MOVS R0,R4 + BL __aeabi_memset + POP {R4,PC} // return + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_sub: + RSBS R1,R1,#+0 + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_dif: + SUBS R0,R0,R1 + BX LR // return + + +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ +/** */ +/** This single function serves all of the below prototypes. */ +/** */ +/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */ +/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */ +/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */ +/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */ +/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */ +/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */ +/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */ +/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */ +/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */ +/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */ +/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */ +/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */ +/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */ +/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */ +/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */ +/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */ +/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */ +/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */ +/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */ +/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */ +/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */ +/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */ +/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */ +/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */ +/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */ +/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */ +/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */ +/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */ +/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */ +/** VOID _tx_misra_event_flags_group_not_used(TX_EVENT_FLAGS_GROUP *group_ptr); */ +/** VOID _tx_misra_event_flags_set_notify_not_used(VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); */ +/** VOID _tx_misra_queue_not_used(TX_QUEUE *queue_ptr); */ +/** VOID _tx_misra_queue_send_notify_not_used(VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); */ +/** VOID _tx_misra_semaphore_not_used(TX_SEMAPHORE *semaphore_ptr); */ +/** VOID _tx_misra_semaphore_put_notify_not_used(VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); */ +/** VOID _tx_misra_thread_not_used(TX_THREAD *thread_ptr); */ +/** VOID _tx_misra_thread_entry_exit_notify_not_used(VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + .text + .thumb_func +_tx_misra_pointer_to_ulong_convert: +_tx_misra_ulong_to_pointer_convert: +_tx_misra_indirect_void_to_uchar_pointer_convert: +_tx_misra_uchar_to_indirect_uchar_pointer_convert: +_tx_misra_block_pool_to_uchar_pointer_convert: +_tx_misra_void_to_block_pool_pointer_convert: +_tx_misra_void_to_uchar_pointer_convert: +_tx_misra_uchar_to_block_pool_pointer_convert: +_tx_misra_void_to_indirect_uchar_pointer_convert: +_tx_misra_void_to_byte_pool_pointer_convert: +_tx_misra_byte_pool_to_uchar_pointer_convert: +_tx_misra_uchar_to_align_type_pointer_convert: +_tx_misra_uchar_to_indirect_byte_pool_pointer_convert: +_tx_misra_void_to_event_flags_pointer_convert: +_tx_misra_void_to_ulong_pointer_convert: +_tx_misra_void_to_mutex_pointer_convert: +_tx_misra_void_to_queue_pointer_convert: +_tx_misra_void_to_semaphore_pointer_convert: +_tx_misra_uchar_to_void_pointer_convert: +_tx_misra_ulong_to_thread_pointer_convert: +_tx_misra_timer_indirect_to_void_pointer_convert: +_tx_misra_const_char_to_char_pointer_convert: +_tx_misra_void_to_thread_pointer_convert: +#ifdef TX_ENABLE_EVENT_TRACE +_tx_misra_object_to_uchar_pointer_convert: +_tx_misra_uchar_to_object_pointer_convert: +_tx_misra_uchar_to_header_pointer_convert: +_tx_misra_uchar_to_entry_pointer_convert: +_tx_misra_entry_to_uchar_pointer_convert: +#endif +_tx_misra_char_to_uchar_pointer_convert: +_tx_misra_event_flags_group_not_used: +_tx_misra_event_flags_set_notify_not_used: +_tx_misra_queue_not_used: +_tx_misra_queue_send_notify_not_used: +_tx_misra_semaphore_not_used: +_tx_misra_semaphore_put_notify_not_used: +_tx_misra_thread_entry_exit_notify_not_used: +_tx_misra_thread_not_used: + + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_sub: + MVNS R2,#+3 + MULS R1,R2,R1 + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_dif: + SUBS R0,R0,R1 + ASRS R0,R0,#+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */ +/** UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_message_copy: + PUSH {R4,R5} + LDR R3,[R0, #+0] + LDR R4,[R1, #+0] + LDR R5,[R3, #+0] + STR R5,[R4, #+0] + ADDS R4,R4,#+4 + ADDS R3,R3,#+4 + CMP R2,#+2 + BCC.N _tx_misra_message_copy_0 + SUBS R2,R2,#+1 + B.N _tx_misra_message_copy_1 +_tx_misra_message_copy_2: + LDR R5,[R3, #+0] + STR R5,[R4, #+0] + ADDS R4,R4,#+4 + ADDS R3,R3,#+4 + SUBS R2,R2,#+1 +_tx_misra_message_copy_1: + CMP R2,#+0 + BNE.N _tx_misra_message_copy_2 +_tx_misra_message_copy_0: + STR R3,[R0, #+0] + STR R4,[R1, #+0] + POP {R4,R5} + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */ +/** TX_TIMER_INTERNAL **ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_timer_pointer_dif: + SUBS R0,R0,R1 + ASRS R0,R0,#+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */ +/** **ptr1, ULONG size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_timer_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */ +/** *internal_timer, TX_TIMER **user_timer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_user_timer_pointer_get: + SUBS R0,#8 + STR R0,[R1, #+0] + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */ +/** VOID **highest_stack); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_thread_stack_check: + PUSH {R3-R5,LR} + MOVS R4,R0 + MOVS R5,R1 + BL _tx_thread_interrupt_disable + CMP R4,#+0 + BEQ.N _tx_misra_thread_stack_check_0 + LDR R1,[R4, #+0] + LDR R2,=0x54485244 + CMP R1,R2 + BNE.N _tx_misra_thread_stack_check_0 + LDR R1,[R4, #+8] + LDR R2,[R5, #+0] + CMP R1,R2 + BCS.N _tx_misra_thread_stack_check_1 + LDR R1,[R4, #+8] + STR R1,[R5, #+0] +_tx_misra_thread_stack_check_1: + LDR R1,[R4, #+12] + LDR R1,[R1, #+0] + CMP R1,#-269488145 + BNE.N _tx_misra_thread_stack_check_2 + LDR R1,[R4, #+16] + LDR R1,[R1, #+1] + CMP R1,#-269488145 + BNE.N _tx_misra_thread_stack_check_2 + LDR R1,[R5, #+0] + LDR R2,[R4, #+12] + CMP R1,R2 + BCS.N _tx_misra_thread_stack_check_3 +_tx_misra_thread_stack_check_2: + BL _tx_thread_interrupt_restore + MOVS R0,R4 + BL _tx_thread_stack_error_handler + BL _tx_thread_interrupt_disable +_tx_misra_thread_stack_check_3: + LDR R1,[R5, #+0] + LDR R1,[R1, #-4] + CMP R1,#-269488145 + BEQ.N _tx_misra_thread_stack_check_0 + BL _tx_thread_interrupt_restore + MOVS R0,R4 + BL _tx_thread_stack_analyze + BL _tx_thread_interrupt_disable +_tx_misra_thread_stack_check_0: + BL _tx_thread_interrupt_restore + POP {R0,R4,R5,PC} // return + +#ifdef TX_ENABLE_EVENT_TRACE + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_trace_event_insert(ULONG event_id, */ +/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */ +/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_trace_event_insert: + PUSH {R3-R7,LR} + LDR.N R4,DataTable2_1 + LDR R4,[R4, #+0] + CMP R4,#+0 + BEQ.N _tx_misra_trace_event_insert_0 + LDR.N R5,DataTable2_2 + LDR R5,[R5, #+0] + LDR R6,[SP, #+28] + TST R5,R6 + BEQ.N _tx_misra_trace_event_insert_0 + LDR.N R5,DataTable2_3 + LDR R5,[R5, #+0] + LDR.N R6,DataTable2_4 + LDR R6,[R6, #+0] + CMP R5,#+0 + BNE.N _tx_misra_trace_event_insert_1 + LDR R5,[R6, #+44] + LDR R7,[R6, #+60] + LSLS R7,R7,#+16 + ORRS R7,R7,#0x80000000 + ORRS R5,R7,R5 + B.N _tx_misra_trace_event_insert_2 +_tx_misra_trace_event_insert_1: + CMP R5,#-252645136 + BCS.N _tx_misra_trace_event_insert_3 + MOVS R5,R6 + MOVS R6,#-1 + B.N _tx_misra_trace_event_insert_2 +_tx_misra_trace_event_insert_3: + MOVS R6,#-252645136 + MOVS R5,#+0 +_tx_misra_trace_event_insert_2: + STR R6,[R4, #+0] + STR R5,[R4, #+4] + STR R0,[R4, #+8] + LDR R0,[SP, #+32] + STR R0,[R4, #+12] + STR R1,[R4, #+16] + STR R2,[R4, #+20] + STR R3,[R4, #+24] + LDR R0,[SP, #+24] + STR R0,[R4, #+28] + ADDS R4,R4,#+32 + LDR.N R0,DataTable2_5 + LDR R0,[R0, #+0] + CMP R4,R0 + BCC.N _tx_misra_trace_event_insert_4 + LDR.N R0,DataTable2_6 + LDR R4,[R0, #+0] + LDR.N R0,DataTable2_1 + STR R4,[R0, #+0] + LDR.N R0,DataTable2_7 + LDR R0,[R0, #+0] + STR R4,[R0, #+32] + LDR.N R0,DataTable2_8 + LDR R0,[R0, #+0] + CMP R0,#+0 + BEQ.N _tx_misra_trace_event_insert_0 + LDR.N R0,DataTable2_7 + LDR R0,[R0, #+0] + LDR.N R1,DataTable2_8 + LDR R1,[R1, #+0] + BLX R1 + B.N _tx_misra_trace_event_insert_0 +_tx_misra_trace_event_insert_4: + LDR.N R0,DataTable2_1 + STR R4,[R0, #+0] + LDR.N R0,DataTable2_7 + LDR R0,[R0, #+0] + STR R4,[R0, #+32] +_tx_misra_trace_event_insert_0: + POP {R0,R4-R7,PC} // return + + + .data +DataTable2_1: + .word _tx_trace_buffer_current_ptr + + .data +DataTable2_2: + .word _tx_trace_event_enable_bits + + .data +DataTable2_5: + .word _tx_trace_buffer_end_ptr + + .data +DataTable2_6: + .word _tx_trace_buffer_start_ptr + + .data +DataTable2_7: + .word _tx_trace_header_ptr + + .data +DataTable2_8: + .word _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + .data +DataTable2_3: + .word _tx_thread_system_state + + .data +DataTable2_4: + .word _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARM_FP + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_fpccr_get: + LDR r0, =0xE000EF34 // Build FPCCR address + LDR r0, [r0] // Load FPCCR value + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_vfp_touch(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + .data + .word 0 diff --git a/ports/cortex_m3/ac6/src/tx_thread_context_restore.S b/ports/cortex_m3/ac6/src/tx_thread_context_restore.S new file mode 100644 index 0000000..949478b --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_context_restore.S @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_exit +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } diff --git a/ports/cortex_m3/ac6/src/tx_thread_context_save.S b/ports/cortex_m3/ac6/src/tx_thread_context_save.S new file mode 100644 index 0000000..f6a1039 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_context_save.S @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_enter +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } diff --git a/ports/cortex_m3/ac6/src/tx_thread_interrupt_control.S b/ports/cortex_m3/ac6/src/tx_thread_interrupt_control.S new file mode 100644 index 0000000..dcc24d4 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_interrupt_control.S @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } diff --git a/ports/cortex_m3/ac6/src/tx_thread_interrupt_disable.S b/ports/cortex_m3/ac6/src/tx_thread_interrupt_disable.S new file mode 100644 index 0000000..a1a0b45 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_interrupt_disable.S @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .global _tx_thread_interrupt_disable + .thumb_func +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } diff --git a/ports/cortex_m3/ac6/src/tx_thread_interrupt_restore.S b/ports/cortex_m3/ac6/src/tx_thread_interrupt_restore.S new file mode 100644 index 0000000..bc5b910 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_interrupt_restore.S @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .global _tx_thread_interrupt_restore + .thumb_func +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } diff --git a/ports/cortex_m3/ac6/src/tx_thread_schedule.S b/ports/cortex_m3/ac6/src/tx_thread_schedule.S new file mode 100644 index 0000000..5f22b3f --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_schedule.S @@ -0,0 +1,330 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +#endif +#ifdef TX_LOW_POWER + .global tx_low_power_enter + .global tx_low_power_exit +#endif + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* _tx_thread_system_return Return to system from thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + .global _tx_thread_schedule + .thumb_func +_tx_thread_schedule: + + /* This function should only ever be called on Cortex-M + from the first schedule request. Subsequent scheduling occurs + from the PendSV handling routine below. */ + + /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */ + + MOV r0, #0 // Build value for TX_FALSE + LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag + STR r0, [r2, #0] // Clear preempt disable flag + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __ARM_PCS_VFP + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* Enable interrupts */ + CPSIE i + + /* Enter the scheduler for the first time. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + DSB // Complete all memory accesses + ISB // Flush pipeline + + /* Wait here for the PendSV to take place. */ + +__tx_wait_here: + B __tx_wait_here // Wait for the PendSV to happen +// } + + /* Generic context switching PendSV handler. */ + + .global PendSV_Handler + .global __tx_PendSVHandler + .syntax unified + .thumb_func +PendSV_Handler: + .thumb_func +__tx_PendSVHandler: + + /* Get current thread value and new thread pointer. */ + +__tx_ts_handler: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread exit function to indicate the thread is no longer executing. */ +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif /* TX_PORT_USE_BASEPRI */ + PUSH {r0, lr} // Save LR (and r0 just for alignment) + BL _tx_execution_thread_exit // Call the thread exit function + POP {r0, lr} // Recover LR +#ifdef TX_PORT_USE_BASEPRI + MOV r0, 0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r0 +#else + CPSIE i // Enable interrupts +#endif /* TX_PORT_USE_BASEPRI */ +#endif /* EXECUTION PROFILE */ + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + MOV r3, #0 // Build NULL value + LDR r1, [r0] // Pickup current thread pointer + + /* Determine if there is a current thread to finish preserving. */ + + CBZ r1, __tx_ts_new // If NULL, skip preservation + + /* Recover PSP and preserve current thread context. */ + + STR r3, [r0] // Set _tx_thread_current_ptr to NULL + MRS r12, PSP // Pickup PSP pointer (thread's stack pointer) + STMDB r12!, {r4-r11} // Save its remaining registers +#ifdef __ARM_PCS_VFP + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_save + VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers +_skip_vfp_save: +#endif + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + STMDB r12!, {LR} // Save LR on the stack + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + STR r12, [r1, #8] // Save the thread stack pointer + CBZ r5, __tx_ts_new // If not active, skip processing + + /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */ + + STR r5, [r1, #24] // Save current time-slice + + /* Clear the global time-slice. */ + + STR r3, [r4] // Clear time-slice + + /* Executing thread is now completely preserved!!! */ + +__tx_ts_new: + + /* Now we are looking for a new thread to execute! */ + +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Is there another thread ready to execute? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + STR r1, [r0] // Setup the current thread pointer to the new thread +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + + /* Increment the thread run count. */ + +__tx_ts_restore: + LDR r7, [r1, #4] // Pickup the current thread run count + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + LDR r5, [r1, #24] // Pickup thread's current time-slice + ADD r7, r7, #1 // Increment the thread run count + STR r7, [r1, #4] // Store the new run count + + /* Setup global time-slice with thread's current time-slice. */ + + STR r5, [r4] // Setup global time-slice + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread entry function to indicate the thread is executing. */ + PUSH {r0, r1} // Save r0 and r1 + BL _tx_execution_thread_enter // Call the thread execution enter function + POP {r0, r1} // Recover r0 and r1 +#endif + + /* Restore the thread context and PSP. */ + + LDR r12, [r1, #8] // Pickup thread's stack pointer + LDMIA r12!, {LR} // Pickup LR +#ifdef __ARM_PCS_VFP + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_restore // If not, skip VFP restore + VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers +_skip_vfp_restore: +#endif + LDMIA r12!, {r4-r11} // Recover thread's registers + MSR PSP, r12 // Setup the thread's stack pointer + + /* Return to thread. */ + + BX lr // Return to thread! + + /* The following is the idle wait processing... in this case, no threads are ready for execution and the + system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts + are disabled to allow use of WFI for waiting for a thread to arrive. */ + +__tx_ts_wait: +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Pickup the next thread to execute pointer + STR r1, [r0] // Store it in the current pointer + CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready! + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_enter // Possibly enter low power mode + POP {r0-r3} +#endif + +#ifdef TX_ENABLE_WFI + DSB // Ensure no outstanding memory transactions + WFI // Wait for interrupt + ISB // Ensure pipeline is flushed +#endif + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_exit // Exit low power mode + POP {r0-r3} +#endif + +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_wait // Loop to continue waiting + + /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are + already in the handler! */ + +__tx_ts_ready: + MOV r7, #0x08000000 // Build clear PendSV value + MOV r8, #0xE000E000 // Build base NVIC address + STR r7, [r8, #0xD04] // Clear any PendSV + + /* Re-enable interrupts and restore new thread. */ +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_restore // Restore the thread +// } + +#ifdef __ARM_PCS_VFP + + .global tx_thread_fpu_enable + .thumb_func +tx_thread_fpu_enable: + .global tx_thread_fpu_disable + .thumb_func +tx_thread_fpu_disable: + + /* Automatic VPF logic is supported, this function is present only for + backward compatibility purposes and therefore simply returns. */ + + BX LR // Return to caller + +#endif diff --git a/ports/cortex_m3/ac6/src/tx_thread_stack_build.S b/ports/cortex_m3/ac6/src/tx_thread_stack_build.S new file mode 100644 index 0000000..d5cc0b4 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_stack_build.S @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .global _tx_thread_stack_build + .thumb_func +_tx_thread_stack_build: + + /* Build a fake interrupt frame. The form of the fake interrupt stack + on the Cortex-M should look like the following after it is built: + + Stack Top: + LR Interrupted LR (LR at time of PENDSV) + r4 Initial value for r4 + r5 Initial value for r5 + r6 Initial value for r6 + r7 Initial value for r7 + r8 Initial value for r8 + r9 Initial value for r9 + r10 Initial value for r10 + r11 Initial value for r11 + r0 Initial value for r0 (Hardware stack starts here!!) + r1 Initial value for r1 + r2 Initial value for r2 + r3 Initial value for r3 + r12 Initial value for r12 + lr Initial value for lr + pc Initial value for pc + xPSR Initial value for xPSR + + Stack Bottom: (higher memory address) */ + + LDR r2, [r0, #16] // Pickup end of stack area + BIC r2, r2, #0x7 // Align frame for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size + LDR r3, =0xFFFFFFFD // Build initial LR value + STR r3, [r2, #0] // Save on the stack + + /* Actually build the stack frame. */ + + MOV r3, #0 // Build initial register value + STR r3, [r2, #4] // Store initial r4 + STR r3, [r2, #8] // Store initial r5 + STR r3, [r2, #12] // Store initial r6 + STR r3, [r2, #16] // Store initial r7 + STR r3, [r2, #20] // Store initial r8 + STR r3, [r2, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + STR r3, [r2, #44] // Store initial r2 + STR r3, [r2, #48] // Store initial r3 + STR r3, [r2, #52] // Store initial r12 + MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value + STR r3, [r2, #56] // Store initial lr + STR r1, [r2, #60] // Store initial pc + MOV r3, #0x01000000 // Only T-bit need be set + STR r3, [r2, #64] // Store initial xPSR + + /* Setup stack pointer. */ + // thread_ptr -> tx_thread_stack_ptr = r2; + + STR r2, [r0, #8] // Save stack pointer in thread's + // control block + BX lr // Return to caller +// } diff --git a/ports/cortex_m3/ac6/src/tx_thread_system_return.S b/ports/cortex_m3/ac6/src/tx_thread_system_return.S new file mode 100644 index 0000000..e747160 --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_thread_system_return.S @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .thumb_func + .global _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } diff --git a/ports/cortex_m3/ac6/src/tx_timer_interrupt.S b/ports/cortex_m3/ac6/src/tx_timer_interrupt.S new file mode 100644 index 0000000..ee13bef --- /dev/null +++ b/ports/cortex_m3/ac6/src/tx_timer_interrupt.S @@ -0,0 +1,260 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_timer_time_slice + .global _tx_timer_system_clock + .global _tx_timer_current_ptr + .global _tx_timer_list_start + .global _tx_timer_list_end + .global _tx_timer_expired_time_slice + .global _tx_timer_expired + .global _tx_thread_time_slice + .global _tx_timer_expiration_process + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-M3/AC6 */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + .global _tx_timer_interrupt + .thumb_func +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif diff --git a/ports/cortex_m3/ghs/inc/tx_el.h b/ports/cortex_m3/ghs/inc/tx_el.h new file mode 100644 index 0000000..b892692 --- /dev/null +++ b/ports/cortex_m3/ghs/inc/tx_el.h @@ -0,0 +1,764 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX/GHS Event Log (EL) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_el.h PORTABLE C/GHS */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the ThreadX event log functions for the GHS MULTI */ +/* EventAnalyzer. It is assumed that tx_api.h and tx_port.h have */ +/* already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ + +#ifndef TX_EL_H +#define TX_EL_H + + +/* Define Event Log specific data definitions. */ + +#define TX_EL_VERSION_ID 2 /* Event log version ID */ +#define TX_EL_HEADER_SIZE 24 /* Event log header size */ +#define TX_EL_TNIS 16 /* Number of thread names supported */ + /* If the application needs to */ + /* track more thread names, just */ + /* increase this number and re- */ + /* build the ThreadX library. */ +#define TX_EL_TNI_ENTRY_SIZE 44 /* Thread name entries are 44 bytes */ +#define TX_EL_TNI_NAME_SIZE 34 /* Thread name size in TNI */ +#define TX_EL_NO_MORE_TNI_ROOM 1 /* Error return from thread register*/ +#define TX_EL_NAME_NOT_FOUND 2 /* Error return from un-register */ +#define TX_EL_EVENT_SIZE 32 /* Number of bytes in each event */ +#define TX_EL_VALID_ENTRY 1 /* Valid log entry */ +#define TX_EL_INVALID_ENTRY 0 /* Invalid log entry */ + + +/* Define necessary offsets. */ + +#define TX_EL_TNI_VALID_OFFSET 34 +#define TX_EL_TNI_THREAD_ID_OFFSET 36 +#define TX_EL_TNI_THREAD_PRIORITY_OFF 40 +#define TX_EL_EVENT_TYPE_OFFSET 0 +#define TX_EL_EVENT_SUBTYPE_OFFSET 2 +#define TX_EL_EVENT_TIME_UPPER_OFFSET 4 +#define TX_EL_EVENT_TIME_LOWER_OFFSET 8 +#define TX_EL_EVENT_THREAD_OFFSET 12 +#define TX_EL_EVENT_INFO_1_OFFSET 16 +#define TX_EL_EVENT_INFO_2_OFFSET 20 +#define TX_EL_EVENT_INFO_3_OFFSET 24 +#define TX_EL_EVENT_INFO_4_OFFSET 28 + + +/* Undefine constants that might be been defined previously by tx_api.h. */ + +#undef TX_EL_INITIALIZE +#undef TX_EL_THREAD_REGISTER +#undef TX_EL_THREAD_UNREGISTER +#undef TX_EL_THREAD_STATUS_CHANGE_INSERT +#undef TX_EL_BYTE_ALLOCATE_INSERT +#undef TX_EL_BYTE_POOL_CREATE_INSERT +#undef TX_EL_BYTE_POOL_DELETE_INSERT +#undef TX_EL_BYTE_RELEASE_INSERT +#undef TX_EL_BLOCK_ALLOCATE_INSERT +#undef TX_EL_BLOCK_POOL_CREATE_INSERT +#undef TX_EL_BLOCK_POOL_DELETE_INSERT +#undef TX_EL_BLOCK_RELEASE_INSERT +#undef TX_EL_EVENT_FLAGS_CREATE_INSERT +#undef TX_EL_EVENT_FLAGS_DELETE_INSERT +#undef TX_EL_EVENT_FLAGS_GET_INSERT +#undef TX_EL_EVENT_FLAGS_SET_INSERT +#undef TX_EL_INTERRUPT_CONTROL_INSERT +#undef TX_EL_QUEUE_CREATE_INSERT +#undef TX_EL_QUEUE_DELETE_INSERT +#undef TX_EL_QUEUE_FLUSH_INSERT +#undef TX_EL_QUEUE_RECEIVE_INSERT +#undef TX_EL_QUEUE_SEND_INSERT +#undef TX_EL_SEMAPHORE_CREATE_INSERT +#undef TX_EL_SEMAPHORE_DELETE_INSERT +#undef TX_EL_SEMAPHORE_GET_INSERT +#undef TX_EL_SEMAPHORE_PUT_INSERT +#undef TX_EL_THREAD_CREATE_INSERT +#undef TX_EL_THREAD_DELETE_INSERT +#undef TX_EL_THREAD_IDENTIFY_INSERT +#undef TX_EL_THREAD_PREEMPTION_CHANGE_INSERT +#undef TX_EL_THREAD_PRIORITY_CHANGE_INSERT +#undef TX_EL_THREAD_RELINQUISH_INSERT +#undef TX_EL_THREAD_RESUME_INSERT +#undef TX_EL_THREAD_SLEEP_INSERT +#undef TX_EL_THREAD_SUSPEND_INSERT +#undef TX_EL_THREAD_TERMINATE_INSERT +#undef TX_EL_THREAD_TIME_SLICE_CHANGE_INSERT +#undef TX_EL_TIME_GET_INSERT +#undef TX_EL_TIME_SET_INSERT +#undef TX_EL_TIMER_ACTIVATE_INSERT +#undef TX_EL_TIMER_CHANGE_INSERT +#undef TX_EL_TIMER_CREATE_INSERT +#undef TX_EL_TIMER_DEACTIVATE_INSERT +#undef TX_EL_TIMER_DELETE_INSERT +#undef TX_EL_BLOCK_POOL_INFO_GET_INSERT +#undef TX_EL_BLOCK_POOL_PRIORITIZE_INSERT +#undef TX_EL_BYTE_POOL_INFO_GET_INSERT +#undef TX_EL_BYTE_POOL_PRIORITIZE_INSERT +#undef TX_EL_EVENT_FLAGS_INFO_GET_INSERT +#undef TX_EL_MUTEX_CREATE_INSERT +#undef TX_EL_MUTEX_DELETE_INSERT +#undef TX_EL_MUTEX_GET_INSERT +#undef TX_EL_MUTEX_INFO_GET_INSERT +#undef TX_EL_MUTEX_PRIORITIZE_INSERT +#undef TX_EL_MUTEX_PUT_INSERT +#undef TX_EL_QUEUE_INFO_GET_INSERT +#undef TX_EL_QUEUE_FRONT_SEND_INSERT +#undef TX_EL_QUEUE_PRIORITIZE_INSERT +#undef TX_EL_SEMAPHORE_INFO_GET_INSERT +#undef TX_EL_SEMAPHORE_PRIORITIZE_INSERT +#undef TX_EL_THREAD_INFO_GET_INSERT +#undef TX_EL_THREAD_WAIT_ABORT_INSERT +#undef TX_EL_TIMER_INFO_GET_INSERT +#undef TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_EVENT_FLAGS_SET_NOTIFY_INSERT +#undef TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_QUEUE_SEND_NOTIFY_INSERT +#undef TX_EL_SEMAPHORE_CEILING_PUT_INSERT +#undef TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_SEMAPHORE_PUT_NOTIFY_INSERT +#undef TX_EL_THREAD_ENTRY_EXIT_NOTIFY_INSERT +#undef TX_EL_THREAD_RESET_INSERT +#undef TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT +#undef TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT +#undef TX_EL_TIMER_PERFORMANCE_INFO_GET_INSERT +#undef TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET_INSERT + + +/* Define Event Types. */ + +#define TX_EL_THREAD_CHANGE 1 +#define TX_EL_INTERRUPT 2 +#define TX_EL_THREADX_CALL 3 +#define TX_EL_USER_EVENT 4 +#define TX_EL_THREAD_STATUS_CHANGE 5 +#define TX_EL_REFRESH 6 /* Not implemented */ +#define TX_EL_TIMER 7 /* Not implemented */ +#define TX_EL_TIMESOURCE_DELTA 8 /* Not implemented */ + + +/* Define TX_EL_THREADX_CALL event sub-types. */ + +#define TX_EL_BYTE_ALLOCATE 0 +#define TX_EL_BYTE_POOL_CREATE 1 +#define TX_EL_BYTE_POOL_DELETE 2 +#define TX_EL_BYTE_RELEASE 3 +#define TX_EL_BLOCK_ALLOCATE 4 +#define TX_EL_BLOCK_POOL_CREATE 5 +#define TX_EL_BLOCK_POOL_DELETE 6 +#define TX_EL_BLOCK_RELEASE 7 +#define TX_EL_EVENT_FLAGS_CREATE 8 +#define TX_EL_EVENT_FLAGS_DELETE 9 +#define TX_EL_EVENT_FLAGS_GET 10 +#define TX_EL_EVENT_FLAGS_SET 11 +#define TX_EL_INTERRUPT_CONTROL 12 +#define TX_EL_QUEUE_CREATE 13 +#define TX_EL_QUEUE_DELETE 14 +#define TX_EL_QUEUE_FLUSH 15 +#define TX_EL_QUEUE_RECEIVE 16 +#define TX_EL_QUEUE_SEND 17 +#define TX_EL_SEMAPHORE_CREATE 18 +#define TX_EL_SEMAPHORE_DELETE 19 +#define TX_EL_SEMAPHORE_GET 20 +#define TX_EL_SEMAPHORE_PUT 21 +#define TX_EL_THREAD_CREATE 22 +#define TX_EL_THREAD_DELETE 23 +#define TX_EL_THREAD_IDENTIFY 24 +#define TX_EL_THREAD_PREEMPTION_CHANGE 25 +#define TX_EL_THREAD_PRIORITY_CHANGE 26 +#define TX_EL_THREAD_RELINQUISH 27 +#define TX_EL_THREAD_RESUME 28 +#define TX_EL_THREAD_SLEEP 29 +#define TX_EL_THREAD_SUSPEND 30 +#define TX_EL_THREAD_TERMINATE 31 +#define TX_EL_THREAD_TIME_SLICE_CHANGE 32 +#define TX_EL_TIME_GET 33 +#define TX_EL_TIME_SET 34 +#define TX_EL_TIMER_ACTIVATE 35 +#define TX_EL_TIMER_CHANGE 36 +#define TX_EL_TIMER_CREATE 37 +#define TX_EL_TIMER_DEACTIVATE 38 +#define TX_EL_TIMER_DELETE 39 +#define TX_EL_BLOCK_POOL_INFO_GET 40 +#define TX_EL_BLOCK_POOL_PRIORITIZE 41 +#define TX_EL_BYTE_POOL_INFO_GET 42 +#define TX_EL_BYTE_POOL_PRIORITIZE 43 +#define TX_EL_EVENT_FLAGS_INFO_GET 44 +#define TX_EL_MUTEX_CREATE 45 +#define TX_EL_MUTEX_DELETE 46 +#define TX_EL_MUTEX_GET 47 +#define TX_EL_MUTEX_INFO_GET 48 +#define TX_EL_MUTEX_PRIORITIZE 49 +#define TX_EL_MUTEX_PUT 50 +#define TX_EL_QUEUE_INFO_GET 51 +#define TX_EL_QUEUE_FRONT_SEND 52 +#define TX_EL_QUEUE_PRIORITIZE 53 +#define TX_EL_SEMAPHORE_INFO_GET 54 +#define TX_EL_SEMAPHORE_PRIORITIZE 55 +#define TX_EL_THREAD_INFO_GET 56 +#define TX_EL_THREAD_WAIT_ABORT 57 +#define TX_EL_TIMER_INFO_GET 58 +#define TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET 59 +#define TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET 60 +#define TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET 61 +#define TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET 62 +#define TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET 63 +#define TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET 64 +#define TX_EL_EVENT_FLAGS_SET_NOTIFY 65 +#define TX_EL_MUTEX_PERFORMANCE_INFO_GET 66 +#define TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET 67 +#define TX_EL_QUEUE_PERFORMANCE_INFO_GET 68 +#define TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET 69 +#define TX_EL_QUEUE_SEND_NOTIFY 70 +#define TX_EL_SEMAPHORE_CEILING_PUT 71 +#define TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET 72 +#define TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET 73 +#define TX_EL_SEMAPHORE_PUT_NOTIFY 74 +#define TX_EL_THREAD_ENTRY_EXIT_NOTIFY 75 +#define TX_EL_THREAD_RESET 76 +#define TX_EL_THREAD_PERFORMANCE_INFO_GET 77 +#define TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET 78 +#define TX_EL_THREAD_STACK_ERROR_NOTIFY 79 +#define TX_EL_TIMER_PERFORMANCE_INFO_GET 80 +#define TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET 81 + + +/* Define ThreadX sub-types. */ + +#define TX_EL_INTERRUPT_SUB_TYPE 1 +#define TX_EL_END_OF_INTERRUPT 3 + + +/* Define event logging filters, which may be used by the application program to + dynamically enable/disable events in run-time. */ + +#define TX_EL_FILTER_STATUS_CHANGE 0x0001 +#define TX_EL_FILTER_INTERRUPTS 0x0002 +#define TX_EL_FILTER_THREAD_CALLS 0x0004 +#define TX_EL_FILTER_TIMER_CALLS 0x0008 +#define TX_EL_FILTER_EVENT_FLAG_CALLS 0x0010 +#define TX_EL_FILTER_SEMAPHORE_CALLS 0x0020 +#define TX_EL_FILTER_QUEUE_CALLS 0x0040 +#define TX_EL_FILTER_BLOCK_CALLS 0x0080 +#define TX_EL_FILTER_BYTE_CALLS 0x0100 +#define TX_EL_FILTER_MUTEX_CALLS 0x0200 +#define TX_EL_FILTER_ALL_EVENTS 0xFFFF +#define TX_EL_ENABLE_ALL_EVENTS 0x0000 + + +/* Define filter macros that are inserted in-line with the other macros below. */ + +#ifdef TX_ENABLE_EVENT_FILTERS +#define TX_EL_NO_STATUS_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_STATUS_CHANGE)) { +#define TX_EL_NO_INTERRUPT_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_INTERRUPTS)) { +#define TX_EL_NO_THREAD_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_THREAD_CALLS)) { +#define TX_EL_NO_TIMER_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_TIMER_CALLS)) { +#define TX_EL_NO_EVENT_FLAG_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_EVENT_FLAG_CALLS)) { +#define TX_EL_NO_SEMAPHORE_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_SEMAPHORE_CALLS)) { +#define TX_EL_NO_QUEUE_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_QUEUE_CALLS)) { +#define TX_EL_NO_BLOCK_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_BLOCK_CALLS)) { +#define TX_EL_NO_BYTE_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_BYTE_CALLS)) { +#define TX_EL_NO_MUTEX_EVENTS if (!(_tx_el_event_filter & TX_EL_FILTER_MUTEX_CALLS)) { +#define TX_EL_END_FILTER } +#else +#define TX_EL_NO_STATUS_EVENTS +#define TX_EL_NO_INTERRUPT_EVENTS +#define TX_EL_NO_THREAD_EVENTS +#define TX_EL_NO_TIMER_EVENTS +#define TX_EL_NO_EVENT_FLAG_EVENTS +#define TX_EL_NO_SEMAPHORE_EVENTS +#define TX_EL_NO_QUEUE_EVENTS +#define TX_EL_NO_BLOCK_EVENTS +#define TX_EL_NO_BYTE_EVENTS +#define TX_EL_NO_MUTEX_EVENTS +#define TX_EL_END_FILTER +#endif + +/* Define externs and constants for non-event log source modules. This is for + the in-line macros below. */ + +#ifndef TX_EL_SOURCE_CODE +extern UCHAR *_tx_el_tni_start; +extern UCHAR **_tx_el_current_event; +extern UCHAR *_tx_el_event_area_start; +extern UCHAR *_tx_el_event_area_end; +extern UINT _tx_el_maximum_events; +extern ULONG _tx_el_total_events; +extern TX_THREAD *_tx_thread_current_ptr; +extern UINT _tx_el_event_filter; +extern ULONG _tx_el_time_base_upper; +extern ULONG _tx_el_time_base_lower; + + +/* Define macros for event logging functions. */ + +#define TX_EL_THREAD_CREATE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_THREAD_CREATE, thread_ptr, stack_start, stack_size, priority); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_SET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_EVENT_FLAGS_SET, group_ptr, flags_to_set, set_option); TX_EL_END_FILTER +#define TX_EL_THREAD_DELETE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_DELETE, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_INFO_GET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_INFO_GET, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_TIME_SLICE_CHANGE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_THREAD_TIME_SLICE_CHANGE, thread_ptr, thread_ptr -> tx_thread_new_time_slice, new_time_slice); TX_EL_END_FILTER +#define TX_EL_THREAD_TERMINATE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_TERMINATE, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_SLEEP_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_SLEEP, timer_ticks); TX_EL_END_FILTER +#define TX_EL_THREAD_SUSPEND_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_SUSPEND, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_RELINQUISH_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_THREAD_RELINQUISH); TX_EL_END_FILTER +#define TX_EL_THREAD_RESUME_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_RESUME, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_PRIORITY_CHANGE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_THREAD_PRIORITY_CHANGE, thread_ptr, thread_ptr -> tx_thread_priority, new_priority); TX_EL_END_FILTER +#define TX_EL_THREAD_PREEMPTION_CHANGE_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_THREAD_PREEMPTION_CHANGE, thread_ptr, thread_ptr -> tx_thread_preempt_threshold, new_threshold); TX_EL_END_FILTER +#define TX_EL_THREAD_WAIT_ABORT_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_WAIT_ABORT, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_ENTRY_EXIT_NOTIFY_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_THREAD_ENTRY_EXIT_NOTIFY, thread_ptr, thread_entry_exit_notify); TX_EL_END_FILTER +#define TX_EL_THREAD_RESET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_RESET, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_PERFORMANCE_INFO_GET, thread_ptr); TX_EL_END_FILTER +#define TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_THREAD_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_THREAD_STACK_ERROR_NOTIFY, stack_error_handler); TX_EL_END_FILTER +#define TX_EL_TIME_SET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIME_SET, new_time); TX_EL_END_FILTER +#define TX_EL_TIME_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIME_GET, _tx_timer_system_clock); TX_EL_END_FILTER +#define TX_EL_TIMER_DELETE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_DELETE, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_CREATE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_TIMER_CREATE, timer_ptr, initial_ticks, reschedule_ticks, auto_activate); TX_EL_END_FILTER +#define TX_EL_TIMER_CHANGE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_TIMER_CHANGE, timer_ptr, initial_ticks, reschedule_ticks); TX_EL_END_FILTER +#define TX_EL_THREAD_IDENTIFY_INSERT TX_EL_NO_THREAD_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_THREAD_IDENTIFY); TX_EL_END_FILTER +#define TX_EL_TIMER_DEACTIVATE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_DEACTIVATE, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_ACTIVATE_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_ACTIVATE, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_INFO_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_INFO_GET, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_TIMER_PERFORMANCE_INFO_GET, timer_ptr); TX_EL_END_FILTER +#define TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_TIMER_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_TIMER_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PUT_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_GET, semaphore_ptr, semaphore_ptr -> tx_semaphore_count); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_DELETE_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_DELETE, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_CREATE_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_CREATE, semaphore_ptr, initial_count); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_INFO_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_INFO_GET, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PRIORITIZE_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_PRIORITIZE, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_CEILING_PUT_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_SEMAPHORE_CEILING_PUT, semaphore_ptr, semaphore_ptr -> tx_semaphore_count, ceiling); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_SEMAPHORE_PERFORMANCE_INFO_GET, semaphore_ptr); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_SEMAPHORE_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_SEMAPHORE_PUT_NOTIFY_INSERT TX_EL_NO_SEMAPHORE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_SEMAPHORE_PUT_NOTIFY, semaphore_ptr, semaphore_put_notify); TX_EL_END_FILTER +#define TX_EL_QUEUE_FRONT_SEND_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_FRONT_SEND, queue_ptr, source_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_SEND_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_SEND, queue_ptr, source_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_RECEIVE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_RECEIVE, queue_ptr, destination_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_FLUSH_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_FLUSH, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_DELETE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_DELETE, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_CREATE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_QUEUE_CREATE, queue_ptr, queue_start, queue_size, message_size); TX_EL_END_FILTER +#define TX_EL_QUEUE_INFO_GET_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_INFO_GET, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_PRIORITIZE_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_PRIORITIZE, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_QUEUE_PERFORMANCE_INFO_GET, queue_ptr); TX_EL_END_FILTER +#define TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_QUEUE_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_QUEUE_SEND_NOTIFY_INSERT TX_EL_NO_QUEUE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_QUEUE_SEND_NOTIFY, queue_ptr, queue_send_notify); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_EVENT_FLAGS_GET, group_ptr, requested_flags, get_option); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_DELETE_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_DELETE, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_CREATE_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_CREATE, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_INFO_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_INFO_GET, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_EVENT_FLAGS_PERFORMANCE_INFO_GET, group_ptr); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_EVENT_FLAGS_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_EVENT_FLAGS_SET_NOTIFY_INSERT TX_EL_NO_EVENT_FLAG_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_EVENT_FLAGS_SET_NOTIFY, group_ptr, events_set_notify); TX_EL_END_FILTER +#define TX_EL_BYTE_RELEASE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_BYTE_RELEASE, pool_ptr, memory_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_DELETE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_DELETE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_CREATE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_BYTE_POOL_CREATE, pool_ptr, pool_start, pool_size); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_INFO_GET_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_PRIORITIZE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_PRIORITIZE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_ALLOCATE_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_BYTE_ALLOCATE, pool_ptr, memory_ptr, memory_size); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BYTE_POOL_PERFORMANCE_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_BYTE_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_BYTE_POOL_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_BLOCK_RELEASE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_BLOCK_RELEASE, pool_ptr, block_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_DELETE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_DELETE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_CREATE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(TX_EL_BLOCK_POOL_CREATE, pool_ptr, pool_start, pool_size, block_size); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_INFO_GET_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_PRIORITIZE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_PRIORITIZE, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_ALLOCATE_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_BLOCK_ALLOCATE, pool_ptr, block_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_BLOCK_POOL_PERFORMANCE_INFO_GET, pool_ptr); TX_EL_END_FILTER +#define TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_BLOCK_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_BLOCK_POOL_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER +#define TX_EL_MUTEX_CREATE_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_MUTEX_CREATE, mutex_ptr, inherit); TX_EL_END_FILTER +#define TX_EL_MUTEX_DELETE_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_DELETE, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_MUTEX_GET, mutex_ptr, mutex_ptr -> tx_mutex_owner, mutex_ptr -> tx_mutex_ownership_count); TX_EL_END_FILTER +#define TX_EL_MUTEX_INFO_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_INFO_GET, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_PRIORITIZE_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_PRIORITIZE, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_PUT_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(TX_EL_MUTEX_PUT, mutex_ptr, mutex_ptr -> tx_mutex_owner, mutex_ptr -> tx_mutex_ownership_count); TX_EL_END_FILTER +#define TX_EL_MUTEX_PERFORMANCE_INFO_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(TX_EL_MUTEX_PERFORMANCE_INFO_GET, mutex_ptr); TX_EL_END_FILTER +#define TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET_INSERT TX_EL_NO_MUTEX_EVENTS TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(TX_EL_MUTEX_PERFORMANCE_SYSTEM_INFO_GET); TX_EL_END_FILTER + + +#endif + + +/* Define Event Log function prototypes. */ + +VOID _tx_el_initialize(VOID); +UINT _tx_el_thread_register(TX_THREAD *thread_ptr); +UINT _tx_el_thread_unregister(TX_THREAD *thread_ptr); +VOID _tx_el_user_event_insert(UINT sub_type, ULONG info_1, ULONG info_2, + ULONG info_3, ULONG info_4); +VOID _tx_el_thread_running(TX_THREAD *thread_ptr); +VOID _tx_el_thread_preempted(TX_THREAD *thread_ptr); +VOID _tx_el_interrupt(UINT interrupt_number); +VOID _tx_el_interrupt_end(UINT interrupt_number); +VOID _tx_el_interrupt_control_call(void); +VOID _tx_el_event_log_on(void); +VOID _tx_el_event_log_off(void); +VOID _tx_el_event_filter_set(UINT filter); + + +/* Define macros that are used inside the ThreadX source code. + If event logging is disabled, these macros will be defined + as white space. */ + +#ifdef TX_ENABLE_EVENT_LOGGING +#ifndef TX_NO_EVENT_INFO +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(a, b, c, d, e) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) =\ + (ULONG) c;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) =\ + (ULONG) d;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) =\ + (ULONG) e;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(a, b, c, d) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) =\ + (ULONG) c;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) =\ + (ULONG) d;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(a, b, c) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) =\ + (ULONG) c;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) =\ + (ULONG) b;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(a) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + TX_EL_NO_STATUS_EVENTS \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREAD_STATUS_CHANGE; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) b; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) a;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + TX_EL_END_FILTER \ + } +#define TX_EL_THREAD_REGISTER(a) \ + _tx_el_thread_register(a); +#define TX_EL_THREAD_UNREGISTER(a) \ + _tx_el_thread_unregister(a); +#define TX_EL_INITIALIZE _tx_el_initialize(); +#else +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(a, b, c, d, e) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(a, b, c, d) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(a, b, c) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(a) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREADX_CALL; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) a; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) _tx_thread_current_ptr;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + } +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) \ + { \ + UCHAR *entry_ptr; \ + ULONG upper_tbu; \ + TX_EL_NO_STATUS_EVENTS \ + entry_ptr = *_tx_el_current_event; \ + *((unsigned short *) entry_ptr) = TX_EL_THREAD_STATUS_CHANGE; \ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = (unsigned short) b; \ + do { \ + upper_tbu = read_tbu(); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = upper_tbu; \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) =\ + (ULONG) read_tbl();\ + } while (upper_tbu != read_tbu()); \ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) =\ + (ULONG) a;\ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE;\ + if (entry_ptr >= _tx_el_event_area_end) \ + {\ + entry_ptr = _tx_el_event_area_start;\ + }\ + *_tx_el_current_event = entry_ptr;\ + TX_EL_END_FILTER \ + } +#define TX_EL_THREAD_REGISTER(a) \ + _tx_el_thread_register(a); +#define TX_EL_THREAD_UNREGISTER(a) \ + _tx_el_thread_unregister(a); +#define TX_EL_INITIALIZE _tx_el_initialize(); +#endif +#else +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO4(a, b, c, d, e) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO3(a, b, c, d) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(a, b, c) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO1(a, b) +#define TX_EL_KERNEL_CALL_EVENT_INSERT_INFO0(a) +#define TX_EL_THREAD_STATUS_CHANGE_INSERT(a, b) +#define TX_EL_THREAD_REGISTER(a) +#define TX_EL_THREAD_UNREGISTER(a) +#define TX_EL_INITIALIZE +#endif + +#endif + diff --git a/ports/cortex_m3/ghs/inc/tx_ghs.h b/ports/cortex_m3/ghs/inc/tx_ghs.h new file mode 100644 index 0000000..ca97691 --- /dev/null +++ b/ports/cortex_m3/ghs/inc/tx_ghs.h @@ -0,0 +1,77 @@ +/* + * ThreadX C/C++ Library Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ + +#ifndef _TX_GHS_H_ +#define _TX_GHS_H_ + +#include +#include +#include +#include + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) +extern void *__ghs_GetThreadLocalStorageItem(int specifier); + +/* Thread-local storage routines for Green Hills releases 5.x and beyond. + The following specifiers are used when calling + __ghs_GetThreadLocalStorageItem. + + If __ghs_GetThreadLocalStorageItem is customized to + return a per-thread errno value, define the preprocessor symbol + USE_THREAD_LOCAL_ERRNO in ind_errn.c. + */ + +enum __ghs_ThreadLocalStorage_specifier { + __ghs_TLS_asctime_buff, + __ghs_TLS_tmpnam_space, + __ghs_TLS_strtok_saved_pos, + __ghs_TLS_Errno, + __ghs_TLS_gmtime_temp, + __ghs_TLS___eh_globals, + __ghs_TLS_SignalHandlers +}; +#else +/* Thread-local storage routines for Green Hills releases 4.x and 3.x . */ +typedef void (*SignalHandler)(int); + +typedef struct +{ + int Errno; /* errno. */ + SignalHandler SignalHandlers[_SIGMAX]; /* signal() buffer. */ + char tmpnam_space[L_tmpnam]; /* tmpnam(NULL) buffer. */ + char asctime_buff[30]; /* . */ + char *strtok_saved_pos; /* strtok() position. */ + struct tm gmtime_temp; /* gmtime() and localtime() buffer. */ + void *__eh_globals; /* Pointer for C++ exception handling. */ +} ThreadLocalStorage; + +ThreadLocalStorage *GetThreadLocalStorage(void); +#endif + + +void __ghsLock(void); +void __ghsUnlock(void); + +int __ghs_SaveSignalContext(jmp_buf); +void __ghs_RestoreSignalContext(jmp_buf); + +/* prototypes for FILE lock routines. */ +void __ghs_flock_file(void *); +void __ghs_funlock_file(void *); +int __ghs_ftrylock_file(void *); +void __ghs_flock_create(void **); +void __ghs_flock_destroy(void *); + +/* prototype for GHS/ThreadX error shell checking. */ +void __ghs_rnerr(char *errMsg, int stackLevels, int stackTraceDisplay, void *hexVal); + +#endif /* _TX_GHS_H_ */ diff --git a/ports/cortex_m3/ghs/inc/tx_port.h b/ports/cortex_m3/ghs/inc/tx_port.h new file mode 100644 index 0000000..a0f6cae --- /dev/null +++ b/ports/cortex_m3/ghs/inc/tx_port.h @@ -0,0 +1,391 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/GHS */ +/* 6.1.10 */ +/* */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* 01-31-2022 Bhupendra Naphade Modified comment(s),updated */ +/* macro definition, */ +/* resulting in version 6.1.10 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include +#include +#include +#include "tx_ghs.h" + + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef short SHORT; +typedef unsigned short USHORT; + + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + + +/* Define various constants for the ThreadX ARM Cortex-M port. */ + +#define TX_INT_DISABLE 1 /* Disable interrupts */ +#define TX_INT_ENABLE 0 /* Enable interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((ULONG *) 0xE0001004) +#endif +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + + +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower + + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#define TX_INLINE_INITIALIZATION + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#ifndef TX_ENABLE_EXECUTION_CHANGE_NOTIFY +#define TX_THREAD_EXTENSION_3 +#else +#define TX_THREAD_EXTENSION_3 unsigned long long tx_thread_execution_time_total; \ + unsigned long long tx_thread_execution_time_last_start; +#endif + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + +#if (__GHS_VERSION_NUMBER >= 500) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) \ + { \ + extern void __tx_cpp_exception_init(TX_THREAD *thread_ptr); \ + __tx_cpp_exception_init(thread_ptr); \ + } +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) \ + { \ + #pragma weak __cpp_exception_init \ + extern void __cpp_exception_init(void **); \ + static void (*const cpp_init_funcp)(void **) = __cpp_exception_init; \ + if (cpp_init_funcp) \ + __cpp_exception_init(&(thread_ptr -> tx_thread_eh_globals)); \ + } +#endif + +#if (__GHS_VERSION_NUMBER >= 500) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) \ + { \ + extern void __tx_cpp_exception_cleanup(TX_THREAD *thread_ptr); \ + __tx_cpp_exception_cleanup(thread_ptr); \ + } +#else +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) \ + { \ + #pragma weak __cpp_exception_cleanup \ + extern void __cpp_exception_cleanup(void **); \ + static void (*const cpp_cleanup_funcp)(void **) = \ + __cpp_exception_cleanup; \ + if (cpp_cleanup_funcp) \ + __cpp_exception_cleanup(&(thread_ptr -> tx_thread_eh_globals)); \ + } +#endif + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define the get system state macro. */ + +#ifndef TX_THREAD_GET_SYSTEM_STATE +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __MRS(__IPSR)) +#endif + + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h + for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always + zero after initialization for Cortex-M ports. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable); +#endif + + +/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to + prevent early scheduling on Cortex-M parts. */ + +#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++; + + +/* Determine if the ARM architecture has the CLZ instruction. This is available on + architectures v5 and above. If available, redefine the macro for calculating the + lowest bit set. */ + +#ifndef TX_DISABLE_INLINE + +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) m = m & ((ULONG) (-((LONG) m))); \ + b = __CLZ32(m); \ + b = 31 - b; + +#endif + + +/* Define ThreadX interrupt lockout and restore macros for protection on + access of critical kernel information. The restore interrupt macro must + restore the interrupt posture of the running thread prior to the value + present prior to the disable macro. In most cases, the save area macro + is used to define a local function save area for the disable and restore + macros. */ + +#ifdef TX_DISABLE_INLINE + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); + +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); + +#else + +#define TX_INTERRUPT_SAVE_AREA register int interrupt_save; + +/* Define ThreadX interrupt lockout and restore macros using + asm macros. */ + +asm int disable_ints(void) +{ +% + MRS r0,PRIMASK + MOV r1,1 + MSR PRIMASK,r1 +%error +} + +asm void restore_ints(int a) +{ +%reg a + MSR PRIMASK,a +%mem a + LDR r0,a + MSR PRIMASK,r0 +%error +} + +#define TX_DISABLE interrupt_save = disable_ints(); + +#define TX_RESTORE restore_ints(interrupt_save); + +#endif + + +/* Define the interrupt lockout macros for each ThreadX object. */ + +#define TX_BLOCK_POOL_DISABLE TX_DISABLE +#define TX_BYTE_POOL_DISABLE TX_DISABLE +#define TX_EVENT_FLAGS_GROUP_DISABLE TX_DISABLE +#define TX_MUTEX_DISABLE TX_DISABLE +#define TX_QUEUE_DISABLE TX_DISABLE +#define TX_SEMAPHORE_DISABLE TX_DISABLE + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) 2024 Microsoft Corporation. * ThreadX Cortex-M3/GHS Version 6.4.2 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + + + diff --git a/ports/cortex_m3/ghs/src/tx_el.c b/ports/cortex_m3/ghs/src/tx_el.c new file mode 100644 index 0000000..fd58768 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_el.c @@ -0,0 +1,1164 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX/GHS Event Log (EL) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE +#define TX_EL_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_el.h" +#include "string.h" + + +/* Define global variables used to manage the event pool. */ + +UCHAR *_tx_el_tni_start; +UCHAR **_tx_el_current_event; +UCHAR *_tx_el_event_area_start; +UCHAR *_tx_el_event_area_end; +UINT _tx_el_maximum_events; +ULONG _tx_el_total_events; +UINT _tx_el_event_filter; +ULONG _tx_el_time_base_upper; +ULONG _tx_el_time_base_lower; + +extern char __ghsbegin_eventlog[]; +extern char __ghsend_eventlog[]; + +extern TX_THREAD *_tx_thread_current_ptr; +UINT _tx_thread_interrupt_control(UINT new_posture); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_initialize PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the Event Log (in the format dictated by the */ +/* GHS Event Analyzer) and sets up various information for subsequent */ +/* operation. The start and end of the Event Log is determined by the */ +/* .eventlog section in the linker control file. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_initialize(VOID) +{ + +UCHAR *work_ptr; +UCHAR *read_ptr; +ULONG event_log_size; +UCHAR *end_ptr; +UINT i; + + + /* Clear total event counter. */ + _tx_el_total_events = 0; + + /* Clear event filter. */ + _tx_el_event_filter = 0; + + /* First, pickup the starting and ending address of the Event Log memory. */ + work_ptr = (unsigned char *) __ghsbegin_eventlog; + end_ptr = (unsigned char *) __ghsend_eventlog; + + /* Calculate the event log size. */ + event_log_size = end_ptr - work_ptr; + + /* Subtract off the number of bytes in the header and the TNI area. */ + event_log_size = event_log_size - (TX_EL_HEADER_SIZE + + (TX_EL_TNI_ENTRY_SIZE * TX_EL_TNIS)); + + /* Make sure the event log is evenly divisible by the event size. */ + event_log_size = (event_log_size/TX_EL_EVENT_SIZE) * TX_EL_EVENT_SIZE; + + /* Build the Event Log header. */ + + /* Setup the Event Log Version ID. */ + *((unsigned short *) work_ptr) = (unsigned short) TX_EL_VERSION_ID; + work_ptr = work_ptr + sizeof(unsigned short); + + /* Setup the TNIS (number of thread names) field. */ + *((unsigned short *) work_ptr) = (unsigned short) TX_EL_TNIS; + work_ptr = work_ptr + sizeof(unsigned short); + + /* Setup the EVPS (event pool size) field. */ + *((ULONG *) work_ptr) = event_log_size; + work_ptr = work_ptr + sizeof(ULONG); + + /* Remember the maximum number of events. */ + _tx_el_maximum_events = event_log_size/TX_EL_EVENT_SIZE; + + /* Setup max_events field. */ + *((ULONG *) work_ptr) = _tx_el_maximum_events; + work_ptr = work_ptr + sizeof(ULONG); + + /* Setup the evploc (location of event pool). */ + *((ULONG *) work_ptr) = (ULONG) (((ULONG) __ghsbegin_eventlog) + TX_EL_HEADER_SIZE + + (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE)); + work_ptr = work_ptr + sizeof(ULONG); + + /* Save the current event pointer. */ + _tx_el_current_event = (UCHAR **) work_ptr; + + /* Setup event_ptr (pointer to oldest event) field to the start + of the event pool. */ + *_tx_el_current_event = (UCHAR *) (((ULONG) __ghsbegin_eventlog) + TX_EL_HEADER_SIZE + + (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE)); + work_ptr = work_ptr + sizeof(ULONG); + + /* Setup tbfreq (the number of ticks in a second) field. */ + *((ULONG *) work_ptr) = TX_EL_TICKS_PER_SECOND; + work_ptr = work_ptr + sizeof(ULONG); + + /* At this point we are pointing at the Thread Name Information (TNI) array. */ + + /* Remember the start of this for future updates. */ + _tx_el_tni_start = work_ptr; + + /* Clear the entire TNI array, this is the initial setting. */ + end_ptr = work_ptr + (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE); + memset((void *)work_ptr, 0, (TX_EL_TNIS * TX_EL_TNI_ENTRY_SIZE)); + work_ptr = end_ptr; + + /* At this point, we are pointing at the actual Event Entry area. */ + + /* Remember the start of the actual event log area. */ + _tx_el_event_area_start = work_ptr; + + /* Clear the entire Event area. */ + end_ptr = work_ptr + event_log_size; + memset((void *)work_ptr, 0, event_log_size); + work_ptr = end_ptr; + + /* Save the end pointer for later use. */ + _tx_el_event_area_end = work_ptr; + + /* Setup an entry to resolve all activities from initialization and from + an idle system. */ + work_ptr = _tx_el_tni_start; + read_ptr = (UCHAR *) "Initialization/System Idle"; + i = 0; + while ((i < TX_EL_TNI_NAME_SIZE) && (*read_ptr)) + { + + /* Copy a character of thread's name into TNI area of log. */ + *work_ptr++ = *read_ptr++; + + /* Increment the character count. */ + i++; + } + + /* Determine if a NULL needs to be inserted. */ + if (i < TX_EL_TNI_NAME_SIZE) + { + + /* Yes, insert a NULL into the event log string. */ + *work_ptr = (unsigned char) 0; + } + + /* Setup the thread ID to NULL. */ + *((ULONG *) (_tx_el_tni_start + TX_EL_TNI_THREAD_ID_OFFSET)) = (ULONG) TX_NULL; + + /* Set the valid field to indicate the entry is complete. */ + *((UCHAR *) (_tx_el_tni_start + TX_EL_TNI_VALID_OFFSET)) = (ULONG) TX_EL_VALID_ENTRY; + + /* Clear the time base global variables. */ + _tx_el_time_base_upper = 0; + _tx_el_time_base_lower = 0; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_register PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers a thread in the event log for future */ +/* display purposes. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Thread was placed in TNI area */ +/* TX_ERROR No more room in the TNI area */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create ThreadX thread create function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _tx_el_thread_register(TX_THREAD *thread_ptr) +{ + +UCHAR *entry_ptr; +UCHAR *work_ptr; +UCHAR *read_ptr; +UINT i; + + + /* First of all, search for a free slot in the TNI area. */ + entry_ptr = _tx_el_tni_start; + i = 0; + while (i < TX_EL_TNIS) + { + + /* Determine if this entry is available. */ + if (*(entry_ptr + TX_EL_TNI_VALID_OFFSET) == TX_EL_INVALID_ENTRY) + break; + + /* Otherwise, increment the associated pointers and indices. */ + i++; + entry_ptr = entry_ptr + TX_EL_TNI_ENTRY_SIZE; + } + + /* Check to see if there were no more valid entries. */ + if (i >= TX_EL_TNIS) + return(TX_EL_NO_MORE_TNI_ROOM); + + /* Otherwise, we have room in the TNI and a valid record. */ + + /* Setup the thread's name. */ + work_ptr = entry_ptr; + read_ptr = (UCHAR *) thread_ptr -> tx_thread_name; + i = 0; + while ((i < TX_EL_TNI_NAME_SIZE) && (*read_ptr)) + { + + /* Copy a character of thread's name into TNI area of log. */ + *work_ptr++ = *read_ptr++; + + /* Increment the character count. */ + i++; + } + + /* Determine if a NULL needs to be inserted. */ + if (i < TX_EL_TNI_NAME_SIZE) + { + + /* Yes, insert a NULL into the event log string. */ + *work_ptr = (unsigned char) 0; + } + + /* Setup the thread ID. */ + *((ULONG *) (entry_ptr + TX_EL_TNI_THREAD_ID_OFFSET)) = (ULONG) thread_ptr; + + /* Setup the thread priority. */ + *((ULONG *) (entry_ptr + TX_EL_TNI_THREAD_PRIORITY_OFF)) = (ULONG) thread_ptr -> tx_thread_priority; + + /* Set the valid field to indicate the entry is complete. */ + *((UCHAR *) (entry_ptr + TX_EL_TNI_VALID_OFFSET)) = (ULONG) TX_EL_VALID_ENTRY; + + /* Thread name has been registered. */ + return(TX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_unregister PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unregisters a thread in the event log for future */ +/* display purposes. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control block */ +/* */ +/* OUTPUT */ +/* */ +/* TX_SUCCESS Thread was placed in TNI area */ +/* TX_ERROR No more room in the TNI area */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create ThreadX thread create function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _tx_el_thread_unregister(TX_THREAD *thread_ptr) +{ + +UCHAR *entry_ptr; +UCHAR *work_ptr; +UCHAR *read_ptr; +UINT found; +UINT i, j; + + + /* First of all, search for a match in the TNI area. */ + entry_ptr = _tx_el_tni_start; + i = 0; + while (i < TX_EL_TNIS) + { + + /* Determine if this entry is a match. */ + work_ptr = entry_ptr; + read_ptr = (UCHAR *) thread_ptr -> tx_thread_name; + found = TX_TRUE; + j = 0; + do + { + + /* Determine if this character is the same. */ + if (*work_ptr != *read_ptr) + { + + /* Set found to false and fall out of the loop. */ + found = TX_FALSE; + break; + } + else if (*work_ptr == 0) + { + + /* Null terminated, just break the loop. */ + break; + } + else + { + + /* Copy a character of thread's name into TNI area of log. */ + *work_ptr++ = *read_ptr++; + } + + /* Increment the character count. */ + j++; + + } while(j < TX_EL_TNIS); + + + /* Was a match found? */ + if (found) + { + + /* Yes, mark the entry as available now. */ + *(entry_ptr + TX_EL_TNI_VALID_OFFSET) = TX_EL_INVALID_ENTRY; + + /* Get out of the loop! */ + break; + } + + /* Otherwise, increment the associated pointers and indices. */ + i++; + entry_ptr = entry_ptr + TX_EL_TNI_ENTRY_SIZE; + } + + /* Determine status to return. */ + if (found) + return(TX_SUCCESS); + else + return(TX_EL_NAME_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_user_event_insert PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a user event into the event log. */ +/* If the event log is full, the oldest event is overwritten. */ +/* */ +/* INPUT */ +/* */ +/* sub_type Event subtype for kernel call */ +/* info_1 First information field */ +/* info_2 Second information field */ +/* info_3 Third information field */ +/* info_4 Fourth information field */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX services */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_user_event_insert(UINT sub_type, ULONG info_1, ULONG info_2, + ULONG info_3, ULONG info_4) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT upper_tb; +UCHAR *entry_ptr; + + /* Disable interrupts. */ + TX_DISABLE + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_USER_EVENT; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) sub_type; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Store the first info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) = + (ULONG) info_1; + + /* Store the second info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_2_OFFSET)) = + (ULONG) info_2; + + /* Store the third info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_3_OFFSET)) = + (ULONG) info_3; + + /* Store the fourth info field. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_4_OFFSET)) = + (ULONG) info_4; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + /* Restore interrupts. */ + TX_RESTORE +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_running PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a thread change event into the event */ +/* log, which indicates that a context switch is taking place. */ +/* If the event log is full, the oldest event is overwritten. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread being */ +/* scheduled */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_schedule ThreadX scheduler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_thread_running(TX_THREAD *thread_ptr) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + TX_EL_NO_STATUS_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_THREAD_CHANGE; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) 0; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) thread_ptr; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_thread_preempted PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a thread preempted event into the event */ +/* log, which indicates that an interrupt occurred that made a higher */ +/* priority thread ready for execution. In this case, the previously */ +/* executing thread has an event entered to indicate it is no longer */ +/* running. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread being */ +/* scheduled */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_context_restore ThreadX context restore */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_thread_preempted(TX_THREAD *thread_ptr) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + + TX_EL_NO_STATUS_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_THREAD_STATUS_CHANGE; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) TX_READY; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_interrupt PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts an interrupt event into the log, which */ +/* indicates the start of interrupt processing for the specific */ +/* */ +/* INPUT */ +/* */ +/* interrupt_number Interrupt number supplied by */ +/* ISR */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISR processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_interrupt(UINT interrupt_number) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + + TX_EL_NO_INTERRUPT_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_INTERRUPT; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) TX_EL_INTERRUPT_SUB_TYPE; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Store the first info word. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) = + (ULONG) interrupt_number; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_interrupt_end PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts an interrupt end event into the log, which */ +/* indicates the end of interrupt processing for the specific */ +/* */ +/* INPUT */ +/* */ +/* interrupt_number Interrupt number supplied by */ +/* ISR */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ISR processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_interrupt_end(UINT interrupt_number) +{ + +UINT upper_tb; +UCHAR *entry_ptr; + + + TX_EL_NO_INTERRUPT_EVENTS + + /* Increment total event counter. */ + _tx_el_total_events++; + + /* Setup working entry pointer first. */ + entry_ptr = *_tx_el_current_event; + + /* Store the event type. */ + *((unsigned short *) entry_ptr) = (unsigned short) TX_EL_INTERRUPT; + + /* Store the event subtype. */ + *((unsigned short *) (entry_ptr + TX_EL_EVENT_SUBTYPE_OFFSET)) = + (unsigned short) TX_EL_END_OF_INTERRUPT; + + /* Get time stamp. */ + do + { + + /* Pickup the upper tb. */ + upper_tb = (ULONG) read_tbu(); + + /* Store the upper time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_UPPER_OFFSET)) = + (ULONG) upper_tb; + + /* Store the lower time stamp. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_TIME_LOWER_OFFSET)) = + (ULONG) read_tbl(); + } while (upper_tb != (ULONG) read_tbu()); + + /* Store the current thread. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_THREAD_OFFSET)) = + (ULONG) _tx_thread_current_ptr; + + /* Store the first info word. */ + *((ULONG *) (entry_ptr + TX_EL_EVENT_INFO_1_OFFSET)) = + (ULONG) interrupt_number; + + /* Now move the current event log pointer. */ + entry_ptr = entry_ptr + TX_EL_EVENT_SIZE; + + /* Check for a wraparound condition. */ + if (entry_ptr >= _tx_el_event_area_end) + { + + /* Yes, we have wrapped around to the end of the event area. + Start back at the top! */ + entry_ptr = _tx_el_event_area_start; + } + + /* Write the entry pointer back into the header. */ + *_tx_el_current_event = entry_ptr; + + TX_EL_END_FILTER +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_interrupt_control PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function remaps the tx_interrupt_control service call so that */ +/* it can be tracked in the event log. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt posture */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_interrupt_control Interrupt control service */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX services */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +UINT _tx_el_interrupt_control(UINT new_posture) +{ + +TX_INTERRUPT_SAVE_AREA +UINT old_posture; + + + TX_EL_NO_INTERRUPT_EVENTS + + TX_DISABLE + TX_EL_KERNEL_CALL_EVENT_INSERT_INFO2(TX_EL_INTERRUPT_CONTROL, _tx_thread_current_ptr, new_posture) + TX_RESTORE + + TX_EL_END_FILTER + + old_posture = _tx_thread_interrupt_control(new_posture); + return(old_posture); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_event_log_on PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables all event filters. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_event_log_on(void) +{ + + /* Disable all event filters. */ + _tx_el_event_filter = TX_EL_ENABLE_ALL_EVENTS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_event_log_off PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets all event filters, thereby turning event */ +/* logging off. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_event_log_off(void) +{ + + /* Set all event filters. */ + _tx_el_event_filter = TX_EL_FILTER_ALL_EVENTS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_el_event_log_set PORTABLE C */ +/* 6.1 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the events filters specified by the user. */ +/* */ +/* INPUT */ +/* */ +/* filter Events to filter */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +/* */ +/**************************************************************************/ +VOID _tx_el_event_filter_set(UINT filter) +{ + + /* Apply the user event filter. */ + _tx_el_event_filter = filter; +} + diff --git a/ports/cortex_m3/ghs/src/tx_ghs.c b/ports/cortex_m3/ghs/src/tx_ghs.c new file mode 100644 index 0000000..0be9d71 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_ghs.c @@ -0,0 +1,485 @@ +/* + * ThreadX C/C++ Library Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ + +#include "tx_ghs.h" +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#include "tx_api.h" +#include +#include + +/* Allow these routines to access the following ThreadX global variables. */ +extern ULONG _tx_thread_created_count; +extern TX_THREAD *_tx_thread_created_ptr; +extern TX_THREAD *_tx_thread_current_ptr; + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) +/* Thread-local storage routines for Green Hills releases 5.x and above. */ +/* + Thread-Local (Per-Thread) Library Data Retrieval + ================================================ + + __ghs_ThreadLocalStorage_specifier defines all library data items + that the Green Hills libraries allow to be allocated per-thread. + + An implementation can choose which of these data items to allocate + for each thread. For example, an implementation may choose to + allocate an errno value for each thread, but not the strtok_saved_pos + pointer. The application could then use strtok_r instead of strtok for + correct operation. + + To add per-thread library data, define one of the + TX_THREAD_EXTENSION_* macros in tx_port.h to include the data item + or items in each thread control block TX_THREAD. + + If C++ with exceptions is being used, the __eh_globals entry must be + allocated for each thread. This is typically done by default using + TX_THREAD_EXTENSION_1 in tx_port.h. + + If __ghs_GetThreadLocalStorageItem is customized to return a + per-thread errno value, you should also: + + * Customize the System Library for your project + * Define the preprocessor symbol USE_THREAD_LOCAL_ERRNO in + src/libsys/ind_errn.c + + If you customize the System Library, you should remove ind_thrd.c + from the libsys.gpj subproject. + + */ + +/* Provide global __eh_globals value to support C++ exception handling + outside a thread context. This name also forces this module to be + included in the linked program instead of the ind_thrd.o module from + the System Library libsys.a. + */ +static void *__eh_globals; + +#pragma ghs startnomisra +void *__ghs_GetThreadLocalStorageItem(int specifier) +{ + void *ptlsitem = (void *)0; + switch (specifier) { + case (int)__ghs_TLS_Errno: + /* Set ptslsitem to the address of the per-thread errno value. + The per-thread errno value should have the type int. + + If returning a per-thread errno value, follow the steps + above. + + This item is used by numerous library functions. + */ + break; + case (int)__ghs_TLS_SignalHandlers: + /* Set ptslsitem to the address of the per-thread SignalHandlers + array. The per-thread SignalHandlers array should have the + array type as in the following declaration: + SignalHandler SignalHandlers[_SIGMAX]; + The SignalHandler type and _SIGMAX constant are defined in + ind_thrd.h. + + This item is used by the library functions signal() and + raise(). + */ + break; + case (int)__ghs_TLS_asctime_buff: + /* Set ptslsitem to the address of the per-thread asctime_buff + array. The per-thread asctime_buff array should have the + array type as in the following declaration: + char asctime_buff[30]; + + This item is used by the library functions asctime() and + ctime(). The library provides asctime_r() and ctime_r(), + inherently thread-safe versions of these functions. + */ + break; + case (int)__ghs_TLS_tmpnam_space: + /* Set ptslsitem to the address of the per-thread tmpnam_space + array. The per-thread tmpnam_space array should have the + array type as in the following declaration: + char tmpnam_space[L_tmpnam]; + The constant is defined in + + This item is used by the library function tmpnam() when + passed NULL. The library provides tmpnam_r(), an + inherently thread-safe version of tmpnam(). + */ + break; + case (int)__ghs_TLS_strtok_saved_pos: + /* Set ptslsitem to the address of the per-thread + strtok_saved_pos pointer. The per-thread strtok_saved_pos + pointer should have the type "char *". + + This item is used by the library function strtok(). + The library provides strtok_r(), an inherently thread-safe + version of strtok(). + */ + break; + case (int)__ghs_TLS_gmtime_temp: + /* Set ptslsitem to the address of the per-thread gmtime_temp + value. The per-thread gmtime_temp value should have the + type "struct tm" defined in time.h, included by indos.h. + + This item is used by the library functions gmtime() and + localtime(). The library provides gmtime_r() and + localtime_r(), inherently thread-safe versions of these + functions. + */ + break; + case (int)__ghs_TLS___eh_globals: + /* Set ptslsitem to the address of the per-thread __eh_globals + value. The per-thread __eh_globals value should have the + type "void *". + + This item is used by C++ exception handling. + */ + if (_tx_thread_current_ptr) + ptlsitem = (void *)&(_tx_thread_current_ptr->tx_thread_eh_globals); + else + /* Use the global __eh_globals pointer. */ + ptlsitem = (void *)&__eh_globals; + break; + } + return ptlsitem; +} +#pragma ghs endnomisra +#else +/* Thread-local storage routines for Green Hills releases 4.x and 3.x . */ + +/* + * ThreadX C and C++ thread-safe library support routines. + * + * This implementation merely tries to guarantee thread safety within + * individual C library calls such as malloc() and free(), but it does + * not attempt to solve the problems associated with the following + * multithreaded issues: + * + * 1. Use of errno. This can be made thread-safe by adding errno + * to TX_THREAD_PORT_EXTENSION and using that within a modified + * version of libsys/ind_errno.c. + * + * 2. Thread safety ACROSS library calls. Certain C library calls either + * return pointers to statically-allocated data structures or maintain + * state across calls. These include strtok(), asctime(), gmtime(), + * tmpnam(NULL), signal(). To make such C library routines thread-safe + * would require adding a ThreadLocalStorage struct to the thread control + * block TX_THREAD. Since relatively few applications make use of these + * library routines, the implementation provided here uses a single, global + * ThreadLocalStorage data structure rather than greatly increasing the size + * of the thread control block TX_THREAD. + * + * The ThreadX global variable _tx_thread_current_ptr points to the + * current thread's control block TX_THREAD. If a ThreadLocalStorage struct + * called tx_tls is placed in TX_THREAD, the function GetThreadLocalStorage + * should be modified to return &(_tx_thread_current_ptr->tx_tls). + */ + +static ThreadLocalStorage GlobalTLS; + +ThreadLocalStorage *GetThreadLocalStorage() +{ + return &GlobalTLS; +} +#endif + +/* + * Use a global ThreadX mutex to implement thread safety within C and C++ + * library routines. + * + */ +TX_MUTEX __ghLockMutex; + +/* + * Acquire general lock. Blocks until the lock becomes available. + * Use tx_mutex_get to implement __ghsLock + */ +void __ghsLock(void) +{ + tx_mutex_get(&__ghLockMutex, TX_WAIT_FOREVER); +} + +/* + * Release general lock + * Use tx_mutex_put to implement __ghsUnlock + */ +void __ghsUnlock(void) +{ + tx_mutex_put(&__ghLockMutex); +} + +/* ThreadX Initialization function prototype. */ +void _tx_initialize_kernel_setup(void); + +void __gh_lock_init(void) +{ + /* Initialize the low-level portions of ThreadX. */ + _tx_initialize_kernel_setup(); + + /* Create the global thread lock mutex. */ + tx_mutex_create(&__ghLockMutex, "__ghLockMutex", TX_NO_INHERIT); +} + +/* + Saving State Across setjmp() Calls + ================================== + + These routines can be used to save and restore arbitrary state + across calls to setjmp() and longjmp(). +*/ +int __ghs_SaveSignalContext(jmp_buf jmpbuf) +{ + return 0; +} + +/* Restore arbitrary state across a longjmp() */ +void __ghs_RestoreSignalContext(jmp_buf jmpbuf) +{ +} + +#if defined(__GHS_VERSION_NUMBER) && (__GHS_VERSION_NUMBER < 560) +/* + C++ Exception Handling + ====================== + + These routines allow C++ exceptions to be used in multiple threads. + The default implementation uses __ghs_GetThreadLocalStorageItem + to return a thread-specific __eh_globals pointer. + +*/ + +/* Must be called after __cpp_exception_init() is called to allocate + * and initialize the per-thread exception handling structure */ +void *__get_eh_globals(void) +{ +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) + return *(void **)__ghs_GetThreadLocalStorageItem(__ghs_TLS___eh_globals); +#else + if (_tx_thread_current_ptr) + + /* Return thread-specific __eh_globals pointer. */ + return _tx_thread_current_ptr->tx_thread_eh_globals; + else + /* Return the global __eh_globals pointer. */ + return GlobalTLS.__eh_globals; +#endif +} +#endif + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 500) +#pragma weak __cpp_exception_init +extern void __cpp_exception_init(void **); +#pragma weak __cpp_exception_cleanup +extern void __cpp_exception_cleanup(void **); + +/* __tx_cpp_exception_init retrieves the eh_globals field from + thread-local storage and calls __cpp_exception_init. + */ +void __tx_cpp_exception_init(TX_THREAD *thread_ptr) { + void **peh_globals; + if(__cpp_exception_init) { + if (thread_ptr) + peh_globals = &(thread_ptr->tx_thread_eh_globals); + else + /* Use the global __eh_globals pointer. */ + peh_globals = &__eh_globals; + __cpp_exception_init(peh_globals); + } +} + +/* __tx_cpp_exception_cleanup retrieves the eh_globals field from + thread-local storage and calls __cpp_exception_cleanup. + */ +void __tx_cpp_exception_cleanup(TX_THREAD *thread_ptr) { + void **peh_globals; + if(__cpp_exception_cleanup) { + if (thread_ptr) + peh_globals = &(thread_ptr->tx_thread_eh_globals); + else + /* Use the global __eh_globals pointer. */ + peh_globals = &__eh_globals; + __cpp_exception_cleanup(peh_globals); + } +} + +/* __ghs_cpp_exception_init is called from ind_crt1.o to initialize + exceptions for the global context. + */ +void __ghs_cpp_exception_init() { + __tx_cpp_exception_init((void *)0); +} + +/* __ghs_cpp_exception_cleanup is called from ind_exit.o to clean up + exceptions for the global context. + */ +void __ghs_cpp_exception_cleanup(TX_THREAD *thread_ptr) { + __tx_cpp_exception_cleanup((void *)0); +} +#endif + + +/* + File Locks + ====================== + + These routines can be customized to implement per-file locks to allow + thread-safe I/O. + +*/ + +/* Acquire lock for FILE *addr */ +void __ghs_flock_file(void *addr) +{ + tx_mutex_get((TX_MUTEX *)addr, TX_WAIT_FOREVER); +} + +/* Release lock for FILE *addr */ +void __ghs_funlock_file(void *addr) +{ + tx_mutex_put((TX_MUTEX *)addr); +} + +/* Non blocking acquire lock for FILE *addr. May return -1 if */ +/* not implemented. Returns 0 on success and nonzero otherwise. */ +int __ghs_ftrylock_file(void *addr) +{ + return -1; +} + +/* Calls to initialize local lock data structures before they */ +/* are used. */ +void __ghs_flock_create(void **addr) +{ + *addr = (void *)(&__ghLockMutex); +} +void __ghs_flock_destroy(void *addr) {} + + +/* + * ThreadX Peak Stack Checking support routines. + * + * All of these routines are called by MULTI's ThreadX-aware debugging + * package to determine the peak stack use for one thread or for all threads. + * + * These routines are included in this file in order to guarantee that they will + * be available while debugging with MULTI. These routines are not referenced by + * any other part of the ThreadX system. + * + * _txs_thread_stack_check: return the peak stack usage for a thread. + * + * _txs_thread_stack_check_2: store the peak stack usage for all threads + * in the tx_thread_stack_size field of each thread + * control block, TX_THREAD. This routine takes + * advantage of the redundancy within the TX_THREAD + * structure since tx_thread_stack_size can be computed + * from the tx_thread_stack_start and tx_thread_stack_end + * fields of TX_THREAD. + * + * _txs_thread_stack_check_2_fixup: clean up from the _txs_thread_stack_check_2 + * call by computing the stack size for each + * thread and storing the result in the + * tx_thread_stack_size field of each thread control + * block TX_THREAD. + * + * These three routines do not support architectures such as i960 or StarCore + * where the stack grows up instead of down. + * + */ +#ifndef TX_DISABLE_STACK_CHECKING + +ULONG _txs_thread_stack_check(TX_THREAD *thread_ptr) +{ + CHAR *cp; /* Pointer inside thread's stack. */ + + /* Search through the thread's stack to find the highest address modified. */ + for ( cp = (CHAR *)thread_ptr->tx_thread_stack_start; + cp <= (CHAR *)thread_ptr->tx_thread_stack_end; ++cp ) { + + /* Check if this byte in the stack contains something other than TX_STACK_FILL. */ + if (*cp != (char)TX_STACK_FILL) { + + /* Assume cp points to the locating marking the peak stack use. + Return the number of bytes from cp up to and including the + end of the stack. */ + return (((ULONG)thread_ptr->tx_thread_stack_end) - (ULONG)cp + 1); + } + } + return thread_ptr->tx_thread_stack_size; +} + + +int _txs_thread_stack_check_2(void) { + CHAR * cp; /* Pointer inside thread's stack. */ + TX_THREAD * tp; /* Pointer to each thread. */ + + /* If no threads are created, return immediately. */ + if (!_tx_thread_created_count) + return 0; + + /* Start iterating through the threads in the system. Assume that we always + have at least one thread (the system timer thread) in the system. */ + tp = _tx_thread_created_ptr; + + do { + + /* Search through the thread's stack to find the highest address modified. */ + for ( cp = (CHAR *)tp->tx_thread_stack_start; cp <= (CHAR *)tp->tx_thread_stack_end; + ++cp ) { + + /* Check if this byte in the stack contains something other than TX_STACK_FILL. */ + if (*cp != (char)TX_STACK_FILL) { + + /* Assume cp points to the locating marking the peak stack use. + Store the number of bytes from cp up to and including the + end of the stack in the tx_thread_stack_size field. */ + tp->tx_thread_stack_size = ((ULONG)tp->tx_thread_stack_end) - (ULONG)cp + 1; + break; + } + + } + + /* Continue with the next thread. */ + tp = tp->tx_thread_created_next; + + /* Loop until we point to the first thread again. */ + } while ( tp != _tx_thread_created_ptr ); + + return 0; +} + +int _txs_thread_stack_check_2_fixup(void) { + TX_THREAD * tp; /* Pointer to each thread. */ + + /* If no threads are created, return immediately. */ + if (!_tx_thread_created_count) + return 0; + + /* Start iterating through the threads in the system. Assume that we always + have at least one thread (the system timer thread) in the system. */ + tp = _tx_thread_created_ptr; + + do { + + /* Compute the tx_thread_stack_size field by using the tx_thread_stack_end and + tx_thread_stack_start fields. */ + tp->tx_thread_stack_size = (ULONG)tp->tx_thread_stack_end-(ULONG)tp->tx_thread_stack_start+1; + + /* Continue with the next thread. */ + tp = tp->tx_thread_created_next; + + /* Loop until we point to the first thread again. */ + } while ( tp != _tx_thread_created_ptr ); + + return 0; +} + +#endif /* TX_DISABLE_STACK_CHECKING */ diff --git a/ports/cortex_m3/ghs/src/tx_ghse.c b/ports/cortex_m3/ghs/src/tx_ghse.c new file mode 100644 index 0000000..6369df7 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_ghse.c @@ -0,0 +1,49 @@ +/* + * ThreadX C++ Library Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ +#include "tx_ghs.h" +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#include "tx_api.h" + +/* + C++ Exception Handling + ====================== + + These routines allow C++ exceptions to be used in multiple threads. + The default implementation uses __ghs_GetThreadLocalStorageItem + to return a thread-specific __eh_globals pointer. + +*/ + +#if defined(__ghs) && (__GHS_VERSION_NUMBER >= 560) +#ifdef _WIN32 +/* Windows uses a different linker, so include a stub routine, never called, + to pull in __cpp_exception_init and __cpp_exception_cleanup */ +extern void __cpp_exception_init(void **); +extern void __cpp_exception_cleanup(void **); +void __tx_win32_pull_in_exceptions(void) { + __cpp_exception_init(0); + __cpp_exception_cleanup(0); +} +#else +#pragma ghs reference __cpp_exception_init +#pragma ghs reference __cpp_exception_cleanup +#endif + +/* Must be called after __cpp_exception_init() is called to allocate + * and initialize the per-thread exception handling structure */ +void *__get_eh_globals(void) +{ + return *(void **)__ghs_GetThreadLocalStorageItem(__ghs_TLS___eh_globals); +} +#endif diff --git a/ports/cortex_m3/ghs/src/tx_thread_context_restore.arm b/ports/cortex_m3/ghs/src/tx_thread_context_restore.arm new file mode 100644 index 0000000..d89fcfd --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_context_restore.arm @@ -0,0 +1,86 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_restore Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is only needed for legacy applications and it should */ +;/* not be called in any new development on a Cortex-M. */ +;/* This function restores the interrupt context if it is processing a */ +;/* nested interrupt. If not, it returns to the interrupt thread if no */ +;/* preemption is necessary. Otherwise, if preemption is necessary or */ +;/* if no thread was running, the function returns to the scheduler. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs Interrupt Service Routines */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_restore(VOID) +;{ + .globl _tx_thread_context_restore +_tx_thread_context_restore: + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the ISR exit function to indicate an ISR is complete. */ +; + PUSH {r0, lr} ; Save return address + BL _tx_execution_isr_exit ; Call the ISR exit function + POP {r0, lr} ; Save return address +#endif +; + POP {lr} + BX lr +; +;} + .type _tx_thread_context_restore,$function + .size _tx_thread_context_restore,.-_tx_thread_context_restore diff --git a/ports/cortex_m3/ghs/src/tx_thread_context_save.arm b/ports/cortex_m3/ghs/src/tx_thread_context_save.arm new file mode 100644 index 0000000..13cd6d9 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_context_save.arm @@ -0,0 +1,84 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_save Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is only needed for legacy applications and it should */ +;/* not be called in any new development on a Cortex-M. */ +;/* This function saves the context of an executing thread in the */ +;/* beginning of interrupt processing. The function also ensures that */ +;/* the system stack is used upon return to the calling ISR. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_save(VOID) +;{ + .globl _tx_thread_context_save +_tx_thread_context_save: +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the ISR enter function to indicate an ISR is starting. */ +; + PUSH {r0, lr} ; Save return address + BL _tx_execution_isr_enter ; Call the ISR enter function + POP {r0, lr} ; Recover return address +#endif +; +; /* Context is already saved - just return! */ +; + BX lr +;} + .type _tx_thread_context_save,$function + .size _tx_thread_context_save,.-_tx_thread_context_save diff --git a/ports/cortex_m3/ghs/src/tx_thread_interrupt_control.arm b/ports/cortex_m3/ghs/src/tx_thread_interrupt_control.arm new file mode 100644 index 0000000..fa8e83a --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_interrupt_control.arm @@ -0,0 +1,74 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_control Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for changing the interrupt lockout */ +;/* posture of the system. */ +;/* */ +;/* INPUT */ +;/* */ +;/* new_posture New interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_control(UINT new_posture) +;{ + .globl _tx_thread_interrupt_control +_tx_thread_interrupt_control: + MRS r1, PRIMASK ; Pickup current interrupt lockout + MSR PRIMASK, r0 ; Apply the new interrupt lockout + MOV r0, r1 ; Transfer old to return register + BX lr ; Return to caller +; +;} + .type _tx_thread_interrupt_control,$function + .size _tx_thread_interrupt_control,.-_tx_thread_interrupt_control diff --git a/ports/cortex_m3/ghs/src/tx_thread_interrupt_disable.arm b/ports/cortex_m3/ghs/src/tx_thread_interrupt_disable.arm new file mode 100644 index 0000000..26dcfec --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_interrupt_disable.arm @@ -0,0 +1,84 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +;#define TX_SOURCE_CODE +; +; +;/* Include necessary system files. */ +; +;#include "tx_api.h" +;#include "tx_thread.h" +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_restore Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for disabling interrupts and returning */ +;/* the previous interrupt lockout posture. */ +;/* */ +;/* INPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_disable(UINT new_posture) +;{ + .globl _tx_thread_interrupt_disable +_tx_thread_interrupt_disable: +; +; /* Return current interrupt lockout posture. */ +; + MRS r0, PRIMASK + CPSID i + BX lr +; +;} + .type _tx_thread_interrupt_disable,$function + .size _tx_thread_interrupt_disable,.-_tx_thread_interrupt_disable diff --git a/ports/cortex_m3/ghs/src/tx_thread_interrupt_restore.arm b/ports/cortex_m3/ghs/src/tx_thread_interrupt_restore.arm new file mode 100644 index 0000000..b850d47 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_interrupt_restore.arm @@ -0,0 +1,75 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_restore Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for restoring the previous */ +;/* interrupt lockout posture. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* previous_posture Previous interrupt posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_interrupt_restore(UINT new_posture) +;{ + .globl _tx_thread_interrupt_restore +_tx_thread_interrupt_restore: +; +; /* Restore previous interrupt lockout posture. */ +; + MSR PRIMASK, r0 + BX lr +; +;} + .type _tx_thread_interrupt_restore,$function + .size _tx_thread_interrupt_restore,.-_tx_thread_interrupt_restore diff --git a/ports/cortex_m3/ghs/src/tx_thread_schedule.arm b/ports/cortex_m3/ghs/src/tx_thread_schedule.arm new file mode 100644 index 0000000..86ef0b2 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_schedule.arm @@ -0,0 +1,252 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_schedule Cortex-M3/GHS */ +;/* 6.1.10 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function waits for a thread control block pointer to appear in */ +;/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +;/* in the variable, the corresponding thread is resumed. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_initialize_kernel_enter ThreadX entry function */ +;/* _tx_thread_system_return Return to system from thread */ +;/* _tx_thread_context_restore Restore thread's context */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* 01-31-2022 Scott Larson Modified comment(s), add */ +;/* low power code, */ +;/* resulting in version 6.1.10 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_schedule(VOID) +;{ + .globl _tx_thread_schedule +_tx_thread_schedule: +; +; /* This function should only ever be called on Cortex-M +; from the first schedule request. Subsequent scheduling occurs +; from the PendSV handling routines below. */ +; +; /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */ +; + MOV r0, #0 ; Build value for TX_FALSE + LDR r2, =_tx_thread_preempt_disable ; Build address of preempt disable flag + STR r0, [r2, #0] ; Clear preempt disable flag +; +; /* Enable interrupts */ +; + CPSIE i +; +; /* Enter the scheduler for the first time. */ +; + MOV r0, #0x10000000 ; Load PENDSVSET bit + MOV r1, #0xE000E000 ; Load NVIC base + STR r0, [r1, #0xD04] ; Set PENDSVBIT in ICSR + DSB ; Complete all memory accesses + ISB ; Flush pipeline +; +; /* Wait here for the PendSV to take place. */ +; +__tx_wait_here: + B __tx_wait_here ; Wait for the PendSV to happen + + .type _tx_thread_schedule,$function + .size _tx_thread_schedule,.-_tx_thread_schedule +;} +; +; /* Generic context PendSV handler. */ +; + .globl PendSV_Handler + .globl __tx_PendSVHandler +PendSV_Handler: +__tx_PendSVHandler: +; +; /* Get current thread value and new thread pointer. */ +; +__tx_ts_handler: + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the thread exit function to indicate the thread is no longer executing. */ +; + CPSID i ; Disable interrupts + PUSH {r0, lr} ; Save LR (and r0 just for alignment) + BL _tx_execution_thread_exit ; Call the thread exit function + POP {r0, lr} ; Recover LR + CPSIE i ; Enable interrupts +#endif + LDR r0, =_tx_thread_current_ptr ; Build current thread pointer address + LDR r2, =_tx_thread_execute_ptr ; Build execute thread pointer address + MOV r3, #0 ; Build NULL value + LDR r1, [r0] ; Pickup current thread pointer +; +; /* Determine if there is a current thread to finish preserving. */ +; + CBZ r1, __tx_ts_new ; If NULL, skip preservation +; +; /* Recover PSP and preserve current thread context. */ +; + STR r3, [r0] ; Set _tx_thread_current_ptr to NULL + MRS r12, PSP ; Pickup PSP pointer (thread's stack pointer) + STMDB r12!, {r4-r11} ; Save its remaining registers + LDR r4, =_tx_timer_time_slice ; Build address of time-slice variable + STR.W LR, [r12, #-0x4]! ; Save LR on the stack +; +; /* Determine if time-slice is active. If it isn't, skip time handling processing. */ +; + LDR r5, [r4] ; Pickup current time-slice + STR r12, [r1, #8] ; Save the thread stack pointer + CBZ r5, __tx_ts_new ; If not active, skip processing +; +; /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */ +; + STR r5, [r1, #24] ; Save current time-slice +; +; /* Clear the global time-slice. */ +; + STR r3, [r4] ; Clear time-slice +; +; +; /* Executing thread is now completely preserved!!! */ +; +__tx_ts_new: +; +; /* Now we are looking for a new thread to execute! */ +; + CPSID i ; Disable interrupts + LDR r1, [r2] ; Is there another thread ready to execute? + CBZ r1, __tx_ts_wait ; No, skip to the wait processing +; +; /* Yes, another thread is ready for else, make the current thread the new thread. */ +; + STR r1, [r0] ; Setup the current thread pointer to the new thread + CPSIE i ; Enable interrupts +; +; /* Increment the thread run count. */ +; +__tx_ts_restore: + LDR r7, [r1, #4] ; Pickup the current thread run count + LDR r4, =_tx_timer_time_slice ; Build address of time-slice variable + LDR r5, [r1, #24] ; Pickup thread's current time-slice + ADD r7, r7, #1 ; Increment the thread run count + STR r7, [r1, #4] ; Store the new run count +; +; /* Setup global time-slice with thread's current time-slice. */ +; + STR r5, [r4] ; Setup global time-slice + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the thread entry function to indicate the thread is executing. */ +; + PUSH {r0, r1} ; Save r0/r1 + BL _tx_execution_thread_enter ; Call the thread execution enter function + POP {r0, r1} ; Recover r3 +#endif +; +; /* Restore the thread context and PSP. */ +; + LDR r12, [r1, #8] ; Pickup thread's stack pointer + LDR.W LR, [r12], #4 ; Pickup LR + LDMIA r12!, {r4-r11} ; Recover thread's registers + MSR PSP, r12 ; Setup the thread's stack pointer +; +; /* Return to thread. */ +; + BX lr ; Return to thread! +; +; /* The following is the idle wait processing... in this case, no threads are ready for execution and the +; system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts +; are disabled to allow use of WFI for waiting for a thread to arrive. */ +; +__tx_ts_wait: + CPSID i ; Disable interrupts + LDR r1, [r2] ; Pickup the next thread to execute pointer + STR r1, [r0] ; Store it in the current pointer + CBNZ r1, __tx_ts_ready ; If non-NULL, a new thread is ready! + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_enter ; Possibly enter low power mode + POP {r0-r3} +#endif + +#ifdef TX_ENABLE_WFI + DSB ; Ensure no outstanding memory transactions + WFI ; Wait for interrupt + ISB ; Ensure pipeline is flushed +#endif + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_exit ; Exit low power mode + POP {r0-r3} +#endif + + CPSIE i ; Enable interrupts + B __tx_ts_wait ; Loop to continue waiting +; +; /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are +; already in the handler! */ +; +__tx_ts_ready: + MOV r7, #0x08000000 ; Build clear PendSV value + MOV r8, #0xE000E000 ; Build base NVIC address + STR r7, [r8, #0xD04] ; Clear any PendSV +; +; /* Re-enable interrupts and restore new thread. */ +; + CPSIE i ; Enable interrupts + B __tx_ts_restore ; Restore the thread +;} +; + .type __tx_PendSVHandler,$function + .size __tx_PendSVHandler,.-__tx_PendSVHandler diff --git a/ports/cortex_m3/ghs/src/tx_thread_stack_build.arm b/ports/cortex_m3/ghs/src/tx_thread_stack_build.arm new file mode 100644 index 0000000..30a47d8 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_stack_build.arm @@ -0,0 +1,134 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_stack_build Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function builds a stack frame on the supplied thread's stack. */ +;/* The stack frame results in a fake interrupt return to the supplied */ +;/* function pointer. */ +;/* */ +;/* INPUT */ +;/* */ +;/* thread_ptr Pointer to thread control blk */ +;/* function_ptr Pointer to return function */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_thread_create Create thread service */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +;{ + .globl _tx_thread_stack_build +_tx_thread_stack_build: +; +; +; /* Build a fake interrupt frame. The form of the fake interrupt stack +; on the Cortex-M should look like the following after it is built: +; +; Stack Top: +; LR Interrupted LR (LR at time of PENDSV) +; r4 Initial value for r4 +; r5 Initial value for r5 +; r6 Initial value for r6 +; r7 Initial value for r7 +; r8 Initial value for r8 +; r9 Initial value for r9 +; r10 Initial value for r10 +; r11 Initial value for r11 +; r0 Initial value for r0 (Hardware stack starts here!!) +; r1 Initial value for r1 +; r2 Initial value for r2 +; r3 Initial value for r3 +; r12 Initial value for r12 +; lr Initial value for lr +; pc Initial value for pc +; xPSR Initial value for xPSR +; +; Stack Bottom: (higher memory address) */ +; + LDR r2, [r0, #16] ; Pickup end of stack area + BIC r2, r2, #0x7 ; Align frame for 8-byte alignment + SUB r2, r2, #68 ; Subtract frame size + LDR r3, =0xFFFFFFFD ; Build initial LR value + STR r3, [r2, #0] ; Save on the stack +; +; /* Actually build the stack frame. */ +; + MOV r3, #0 ; Build initial register value + STR r3, [r2, #4] ; Store initial r4 + STR r3, [r2, #8] ; Store initial r5 + STR r3, [r2, #12] ; Store initial r6 + STR r3, [r2, #16] ; Store initial r7 + STR r3, [r2, #20] ; Store initial r8 + STR r3, [r2, #24] ; Store initial r9 + STR r3, [r2, #28] ; Store initial r10 + STR r3, [r2, #32] ; Store initial r11 +; +; /* Hardware stack follows. */ +; + STR r3, [r2, #36] ; Store initial r0 + STR r3, [r2, #40] ; Store initial r1 + STR r3, [r2, #44] ; Store initial r2 + STR r3, [r2, #48] ; Store initial r3 + STR r3, [r2, #52] ; Store initial r12 + MOV r3, #0xFFFFFFFF ; Poison EXC_RETURN value + STR r3, [r2, #56] ; Store initial lr + STR r1, [r2, #60] ; Store initial pc + MOV r3, #0x01000000 ; Only T-bit need be set + STR r3, [r2, #64] ; Store initial xPSR +; +; /* Setup stack pointer. */ +; thread_ptr -> tx_thread_stack_ptr = r2; +; + STR r2, [r0, #8] ; Save stack pointer in thread's + ; control block + BX lr ; Return to caller +;} + .type _tx_thread_stack_build,$function + .size _tx_thread_stack_build,.-_tx_thread_stack_build diff --git a/ports/cortex_m3/ghs/src/tx_thread_system_return.arm b/ports/cortex_m3/ghs/src/tx_thread_system_return.arm new file mode 100644 index 0000000..a1cfe33 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_thread_system_return.arm @@ -0,0 +1,86 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_system_return Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is target processor specific. It is used to transfer */ +;/* control from a thread back to the ThreadX system. Only a */ +;/* minimal context is saved since the compiler assumes temp registers */ +;/* are going to get slicked by a function call anyway. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling loop */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ThreadX components */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_system_return(VOID) +;{ + .globl _tx_thread_system_return +_tx_thread_system_return: +; +; /* Return to real scheduler via PendSV. Note that this routine is often +; replaced with in-line assembly in tx_port.h to improved performance. */ +; + MOV r0, #0x10000000 ; Load PENDSVSET bit + MOV r1, #0xE000E000 ; Load NVIC base + STR r0, [r1, #0xD04] ; Set PENDSVBIT in ICSR + MRS r0, IPSR ; Pickup IPSR + CMP r0, #0 ; Is it a thread returning? + BNE _isr_context ; If ISR, skip interrupt enable + MRS r1, PRIMASK ; Thread context returning, pickup PRIMASK + CPSIE i ; Enable interrupts + MSR PRIMASK, r1 ; Restore original interrupt posture +_isr_context: + BX lr ; Return to caller +;} + .type _tx_thread_system_return,$function + .size _tx_thread_system_return,.-_tx_thread_system_return diff --git a/ports/cortex_m3/ghs/src/tx_timer_interrupt.arm b/ports/cortex_m3/ghs/src/tx_timer_interrupt.arm new file mode 100644 index 0000000..16d0c03 --- /dev/null +++ b/ports/cortex_m3/ghs/src/tx_timer_interrupt.arm @@ -0,0 +1,242 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Timer */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + .text + .align 4 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_timer_interrupt Cortex-M3/GHS */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function processes the hardware timer interrupt. This */ +;/* processing includes incrementing the system clock and checking for */ +;/* time slice and/or timer expiration. If either is found, the */ +;/* expiration functions are called. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_timer_expiration_process Timer expiration processing */ +;/* _tx_thread_time_slice Time slice interrupted thread */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* interrupt vector */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_timer_interrupt(VOID) +;{ + .globl _tx_timer_interrupt +_tx_timer_interrupt: +; +; /* Upon entry to this routine, it is assumed that the compiler scratch registers are available +; for use. */ +; +; /* Increment the system clock. */ +; _tx_timer_system_clock++; +; + LDR r1, =_tx_timer_system_clock ; Pickup address of system clock + LDR r0, [r1, #0] ; Pickup system clock + ADD r0, r0, #1 ; Increment system clock + STR r0, [r1, #0] ; Store new system clock +; +; /* Test for time-slice expiration. */ +; if (_tx_timer_time_slice) +; { +; + LDR r3, =_tx_timer_time_slice ; Pickup address of time-slice + LDR r2, [r3, #0] ; Pickup time-slice + CBZ r2, __tx_timer_no_time_slice ; Is it non-active? + ; Yes, skip time-slice processing +; +; /* Decrement the time_slice. */ +; _tx_timer_time_slice--; +; + SUB r2, r2, #1 ; Decrement the time-slice + STR r2, [r3, #0] ; Store new time-slice value +; +; /* Check for expiration. */ +; if (__tx_timer_time_slice == 0) +; + CBNZ r2, __tx_timer_no_time_slice ; Has it expired? +; +; /* Set the time-slice expired flag. */ +; _tx_timer_expired_time_slice = TX_TRUE; +; + LDR r3, =_tx_timer_expired_time_slice ; Pickup address of expired flag + MOV r0, #1 ; Build expired value + STR r0, [r3, #0] ; Set time-slice expiration flag +; +; } +; +__tx_timer_no_time_slice: +; +; /* Test for timer expiration. */ +; if (*_tx_timer_current_ptr) +; { +; + LDR r1, =_tx_timer_current_ptr ; Pickup current timer pointer addr + LDR r0, [r1, #0] ; Pickup current timer + LDR r2, [r0, #0] ; Pickup timer list entry + CBZ r2, __tx_timer_no_timer ; Is there anything in the list? + ; No, just increment the timer +; +; /* Set expiration flag. */ +; _tx_timer_expired = TX_TRUE; +; + LDR r3, =_tx_timer_expired ; Pickup expiration flag address + MOV r2, #1 ; Build expired value + STR r2, [r3, #0] ; Set expired flag + B __tx_timer_done ; Finished timer processing +; +; } +; else +; { +__tx_timer_no_timer: +; +; /* No timer expired, increment the timer pointer. */ +; _tx_timer_current_ptr++; +; + ADD r0, r0, #4 ; Move to next timer +; +; /* Check for wrap-around. */ +; if (_tx_timer_current_ptr == _tx_timer_list_end) +; + LDR r3, =_tx_timer_list_end ; Pickup addr of timer list end + LDR r2, [r3, #0] ; Pickup list end + CMP r0, r2 ; Are we at list end? + BNE __tx_timer_skip_wrap ; No, skip wrap-around logic +; +; /* Wrap to beginning of list. */ +; _tx_timer_current_ptr = _tx_timer_list_start; +; + LDR r3, =_tx_timer_list_start ; Pickup addr of timer list start + LDR r0, [r3, #0] ; Set current pointer to list start +; +__tx_timer_skip_wrap: +; + STR r0, [r1, #0] ; Store new current timer pointer +; } +; +__tx_timer_done: +; +; +; /* See if anything has expired. */ +; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) +; { +; + LDR r3, =_tx_timer_expired_time_slice ; Pickup addr of expired flag + LDR r2, [r3, #0] ; Pickup time-slice expired flag + CBNZ r2, __tx_something_expired ; Did a time-slice expire? + ; If non-zero, time-slice expired + LDR r1, =_tx_timer_expired ; Pickup addr of other expired flag + LDR r0, [r1, #0] ; Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired ; Did a timer expire? + ; No, nothing expired +; +__tx_something_expired: +; +; + STMDB sp!, {r0, lr} ; Save the lr register on the stack + ; and save r0 just to keep 8-byte alignment +; +; /* Did a timer expire? */ +; if (_tx_timer_expired) +; { +; + LDR r1, =_tx_timer_expired ; Pickup addr of expired flag + LDR r0, [r1, #0] ; Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate ; Check for timer expiration + ; If not set, skip timer activation +; +; /* Process timer expiration. */ +; _tx_timer_expiration_process(); +; + BL _tx_timer_expiration_process ; Call the timer expiration handling routine +; +; } +__tx_timer_dont_activate: +; +; /* Did time slice expire? */ +; if (_tx_timer_expired_time_slice) +; { +; + LDR r3, =_tx_timer_expired_time_slice ; Pickup addr of time-slice expired + LDR r2, [r3, #0] ; Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration ; See if the flag is set + ; No, skip time-slice processing +; +; /* Time slice interrupted thread. */ +; _tx_thread_time_slice(); + + BL _tx_thread_time_slice ; Call time-slice processing + LDR r0, =_tx_thread_preempt_disable ; Build address of preempt disable flag + LDR r1, [r0] ; Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice ; Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr ; Build current thread pointer address + LDR r1, [r0] ; Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr ; Build execute thread pointer address + LDR r3, [r2] ; Pickup the execute thread pointer + LDR r0, =0xE000ED04 ; Build address of control register + LDR r2, =0x10000000 ; Build value for PendSV bit + CMP r1, r3 ; Are they the same? + BEQ __tx_timer_skip_time_slice ; If the same, there was no time-slice performed + STR r2, [r0] ; Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: +; +; } +; +__tx_timer_not_ts_expiration: +; + LDMIA sp!, {r0, lr} ; Recover lr register (r0 is just there for + ; the 8-byte stack alignment +; +; } +; +__tx_timer_nothing_expired: + + DSB ; Complete all memory access + BX lr ; Return to caller +; +;} + .type _tx_timer_interrupt,$function + .size _tx_timer_interrupt,.-_tx_timer_interrupt diff --git a/ports/cortex_m3/ghs/src/txr_ghs.c b/ports/cortex_m3/ghs/src/txr_ghs.c new file mode 100644 index 0000000..19572e2 --- /dev/null +++ b/ports/cortex_m3/ghs/src/txr_ghs.c @@ -0,0 +1,84 @@ +/* + * ThreadX API Runtime Error Support + * + * Copyright 1983-2019 Green Hills Software LLC. + * + * This program is the property of Green Hills Software LLC., + * its contents are proprietary information and no part of it + * is to be disclosed to anyone except employees of Green Hills + * Software LLC., or as agreed in writing signed by the President + * of Green Hills Software LLC. + */ + +/* #include "tx_ghs.h" */ +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#include "tx_api.h" + +/* Customized ThreadX API runtime error support routine. */ + +void _rnerr(int num, int linenum, const char*str, void*ptr, ...); + +/* __ghs_rnerr() + This is the custom runtime error checking routine. + This implementation uses the existing __rnerr() routine. + Another implementation could use the .syscall mechanism, + provided MULTI was modified to understand that. + */ +void __ghs_rnerr(char *errMsg, int stackLevels, int stackTraceDisplay, void *hexVal) { + TX_INTERRUPT_SAVE_AREA + int num; + /* + Initialize the stack levels value. + + Add 3 to account for the calls to _rnerr, __rnerr, and + __ghs_rnerr. + + If the implementation changes, calls to __ghs_rnerr + will not need to be changed. + + Zero is not permitted, so substitute 3 in that case. + */ + num = (stackLevels+3) & 0xf; + if (!num) { + num = 3; + } + /* + Shift the stack levels value to bits 12..15 and + insert the stack trace display value in bit 11. + Bits 0..10 are unused. + */ + num = (num << 12) | (stackTraceDisplay ? 0x800 : 0); + + /* This will mask all interrupts in the RTEC code, which is probably + unacceptable for many targets. */ + TX_DISABLE + _rnerr(num, -1, (const char *)hexVal, (void *)errMsg); + TX_RESTORE +} + + +/* ThreadX thread stack checking runtime support routine. */ + +extern char __ghsbegin_stack[]; +extern TX_THREAD *_tx_thread_current_ptr; + +void __stkchk(void) { + int i; + if(_tx_thread_current_ptr) + { + if((unsigned)(&i) <= + (unsigned)(_tx_thread_current_ptr -> tx_thread_stack_start)) + { + _rnerr(21, -1, 0, 0); + } + } + else + { + if((unsigned)(&i) <= (unsigned)__ghsbegin_stack) + { + _rnerr(21, -1, 0, 0); + } + } +} diff --git a/ports/cortex_m3/gnu/inc/tx_port.h b/ports/cortex_m3/gnu/inc/tx_port.h new file mode 100644 index 0000000..02d61f3 --- /dev/null +++ b/ports/cortex_m3/gnu/inc/tx_port.h @@ -0,0 +1,728 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/GNU */ +/* 6.1.12 */ +/* */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */ +/* the ARMv7-M architecture and compilers into one common file. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comments, updated */ +/* typedef to fix misra */ +/* violation, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#include "tx_ghs.h" +#endif /* __ghs__ */ + + +#if !defined(__GNUC__) && !defined(__CC_ARM) +#define __get_control_value __get_CONTROL +#define __set_control_value __set_CONTROL +#endif + +#ifndef __GNUC__ +#define __get_ipsr_value __get_IPSR +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long long ULONG64; +typedef short SHORT; +typedef unsigned short USHORT; +#define ULONG64_DEFINED + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + +/* By default, ThreadX for Cortex-M uses the PRIMASK register to enable/disable interrupts. +If using BASEPRI is desired, define the following two symbols for both c and assembly files: +TX_PORT_USE_BASEPRI - This tells ThreadX to use BASEPRI instead of PRIMASK. +TX_PORT_BASEPRI = (priority_mask << (8 - number_priority_bits)) - this defines the maximum priority level to mask. +Any interrupt with a higher priority than priority_mask will not be masked, thus the interrupt will run. +*/ + +/* Define various constants for the ThreadX Cortex-M port. */ + +#define TX_INT_DISABLE 1 /* Disable interrupts */ +#define TX_INT_ENABLE 0 /* Enable interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0xE0001004) +#endif +#else +ULONG _tx_misra_time_stamp_get(VOID); +#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get() +#endif + +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#ifdef TX_MISRA_ENABLE +#define TX_DISABLE_INLINE +#else +#define TX_INLINE_INITIALIZATION +#endif + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifndef TX_MISRA_ENABLE +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#elif defined(__ghs__) +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#else +#define TX_THREAD_EXTENSION_2 +#endif + + +#define TX_THREAD_EXTENSION_3 + + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#if (__VER__ < 8000000) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0); +#else +void *_tx_iar_create_per_thread_tls_area(void); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); +void __iar_Initlocks(void); + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0); +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); +#endif +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + +#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) + +#ifdef TX_MISRA_ENABLE + +ULONG _tx_misra_control_get(void); +void _tx_misra_control_set(ULONG value); +ULONG _tx_misra_fpccr_get(void); +void _tx_misra_vfp_touch(void); + +#else /* TX_MISRA_ENABLE not defined */ + +/* Define some helper functions (these are intrinsics in some compilers). */ +#ifdef __GNUC__ /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + +__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value) +{ + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); + +#elif defined(__CC_ARM) /* ARM Compiler 5 */ + +__attribute__( ( always_inline ) ) ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm volatile ("MRS control_value,CONTROL"); + return(control_value); +} + +__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value) +{ + __asm__ volatile ("MSR CONTROL,control_value"); +} +/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */ +void _tx_vfp_access(void); +#define TX_VFP_TOUCH() _tx_vfp_access(); + +#elif defined(__ICCARM__) /* IAR */ +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); +#endif /* Helper functions for different compilers */ + +#endif /* TX_MISRA_ENABLE */ + + +/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA + in order to ensure no lazy stacking will occur. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } +#else + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } + +#endif + +/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR. + If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating + this one, so if the FPCCR.LSPACT bit is set, we need to save the CONTROL.FPCA state, touch the FPU to flush + the lazy FPU save, then restore the CONTROL.FPCA state. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((volatile ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + TX_VFP_TOUCH(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + } \ + } \ + } +#else + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = _tx_misra_fpccr_get(); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + _tx_misra_vfp_touch(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + } \ + } \ + } +#endif + +#else /* No VFP in use */ + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */ + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define the get system state macro. */ + +#ifndef TX_THREAD_GET_SYSTEM_STATE +#ifndef TX_MISRA_ENABLE + +#ifdef __CC_ARM /* ARM Compiler 5 */ + +register unsigned int _ipsr __asm("ipsr"); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr) + +#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void) +{ +unsigned int ipsr_value; + __asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) ); + return(ipsr_value); +} + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value()) + +#elif defined(__ICCARM__) /* IAR */ + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR()) + +#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */ + +#else /* TX_MISRA_ENABLE is defined, use MISRA function. */ +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif /* TX_MISRA_ENABLE */ +#endif /* TX_THREAD_GET_SYSTEM_STATE */ + + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h + for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always + zero after initialization for Cortex-M ports. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable); +#endif + +/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to + prevent early scheduling on Cortex-M parts. */ + +#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++; + + + + +#ifndef TX_DISABLE_INLINE + +/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */ +#ifdef __ICCARM__ /* IAR Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m))); +#elif defined(__CC_ARM) /* AC5 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m))); +#elif defined(__GNUC__) /* GCC and AC6 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); +#endif + + + +/* Define the interrupt disable/restore macros for each compiler. */ + +#if defined(__GNUC__) || defined(__ICCARM__) + +/*** GCC/AC6 and IAR ***/ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture)); +#else + __asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture)); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +__attribute__( ( always_inline ) ) static inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value)); +} +#else +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + __asm__ volatile ("CPSIE i": : : "memory"); +} +#endif + +__attribute__( ( always_inline ) ) static inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); + //__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory"); +#else + __asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory"); +#endif +} + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i" : : : "memory"); +#endif + return(int_posture); +} + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_interrupt_posture(); +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(0); +#else + __enable_interrupts(); +#endif + __restore_interrupt(interrupt_save); + } +} + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End GCC/AC6 and IAR ***/ + +#elif defined(__CC_ARM) + +/*** AC5 ***/ + +static __inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS #posture, BASEPRI"); +#else + __asm__ volatile ("MRS #posture, PRIMASK"); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +static __inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI, #basepri_value"); +} +#endif + +static __inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i"); +#endif + return(int_posture); +} + +static __inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); +#else + __asm__ volatile ("MSR PRIMASK, #int_posture"); +#endif +} + +static void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (_ipsr == 0) + { +#ifdef TX_PORT_USE_BASEPRI + interrupt_save = __get_interrupt_posture(); + __set_basepri_value(0); + __set_basepri_value(interrupt_save); +#else + interrupt_save = __disable_irq(); + __enable_irq(); + if (interrupt_save != 0) + __disable_irq(); +#endif + } +} + + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End AC5 ***/ + +#endif /* Interrupt disable/restore macros for each compiler. */ + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else /* TX_DISABLE_INLINE is defined */ + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); +#endif /* TX_DISABLE_INLINE */ + + +/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing + thread. These are no longer needed, but are preserved for backward compatibility only. */ + +void tx_thread_fpu_enable(void); +void tx_thread_fpu_disable(void); + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) 2024 Microsoft Corporation. * ThreadX Cortex-M3/GNU Version 6.4.2 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + + +#endif diff --git a/ports/cortex_m3/gnu/src/tx_misra.S b/ports/cortex_m3/gnu/src/tx_misra.S new file mode 100644 index 0000000..8ac0c62 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_misra.S @@ -0,0 +1,722 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX MISRA Compliance */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + .global __aeabi_memset + .global _tx_thread_current_ptr + .global _tx_thread_interrupt_disable + .global _tx_thread_interrupt_restore + .global _tx_thread_stack_analyze + .global _tx_thread_stack_error_handler + .global _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_trace_buffer_current_ptr + .global _tx_trace_buffer_end_ptr + .global _tx_trace_buffer_start_ptr + .global _tx_trace_event_enable_bits + .global _tx_trace_full_notify_function + .global _tx_trace_header_ptr +#endif + + .global _tx_misra_always_true + .global _tx_misra_block_pool_to_uchar_pointer_convert + .global _tx_misra_byte_pool_to_uchar_pointer_convert + .global _tx_misra_char_to_uchar_pointer_convert + .global _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_entry_to_uchar_pointer_convert +#endif + .global _tx_misra_indirect_void_to_uchar_pointer_convert + .global _tx_misra_memset + .global _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_object_to_uchar_pointer_convert +#endif + .global _tx_misra_pointer_to_ulong_convert + .global _tx_misra_status_get + .global _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_time_stamp_get +#endif + .global _tx_misra_timer_indirect_to_void_pointer_convert + .global _tx_misra_timer_pointer_add + .global _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_trace_event_insert +#endif + .global _tx_misra_uchar_pointer_add + .global _tx_misra_uchar_pointer_dif + .global _tx_misra_uchar_pointer_sub + .global _tx_misra_uchar_to_align_type_pointer_convert + .global _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_entry_pointer_convert + .global _tx_misra_uchar_to_header_pointer_convert +#endif + .global _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + .global _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + .global _tx_misra_uchar_to_object_pointer_convert +#endif + .global _tx_misra_uchar_to_void_pointer_convert + .global _tx_misra_ulong_pointer_add + .global _tx_misra_ulong_pointer_dif + .global _tx_misra_ulong_pointer_sub + .global _tx_misra_ulong_to_pointer_convert + .global _tx_misra_ulong_to_thread_pointer_convert + .global _tx_misra_user_timer_pointer_get + .global _tx_misra_void_to_block_pool_pointer_convert + .global _tx_misra_void_to_byte_pool_pointer_convert + .global _tx_misra_void_to_event_flags_pointer_convert + .global _tx_misra_void_to_indirect_uchar_pointer_convert + .global _tx_misra_void_to_mutex_pointer_convert + .global _tx_misra_void_to_queue_pointer_convert + .global _tx_misra_void_to_semaphore_pointer_convert + .global _tx_misra_void_to_thread_pointer_convert + .global _tx_misra_void_to_uchar_pointer_convert + .global _tx_misra_void_to_ulong_pointer_convert + .global _tx_misra_ipsr_get + .global _tx_misra_control_get + .global _tx_misra_control_set +#ifdef __ARM_FP + .global _tx_misra_fpccr_get + .global _tx_misra_vfp_touch +#endif + + .global _tx_misra_event_flags_group_not_used + .global _tx_misra_event_flags_set_notify_not_used + .global _tx_misra_queue_not_used + .global _tx_misra_queue_send_notify_not_used + .global _tx_misra_semaphore_not_used + .global _tx_misra_semaphore_put_notify_not_used + .global _tx_misra_thread_entry_exit_notify_not_used + .global _tx_misra_thread_not_used + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .align 4 + .syntax unified + .thumb_func +_tx_misra_memset: + PUSH {R4,LR} + MOVS R4,R0 + MOVS R0,R2 + MOVS R2,R1 + MOVS R1,R0 + MOVS R0,R4 + BL __aeabi_memset + POP {R4,PC} // return + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_sub: + RSBS R1,R1,#+0 + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_uchar_pointer_dif: + SUBS R0,R0,R1 + BX LR // return + + +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ +/** */ +/** This single function serves all of the below prototypes. */ +/** */ +/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */ +/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */ +/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */ +/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */ +/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */ +/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */ +/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */ +/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */ +/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */ +/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */ +/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */ +/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */ +/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */ +/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */ +/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */ +/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */ +/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */ +/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */ +/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */ +/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */ +/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */ +/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */ +/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */ +/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */ +/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */ +/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */ +/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */ +/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */ +/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */ +/** VOID _tx_misra_event_flags_group_not_used(TX_EVENT_FLAGS_GROUP *group_ptr); */ +/** VOID _tx_misra_event_flags_set_notify_not_used(VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); */ +/** VOID _tx_misra_queue_not_used(TX_QUEUE *queue_ptr); */ +/** VOID _tx_misra_queue_send_notify_not_used(VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); */ +/** VOID _tx_misra_semaphore_not_used(TX_SEMAPHORE *semaphore_ptr); */ +/** VOID _tx_misra_semaphore_put_notify_not_used(VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); */ +/** VOID _tx_misra_thread_not_used(TX_THREAD *thread_ptr); */ +/** VOID _tx_misra_thread_entry_exit_notify_not_used(VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + .text + .thumb_func +_tx_misra_pointer_to_ulong_convert: +_tx_misra_ulong_to_pointer_convert: +_tx_misra_indirect_void_to_uchar_pointer_convert: +_tx_misra_uchar_to_indirect_uchar_pointer_convert: +_tx_misra_block_pool_to_uchar_pointer_convert: +_tx_misra_void_to_block_pool_pointer_convert: +_tx_misra_void_to_uchar_pointer_convert: +_tx_misra_uchar_to_block_pool_pointer_convert: +_tx_misra_void_to_indirect_uchar_pointer_convert: +_tx_misra_void_to_byte_pool_pointer_convert: +_tx_misra_byte_pool_to_uchar_pointer_convert: +_tx_misra_uchar_to_align_type_pointer_convert: +_tx_misra_uchar_to_indirect_byte_pool_pointer_convert: +_tx_misra_void_to_event_flags_pointer_convert: +_tx_misra_void_to_ulong_pointer_convert: +_tx_misra_void_to_mutex_pointer_convert: +_tx_misra_void_to_queue_pointer_convert: +_tx_misra_void_to_semaphore_pointer_convert: +_tx_misra_uchar_to_void_pointer_convert: +_tx_misra_ulong_to_thread_pointer_convert: +_tx_misra_timer_indirect_to_void_pointer_convert: +_tx_misra_const_char_to_char_pointer_convert: +_tx_misra_void_to_thread_pointer_convert: +#ifdef TX_ENABLE_EVENT_TRACE +_tx_misra_object_to_uchar_pointer_convert: +_tx_misra_uchar_to_object_pointer_convert: +_tx_misra_uchar_to_header_pointer_convert: +_tx_misra_uchar_to_entry_pointer_convert: +_tx_misra_entry_to_uchar_pointer_convert: +#endif +_tx_misra_char_to_uchar_pointer_convert: +_tx_misra_event_flags_group_not_used: +_tx_misra_event_flags_set_notify_not_used: +_tx_misra_queue_not_used: +_tx_misra_queue_send_notify_not_used: +_tx_misra_semaphore_not_used: +_tx_misra_semaphore_put_notify_not_used: +_tx_misra_thread_entry_exit_notify_not_used: +_tx_misra_thread_not_used: + + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_sub: + MVNS R2,#+3 + MULS R1,R2,R1 + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_ulong_pointer_dif: + SUBS R0,R0,R1 + ASRS R0,R0,#+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */ +/** UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_message_copy: + PUSH {R4,R5} + LDR R3,[R0, #+0] + LDR R4,[R1, #+0] + LDR R5,[R3, #+0] + STR R5,[R4, #+0] + ADDS R4,R4,#+4 + ADDS R3,R3,#+4 + CMP R2,#+2 + BCC.N _tx_misra_message_copy_0 + SUBS R2,R2,#+1 + B.N _tx_misra_message_copy_1 +_tx_misra_message_copy_2: + LDR R5,[R3, #+0] + STR R5,[R4, #+0] + ADDS R4,R4,#+4 + ADDS R3,R3,#+4 + SUBS R2,R2,#+1 +_tx_misra_message_copy_1: + CMP R2,#+0 + BNE.N _tx_misra_message_copy_2 +_tx_misra_message_copy_0: + STR R3,[R0, #+0] + STR R4,[R1, #+0] + POP {R4,R5} + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */ +/** TX_TIMER_INTERNAL **ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_timer_pointer_dif: + SUBS R0,R0,R1 + ASRS R0,R0,#+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */ +/** **ptr1, ULONG size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_timer_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */ +/** *internal_timer, TX_TIMER **user_timer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_user_timer_pointer_get: + SUBS R0,#8 + STR R0,[R1, #+0] + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */ +/** VOID **highest_stack); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_thread_stack_check: + PUSH {R3-R5,LR} + MOVS R4,R0 + MOVS R5,R1 + BL _tx_thread_interrupt_disable + CMP R4,#+0 + BEQ.N _tx_misra_thread_stack_check_0 + LDR R1,[R4, #+0] + LDR R2,=0x54485244 + CMP R1,R2 + BNE.N _tx_misra_thread_stack_check_0 + LDR R1,[R4, #+8] + LDR R2,[R5, #+0] + CMP R1,R2 + BCS.N _tx_misra_thread_stack_check_1 + LDR R1,[R4, #+8] + STR R1,[R5, #+0] +_tx_misra_thread_stack_check_1: + LDR R1,[R4, #+12] + LDR R1,[R1, #+0] + CMP R1,#-269488145 + BNE.N _tx_misra_thread_stack_check_2 + LDR R1,[R4, #+16] + LDR R1,[R1, #+1] + CMP R1,#-269488145 + BNE.N _tx_misra_thread_stack_check_2 + LDR R1,[R5, #+0] + LDR R2,[R4, #+12] + CMP R1,R2 + BCS.N _tx_misra_thread_stack_check_3 +_tx_misra_thread_stack_check_2: + BL _tx_thread_interrupt_restore + MOVS R0,R4 + BL _tx_thread_stack_error_handler + BL _tx_thread_interrupt_disable +_tx_misra_thread_stack_check_3: + LDR R1,[R5, #+0] + LDR R1,[R1, #-4] + CMP R1,#-269488145 + BEQ.N _tx_misra_thread_stack_check_0 + BL _tx_thread_interrupt_restore + MOVS R0,R4 + BL _tx_thread_stack_analyze + BL _tx_thread_interrupt_disable +_tx_misra_thread_stack_check_0: + BL _tx_thread_interrupt_restore + POP {R0,R4,R5,PC} // return + +#ifdef TX_ENABLE_EVENT_TRACE + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_trace_event_insert(ULONG event_id, */ +/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */ +/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_trace_event_insert: + PUSH {R3-R7,LR} + LDR.N R4,DataTable2_1 + LDR R4,[R4, #+0] + CMP R4,#+0 + BEQ.N _tx_misra_trace_event_insert_0 + LDR.N R5,DataTable2_2 + LDR R5,[R5, #+0] + LDR R6,[SP, #+28] + TST R5,R6 + BEQ.N _tx_misra_trace_event_insert_0 + LDR.N R5,DataTable2_3 + LDR R5,[R5, #+0] + LDR.N R6,DataTable2_4 + LDR R6,[R6, #+0] + CMP R5,#+0 + BNE.N _tx_misra_trace_event_insert_1 + LDR R5,[R6, #+44] + LDR R7,[R6, #+60] + LSLS R7,R7,#+16 + ORRS R7,R7,#0x80000000 + ORRS R5,R7,R5 + B.N _tx_misra_trace_event_insert_2 +_tx_misra_trace_event_insert_1: + CMP R5,#-252645136 + BCS.N _tx_misra_trace_event_insert_3 + MOVS R5,R6 + MOVS R6,#-1 + B.N _tx_misra_trace_event_insert_2 +_tx_misra_trace_event_insert_3: + MOVS R6,#-252645136 + MOVS R5,#+0 +_tx_misra_trace_event_insert_2: + STR R6,[R4, #+0] + STR R5,[R4, #+4] + STR R0,[R4, #+8] + LDR R0,[SP, #+32] + STR R0,[R4, #+12] + STR R1,[R4, #+16] + STR R2,[R4, #+20] + STR R3,[R4, #+24] + LDR R0,[SP, #+24] + STR R0,[R4, #+28] + ADDS R4,R4,#+32 + LDR.N R0,DataTable2_5 + LDR R0,[R0, #+0] + CMP R4,R0 + BCC.N _tx_misra_trace_event_insert_4 + LDR.N R0,DataTable2_6 + LDR R4,[R0, #+0] + LDR.N R0,DataTable2_1 + STR R4,[R0, #+0] + LDR.N R0,DataTable2_7 + LDR R0,[R0, #+0] + STR R4,[R0, #+32] + LDR.N R0,DataTable2_8 + LDR R0,[R0, #+0] + CMP R0,#+0 + BEQ.N _tx_misra_trace_event_insert_0 + LDR.N R0,DataTable2_7 + LDR R0,[R0, #+0] + LDR.N R1,DataTable2_8 + LDR R1,[R1, #+0] + BLX R1 + B.N _tx_misra_trace_event_insert_0 +_tx_misra_trace_event_insert_4: + LDR.N R0,DataTable2_1 + STR R4,[R0, #+0] + LDR.N R0,DataTable2_7 + LDR R0,[R0, #+0] + STR R4,[R0, #+32] +_tx_misra_trace_event_insert_0: + POP {R0,R4-R7,PC} // return + + + .data +DataTable2_1: + .word _tx_trace_buffer_current_ptr + + .data +DataTable2_2: + .word _tx_trace_event_enable_bits + + .data +DataTable2_5: + .word _tx_trace_buffer_end_ptr + + .data +DataTable2_6: + .word _tx_trace_buffer_start_ptr + + .data +DataTable2_7: + .word _tx_trace_header_ptr + + .data +DataTable2_8: + .word _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + .data +DataTable2_3: + .word _tx_thread_system_state + + .data +DataTable2_4: + .word _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .text + .thumb_func +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARM_FP + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_fpccr_get: + LDR r0, =0xE000EF34 // Build FPCCR address + LDR r0, [r0] // Load FPCCR value + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_vfp_touch(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + .text + .thumb_func +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + .data + .word 0 diff --git a/ports/cortex_m3/gnu/src/tx_thread_context_restore.S b/ports/cortex_m3/gnu/src/tx_thread_context_restore.S new file mode 100644 index 0000000..f36f0e7 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + .global _tx_execution_isr_exit +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } diff --git a/ports/cortex_m3/gnu/src/tx_thread_context_save.S b/ports/cortex_m3/gnu/src/tx_thread_context_save.S new file mode 100644 index 0000000..bcc690d --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_context_save.S @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } diff --git a/ports/cortex_m3/gnu/src/tx_thread_interrupt_control.S b/ports/cortex_m3/gnu/src/tx_thread_interrupt_control.S new file mode 100644 index 0000000..e7ea870 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } diff --git a/ports/cortex_m3/gnu/src/tx_thread_interrupt_disable.S b/ports/cortex_m3/gnu/src/tx_thread_interrupt_disable.S new file mode 100644 index 0000000..b0169c6 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_interrupt_disable.S @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + .global _tx_thread_interrupt_disable + .thumb_func +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } diff --git a/ports/cortex_m3/gnu/src/tx_thread_interrupt_restore.S b/ports/cortex_m3/gnu/src/tx_thread_interrupt_restore.S new file mode 100644 index 0000000..ef0298b --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_interrupt_restore.S @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + .global _tx_thread_interrupt_restore + .thumb_func +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } diff --git a/ports/cortex_m3/gnu/src/tx_thread_schedule.S b/ports/cortex_m3/gnu/src/tx_thread_schedule.S new file mode 100644 index 0000000..22f4f38 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_schedule.S @@ -0,0 +1,330 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +#ifdef TX_LOW_POWER + .global tx_low_power_enter + .global tx_low_power_exit +#endif + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* _tx_thread_system_return Return to system from thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Fixed predefined macro name, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + .global _tx_thread_schedule + .thumb_func +_tx_thread_schedule: + + /* This function should only ever be called on Cortex-M + from the first schedule request. Subsequent scheduling occurs + from the PendSV handling routine below. */ + + /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */ + + MOV r0, #0 // Build value for TX_FALSE + LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag + STR r0, [r2, #0] // Clear preempt disable flag + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __ARM_FP + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* Enable interrupts */ + CPSIE i + + /* Enter the scheduler for the first time. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + DSB // Complete all memory accesses + ISB // Flush pipeline + + /* Wait here for the PendSV to take place. */ + +__tx_wait_here: + B __tx_wait_here // Wait for the PendSV to happen +// } + + /* Generic context switching PendSV handler. */ + + .global PendSV_Handler + .global __tx_PendSVHandler + .syntax unified + .thumb_func +PendSV_Handler: + .thumb_func +__tx_PendSVHandler: + + /* Get current thread value and new thread pointer. */ + +__tx_ts_handler: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread exit function to indicate the thread is no longer executing. */ +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif /* TX_PORT_USE_BASEPRI */ + PUSH {r0, lr} // Save LR (and r0 just for alignment) + BL _tx_execution_thread_exit // Call the thread exit function + POP {r0, lr} // Recover LR +#ifdef TX_PORT_USE_BASEPRI + MOV r0, 0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r0 +#else + CPSIE i // Enable interrupts +#endif /* TX_PORT_USE_BASEPRI */ +#endif /* EXECUTION PROFILE */ + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + MOV r3, #0 // Build NULL value + LDR r1, [r0] // Pickup current thread pointer + + /* Determine if there is a current thread to finish preserving. */ + + CBZ r1, __tx_ts_new // If NULL, skip preservation + + /* Recover PSP and preserve current thread context. */ + + STR r3, [r0] // Set _tx_thread_current_ptr to NULL + MRS r12, PSP // Pickup PSP pointer (thread's stack pointer) + STMDB r12!, {r4-r11} // Save its remaining registers +#ifdef __ARM_FP + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_save + VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers +_skip_vfp_save: +#endif + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + STMDB r12!, {LR} // Save LR on the stack + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + STR r12, [r1, #8] // Save the thread stack pointer + CBZ r5, __tx_ts_new // If not active, skip processing + + /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */ + + STR r5, [r1, #24] // Save current time-slice + + /* Clear the global time-slice. */ + + STR r3, [r4] // Clear time-slice + + /* Executing thread is now completely preserved!!! */ + +__tx_ts_new: + + /* Now we are looking for a new thread to execute! */ + +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Is there another thread ready to execute? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + STR r1, [r0] // Setup the current thread pointer to the new thread +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + + /* Increment the thread run count. */ + +__tx_ts_restore: + LDR r7, [r1, #4] // Pickup the current thread run count + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + LDR r5, [r1, #24] // Pickup thread's current time-slice + ADD r7, r7, #1 // Increment the thread run count + STR r7, [r1, #4] // Store the new run count + + /* Setup global time-slice with thread's current time-slice. */ + + STR r5, [r4] // Setup global time-slice + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread entry function to indicate the thread is executing. */ + PUSH {r0, r1} // Save r0 and r1 + BL _tx_execution_thread_enter // Call the thread execution enter function + POP {r0, r1} // Recover r0 and r1 +#endif + + /* Restore the thread context and PSP. */ + + LDR r12, [r1, #8] // Pickup thread's stack pointer + LDMIA r12!, {LR} // Pickup LR +#ifdef __ARM_FP + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_restore // If not, skip VFP restore + VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers +_skip_vfp_restore: +#endif + LDMIA r12!, {r4-r11} // Recover thread's registers + MSR PSP, r12 // Setup the thread's stack pointer + + /* Return to thread. */ + + BX lr // Return to thread! + + /* The following is the idle wait processing... in this case, no threads are ready for execution and the + system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts + are disabled to allow use of WFI for waiting for a thread to arrive. */ + +__tx_ts_wait: +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Pickup the next thread to execute pointer + STR r1, [r0] // Store it in the current pointer + CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready! + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_enter // Possibly enter low power mode + POP {r0-r3} +#endif + +#ifdef TX_ENABLE_WFI + DSB // Ensure no outstanding memory transactions + WFI // Wait for interrupt + ISB // Ensure pipeline is flushed +#endif + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_exit // Exit low power mode + POP {r0-r3} +#endif + +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_wait // Loop to continue waiting + + /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are + already in the handler! */ + +__tx_ts_ready: + MOV r7, #0x08000000 // Build clear PendSV value + MOV r8, #0xE000E000 // Build base NVIC address + STR r7, [r8, #0xD04] // Clear any PendSV + + /* Re-enable interrupts and restore new thread. */ +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_restore // Restore the thread +// } + +#ifdef __ARM_FP + + .global tx_thread_fpu_enable + .thumb_func +tx_thread_fpu_enable: + .global tx_thread_fpu_disable + .thumb_func +tx_thread_fpu_disable: + + /* Automatic VPF logic is supported, this function is present only for + backward compatibility purposes and therefore simply returns. */ + + BX LR // Return to caller + +#endif diff --git a/ports/cortex_m3/gnu/src/tx_thread_stack_build.S b/ports/cortex_m3/gnu/src/tx_thread_stack_build.S new file mode 100644 index 0000000..d78ebdc --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + .global _tx_thread_stack_build + .thumb_func +_tx_thread_stack_build: + + /* Build a fake interrupt frame. The form of the fake interrupt stack + on the Cortex-M should look like the following after it is built: + + Stack Top: + LR Interrupted LR (LR at time of PENDSV) + r4 Initial value for r4 + r5 Initial value for r5 + r6 Initial value for r6 + r7 Initial value for r7 + r8 Initial value for r8 + r9 Initial value for r9 + r10 Initial value for r10 + r11 Initial value for r11 + r0 Initial value for r0 (Hardware stack starts here!!) + r1 Initial value for r1 + r2 Initial value for r2 + r3 Initial value for r3 + r12 Initial value for r12 + lr Initial value for lr + pc Initial value for pc + xPSR Initial value for xPSR + + Stack Bottom: (higher memory address) */ + + LDR r2, [r0, #16] // Pickup end of stack area + BIC r2, r2, #0x7 // Align frame for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size + LDR r3, =0xFFFFFFFD // Build initial LR value + STR r3, [r2, #0] // Save on the stack + + /* Actually build the stack frame. */ + + MOV r3, #0 // Build initial register value + STR r3, [r2, #4] // Store initial r4 + STR r3, [r2, #8] // Store initial r5 + STR r3, [r2, #12] // Store initial r6 + STR r3, [r2, #16] // Store initial r7 + STR r3, [r2, #20] // Store initial r8 + STR r3, [r2, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + STR r3, [r2, #44] // Store initial r2 + STR r3, [r2, #48] // Store initial r3 + STR r3, [r2, #52] // Store initial r12 + MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value + STR r3, [r2, #56] // Store initial lr + STR r1, [r2, #60] // Store initial pc + MOV r3, #0x01000000 // Only T-bit need be set + STR r3, [r2, #64] // Store initial xPSR + + /* Setup stack pointer. */ + // thread_ptr -> tx_thread_stack_ptr = r2; + + STR r2, [r0, #8] // Save stack pointer in thread's + // control block + BX lr // Return to caller +// } diff --git a/ports/cortex_m3/gnu/src/tx_thread_system_return.S b/ports/cortex_m3/gnu/src/tx_thread_system_return.S new file mode 100644 index 0000000..3fa0c7a --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_system_return.S @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .text 32 + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + .thumb_func + .global _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } diff --git a/ports/cortex_m3/gnu/src/tx_timer_interrupt.S b/ports/cortex_m3/gnu/src/tx_timer_interrupt.S new file mode 100644 index 0000000..fc3e9db --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,260 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + .global _tx_timer_time_slice + .global _tx_timer_system_clock + .global _tx_timer_current_ptr + .global _tx_timer_list_start + .global _tx_timer_list_end + .global _tx_timer_expired_time_slice + .global _tx_timer_expired + .global _tx_thread_time_slice + .global _tx_timer_expiration_process + + .text + .align 4 + .syntax unified +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-M3/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* 03-08-2023 Scott Larson Include tx_user.h, */ +/* resulting in version 6.2.1 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + .global _tx_timer_interrupt + .thumb_func +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif diff --git a/ports/cortex_m3/iar/inc/tx_port.h b/ports/cortex_m3/iar/inc/tx_port.h new file mode 100644 index 0000000..5481873 --- /dev/null +++ b/ports/cortex_m3/iar/inc/tx_port.h @@ -0,0 +1,728 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/IAR */ +/* 6.1.12 */ +/* */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */ +/* the ARMv7-M architecture and compilers into one common file. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comments, updated */ +/* typedef to fix misra */ +/* violation, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#include "tx_ghs.h" +#endif /* __ghs__ */ + + +#if !defined(__GNUC__) && !defined(__CC_ARM) +#define __get_control_value __get_CONTROL +#define __set_control_value __set_CONTROL +#endif + +#ifndef __GNUC__ +#define __get_ipsr_value __get_IPSR +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long long ULONG64; +typedef short SHORT; +typedef unsigned short USHORT; +#define ULONG64_DEFINED + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + +/* By default, ThreadX for Cortex-M uses the PRIMASK register to enable/disable interrupts. +If using BASEPRI is desired, define the following two symbols for both c and assembly files: +TX_PORT_USE_BASEPRI - This tells ThreadX to use BASEPRI instead of PRIMASK. +TX_PORT_BASEPRI = (priority_mask << (8 - number_priority_bits)) - this defines the maximum priority level to mask. +Any interrupt with a higher priority than priority_mask will not be masked, thus the interrupt will run. +*/ + +/* Define various constants for the ThreadX Cortex-M port. */ + +#define TX_INT_DISABLE 1 /* Disable interrupts */ +#define TX_INT_ENABLE 0 /* Enable interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0xE0001004) +#endif +#else +ULONG _tx_misra_time_stamp_get(VOID); +#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get() +#endif + +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#ifdef TX_MISRA_ENABLE +#define TX_DISABLE_INLINE +#else +#define TX_INLINE_INITIALIZATION +#endif + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifndef TX_MISRA_ENABLE +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#elif defined(__ghs__) +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#else +#define TX_THREAD_EXTENSION_2 +#endif + + +#define TX_THREAD_EXTENSION_3 + + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#if (__VER__ < 8000000) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0); +#else +void *_tx_iar_create_per_thread_tls_area(void); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); +void __iar_Initlocks(void); + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0); +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); +#endif +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + +#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) + +#ifdef TX_MISRA_ENABLE + +ULONG _tx_misra_control_get(void); +void _tx_misra_control_set(ULONG value); +ULONG _tx_misra_fpccr_get(void); +void _tx_misra_vfp_touch(void); + +#else /* TX_MISRA_ENABLE not defined */ + +/* Define some helper functions (these are intrinsics in some compilers). */ +#ifdef __GNUC__ /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + +__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value) +{ + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); + +#elif defined(__CC_ARM) /* ARM Compiler 5 */ + +__attribute__( ( always_inline ) ) ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm volatile ("MRS control_value,CONTROL"); + return(control_value); +} + +__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value) +{ + __asm__ volatile ("MSR CONTROL,control_value"); +} +/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */ +void _tx_vfp_access(void); +#define TX_VFP_TOUCH() _tx_vfp_access(); + +#elif defined(__ICCARM__) /* IAR */ +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); +#endif /* Helper functions for different compilers */ + +#endif /* TX_MISRA_ENABLE */ + + +/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA + in order to ensure no lazy stacking will occur. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } +#else + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } + +#endif + +/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR. + If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating + this one, so if the FPCCR.LSPACT bit is set, we need to save the CONTROL.FPCA state, touch the FPU to flush + the lazy FPU save, then restore the CONTROL.FPCA state. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((volatile ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + TX_VFP_TOUCH(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + } \ + } \ + } +#else + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = _tx_misra_fpccr_get(); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + _tx_misra_vfp_touch(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + } \ + } \ + } +#endif + +#else /* No VFP in use */ + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */ + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define the get system state macro. */ + +#ifndef TX_THREAD_GET_SYSTEM_STATE +#ifndef TX_MISRA_ENABLE + +#ifdef __CC_ARM /* ARM Compiler 5 */ + +register unsigned int _ipsr __asm("ipsr"); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr) + +#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void) +{ +unsigned int ipsr_value; + __asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) ); + return(ipsr_value); +} + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value()) + +#elif defined(__ICCARM__) /* IAR */ + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR()) + +#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */ + +#else /* TX_MISRA_ENABLE is defined, use MISRA function. */ +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif /* TX_MISRA_ENABLE */ +#endif /* TX_THREAD_GET_SYSTEM_STATE */ + + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h + for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always + zero after initialization for Cortex-M ports. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable); +#endif + +/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to + prevent early scheduling on Cortex-M parts. */ + +#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++; + + + + +#ifndef TX_DISABLE_INLINE + +/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */ +#ifdef __ICCARM__ /* IAR Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m))); +#elif defined(__CC_ARM) /* AC5 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m))); +#elif defined(__GNUC__) /* GCC and AC6 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); +#endif + + + +/* Define the interrupt disable/restore macros for each compiler. */ + +#if defined(__GNUC__) || defined(__ICCARM__) + +/*** GCC/AC6 and IAR ***/ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture)); +#else + __asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture)); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +__attribute__( ( always_inline ) ) static inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value)); +} +#else +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + __asm__ volatile ("CPSIE i": : : "memory"); +} +#endif + +__attribute__( ( always_inline ) ) static inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); + //__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory"); +#else + __asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory"); +#endif +} + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i" : : : "memory"); +#endif + return(int_posture); +} + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_interrupt_posture(); +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(0); +#else + __enable_interrupts(); +#endif + __restore_interrupt(interrupt_save); + } +} + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End GCC/AC6 and IAR ***/ + +#elif defined(__CC_ARM) + +/*** AC5 ***/ + +static __inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS #posture, BASEPRI"); +#else + __asm__ volatile ("MRS #posture, PRIMASK"); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +static __inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI, #basepri_value"); +} +#endif + +static __inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i"); +#endif + return(int_posture); +} + +static __inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); +#else + __asm__ volatile ("MSR PRIMASK, #int_posture"); +#endif +} + +static void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (_ipsr == 0) + { +#ifdef TX_PORT_USE_BASEPRI + interrupt_save = __get_interrupt_posture(); + __set_basepri_value(0); + __set_basepri_value(interrupt_save); +#else + interrupt_save = __disable_irq(); + __enable_irq(); + if (interrupt_save != 0) + __disable_irq(); +#endif + } +} + + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End AC5 ***/ + +#endif /* Interrupt disable/restore macros for each compiler. */ + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else /* TX_DISABLE_INLINE is defined */ + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); +#endif /* TX_DISABLE_INLINE */ + + +/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing + thread. These are no longer needed, but are preserved for backward compatibility only. */ + +void tx_thread_fpu_enable(void); +void tx_thread_fpu_disable(void); + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) 2024 Microsoft Corporation. * ThreadX Cortex-M3/IAR Version 6.4.2 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + + +#endif diff --git a/ports/cortex_m3/iar/src/tx_iar.c b/ports/cortex_m3/iar/src/tx_iar.c new file mode 100644 index 0000000..c6092de --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_iar.c @@ -0,0 +1,803 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** IAR Multithreaded Library Support */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Define IAR library for tools prior to version 8. */ + +#if (__VER__ < 8000000) + + +/* IAR version 7 and below. */ + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/* This implementation requires that the following macros are defined in the + tx_port.h file and is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#else +#define TX_THREAD_EXTENSION_2 +#endif + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0); +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + + This should be done automatically if TX_ENABLE_IAR_LIBRARY_SUPPORT is defined while building the ThreadX library and the + application. + + Finally, the project options General Options -> Library Configuration should have the "Enable thread support in library" box selected. +*/ + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT + +#include + + +#if _MULTI_THREAD + +TX_MUTEX __tx_iar_system_lock_mutexes[_MAX_LOCK]; +UINT __tx_iar_system_lock_next_free_mutex = 0; + + +/* Define error counters, just for debug purposes. */ + +UINT __tx_iar_system_lock_no_mutexes; +UINT __tx_iar_system_lock_internal_errors; +UINT __tx_iar_system_lock_isr_caller; + + +/* Define the TLS access function for the IAR library. */ + +void _DLIB_TLS_MEMORY *__iar_dlib_perthread_access(void _DLIB_TLS_MEMORY *symbp) +{ + +char _DLIB_TLS_MEMORY *p = 0; + + /* Is there a current thread? */ + if (_tx_thread_current_ptr) + p = (char _DLIB_TLS_MEMORY *) _tx_thread_current_ptr -> tx_thread_iar_tls_pointer; + else + p = (void _DLIB_TLS_MEMORY *) __segment_begin("__DLIB_PERTHREAD"); + p += __IAR_DLIB_PERTHREAD_SYMBOL_OFFSET(symbp); + return (void _DLIB_TLS_MEMORY *) p; +} + + +/* Define mutexes for IAR library. */ + +void __iar_system_Mtxinit(__iar_Rmtx *m) +{ + +UINT i; +UINT status; +TX_MUTEX *mutex_ptr; + + + /* First, find a free mutex in the list. */ + for (i = 0; i < _MAX_LOCK; i++) + { + + /* Setup a pointer to the start of the next free mutex. */ + mutex_ptr = &__tx_iar_system_lock_mutexes[__tx_iar_system_lock_next_free_mutex++]; + + /* Check for wrap-around on the next free mutex. */ + if (__tx_iar_system_lock_next_free_mutex >= _MAX_LOCK) + { + + /* Yes, set the free index back to 0. */ + __tx_iar_system_lock_next_free_mutex = 0; + } + + /* Is this mutex free? */ + if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Yes, this mutex is free, get out of the loop! */ + break; + } + } + + /* Determine if a free mutex was found. */ + if (i >= _MAX_LOCK) + { + + /* Error! No more free mutexes! */ + + /* Increment the no mutexes error counter. */ + __tx_iar_system_lock_no_mutexes++; + + /* Set return pointer to NULL. */ + *m = TX_NULL; + + /* Return. */ + return; + } + + /* Now create the ThreadX mutex for the IAR library. */ + status = _tx_mutex_create(mutex_ptr, "IAR System Library Lock", TX_NO_INHERIT); + + /* Determine if the creation was successful. */ + if (status == TX_SUCCESS) + { + + /* Yes, successful creation, return mutex pointer. */ + *m = (VOID *) mutex_ptr; + } + else + { + + /* Increment the internal error counter. */ + __tx_iar_system_lock_internal_errors++; + + /* Return a NULL pointer to indicate an error. */ + *m = TX_NULL; + } +} + +void __iar_system_Mtxdst(__iar_Rmtx *m) +{ + + /* Simply delete the mutex. */ + _tx_mutex_delete((TX_MUTEX *) *m); +} + +void __iar_system_Mtxlock(__iar_Rmtx *m) +{ + +UINT status; + + + /* Determine the caller's context. Mutex locks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Get the mutex. */ + status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_system_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_system_lock_isr_caller++; + } +} + +void __iar_system_Mtxunlock(__iar_Rmtx *m) +{ + +UINT status; + + + /* Determine the caller's context. Mutex unlocks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Release the mutex. */ + status = _tx_mutex_put((TX_MUTEX *) *m); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_system_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_system_lock_isr_caller++; + } +} + + +#if _DLIB_FILE_DESCRIPTOR + +TX_MUTEX __tx_iar_file_lock_mutexes[_MAX_FLOCK]; +UINT __tx_iar_file_lock_next_free_mutex = 0; + + +/* Define error counters, just for debug purposes. */ + +UINT __tx_iar_file_lock_no_mutexes; +UINT __tx_iar_file_lock_internal_errors; +UINT __tx_iar_file_lock_isr_caller; + + +void __iar_file_Mtxinit(__iar_Rmtx *m) +{ + +UINT i; +UINT status; +TX_MUTEX *mutex_ptr; + + + /* First, find a free mutex in the list. */ + for (i = 0; i < _MAX_FLOCK; i++) + { + + /* Setup a pointer to the start of the next free mutex. */ + mutex_ptr = &__tx_iar_file_lock_mutexes[__tx_iar_file_lock_next_free_mutex++]; + + /* Check for wrap-around on the next free mutex. */ + if (__tx_iar_file_lock_next_free_mutex >= _MAX_LOCK) + { + + /* Yes, set the free index back to 0. */ + __tx_iar_file_lock_next_free_mutex = 0; + } + + /* Is this mutex free? */ + if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Yes, this mutex is free, get out of the loop! */ + break; + } + } + + /* Determine if a free mutex was found. */ + if (i >= _MAX_LOCK) + { + + /* Error! No more free mutexes! */ + + /* Increment the no mutexes error counter. */ + __tx_iar_file_lock_no_mutexes++; + + /* Set return pointer to NULL. */ + *m = TX_NULL; + + /* Return. */ + return; + } + + /* Now create the ThreadX mutex for the IAR library. */ + status = _tx_mutex_create(mutex_ptr, "IAR File Library Lock", TX_NO_INHERIT); + + /* Determine if the creation was successful. */ + if (status == TX_SUCCESS) + { + + /* Yes, successful creation, return mutex pointer. */ + *m = (VOID *) mutex_ptr; + } + else + { + + /* Increment the internal error counter. */ + __tx_iar_file_lock_internal_errors++; + + /* Return a NULL pointer to indicate an error. */ + *m = TX_NULL; + } +} + +void __iar_file_Mtxdst(__iar_Rmtx *m) +{ + + /* Simply delete the mutex. */ + _tx_mutex_delete((TX_MUTEX *) *m); +} + +void __iar_file_Mtxlock(__iar_Rmtx *m) +{ + +UINT status; + + + /* Determine the caller's context. Mutex locks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Get the mutex. */ + status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_file_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_file_lock_isr_caller++; + } +} + +void __iar_file_Mtxunlock(__iar_Rmtx *m) +{ + +UINT status; + + + /* Determine the caller's context. Mutex unlocks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Release the mutex. */ + status = _tx_mutex_put((TX_MUTEX *) *m); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_file_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_file_lock_isr_caller++; + } +} +#endif /* _DLIB_FILE_DESCRIPTOR */ + +#endif /* _MULTI_THREAD */ + +#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */ + +#else /* IAR version 8 and above. */ + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_mutex.h" + +/* This implementation requires that the following macros are defined in the + tx_port.h file and is included with the following code segments: + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#else +#define TX_THREAD_EXTENSION_2 +#endif + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +void *_tx_iar_create_per_thread_tls_area(void); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); +void __iar_Initlocks(void); + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {__iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0); +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + + This should be done automatically if TX_ENABLE_IAR_LIBRARY_SUPPORT is defined while building the ThreadX library and the + application. + + Finally, the project options General Options -> Library Configuration should have the "Enable thread support in library" box selected. +*/ + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT + +#include + + +void * __aeabi_read_tp(); + +void* _tx_iar_create_per_thread_tls_area(); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); + +#pragma section="__iar_tls$$DATA" + +/* Define the TLS access function for the IAR library. */ +void * __aeabi_read_tp(void) +{ + void *p = 0; + TX_THREAD *thread_ptr = _tx_thread_current_ptr; + if (thread_ptr) + { + p = thread_ptr->tx_thread_iar_tls_pointer; + } + else + { + p = __section_begin("__iar_tls$$DATA"); + } + return p; +} + +/* Define the TLS creation and destruction to use malloc/free. */ + +void* _tx_iar_create_per_thread_tls_area() +{ + UINT tls_size = __iar_tls_size(); + + /* Get memory for TLS. */ + void *p = malloc(tls_size); + + /* Initialize TLS-area and run constructors for objects in TLS */ + __iar_tls_init(p); + return p; +} + +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr) +{ + /* Destroy objects living in TLS */ + __call_thread_dtors(); + free(tls_ptr); +} + +#ifndef _MAX_LOCK +#define _MAX_LOCK 4 +#endif + +static TX_MUTEX __tx_iar_system_lock_mutexes[_MAX_LOCK]; +static UINT __tx_iar_system_lock_next_free_mutex = 0; + + +/* Define error counters, just for debug purposes. */ + +UINT __tx_iar_system_lock_no_mutexes; +UINT __tx_iar_system_lock_internal_errors; +UINT __tx_iar_system_lock_isr_caller; + + +/* Define mutexes for IAR library. */ + +void __iar_system_Mtxinit(__iar_Rmtx *m) +{ + +UINT i; +UINT status; +TX_MUTEX *mutex_ptr; + + + /* First, find a free mutex in the list. */ + for (i = 0; i < _MAX_LOCK; i++) + { + + /* Setup a pointer to the start of the next free mutex. */ + mutex_ptr = &__tx_iar_system_lock_mutexes[__tx_iar_system_lock_next_free_mutex++]; + + /* Check for wrap-around on the next free mutex. */ + if (__tx_iar_system_lock_next_free_mutex >= _MAX_LOCK) + { + + /* Yes, set the free index back to 0. */ + __tx_iar_system_lock_next_free_mutex = 0; + } + + /* Is this mutex free? */ + if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Yes, this mutex is free, get out of the loop! */ + break; + } + } + + /* Determine if a free mutex was found. */ + if (i >= _MAX_LOCK) + { + + /* Error! No more free mutexes! */ + + /* Increment the no mutexes error counter. */ + __tx_iar_system_lock_no_mutexes++; + + /* Set return pointer to NULL. */ + *m = TX_NULL; + + /* Return. */ + return; + } + + /* Now create the ThreadX mutex for the IAR library. */ + status = _tx_mutex_create(mutex_ptr, "IAR System Library Lock", TX_NO_INHERIT); + + /* Determine if the creation was successful. */ + if (status == TX_SUCCESS) + { + + /* Yes, successful creation, return mutex pointer. */ + *m = (VOID *) mutex_ptr; + } + else + { + + /* Increment the internal error counter. */ + __tx_iar_system_lock_internal_errors++; + + /* Return a NULL pointer to indicate an error. */ + *m = TX_NULL; + } +} + +void __iar_system_Mtxdst(__iar_Rmtx *m) +{ + + /* Simply delete the mutex. */ + _tx_mutex_delete((TX_MUTEX *) *m); +} + +void __iar_system_Mtxlock(__iar_Rmtx *m) +{ + if (*m) + { + UINT status; + + /* Determine the caller's context. Mutex locks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Get the mutex. */ + status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_system_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_system_lock_isr_caller++; + } + } +} + +void __iar_system_Mtxunlock(__iar_Rmtx *m) +{ + if (*m) + { + UINT status; + + /* Determine the caller's context. Mutex unlocks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Release the mutex. */ + status = _tx_mutex_put((TX_MUTEX *) *m); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_system_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_system_lock_isr_caller++; + } + } +} + + +#if _DLIB_FILE_DESCRIPTOR + +#include /* Added to get access to FOPEN_MAX */ +#ifndef _MAX_FLOCK +#define _MAX_FLOCK FOPEN_MAX /* Define _MAX_FLOCK as the maximum number of open files */ +#endif + + +TX_MUTEX __tx_iar_file_lock_mutexes[_MAX_FLOCK]; +UINT __tx_iar_file_lock_next_free_mutex = 0; + + +/* Define error counters, just for debug purposes. */ + +UINT __tx_iar_file_lock_no_mutexes; +UINT __tx_iar_file_lock_internal_errors; +UINT __tx_iar_file_lock_isr_caller; + + +void __iar_file_Mtxinit(__iar_Rmtx *m) +{ + +UINT i; +UINT status; +TX_MUTEX *mutex_ptr; + + + /* First, find a free mutex in the list. */ + for (i = 0; i < _MAX_FLOCK; i++) + { + + /* Setup a pointer to the start of the next free mutex. */ + mutex_ptr = &__tx_iar_file_lock_mutexes[__tx_iar_file_lock_next_free_mutex++]; + + /* Check for wrap-around on the next free mutex. */ + if (__tx_iar_file_lock_next_free_mutex >= _MAX_LOCK) + { + + /* Yes, set the free index back to 0. */ + __tx_iar_file_lock_next_free_mutex = 0; + } + + /* Is this mutex free? */ + if (mutex_ptr -> tx_mutex_id != TX_MUTEX_ID) + { + + /* Yes, this mutex is free, get out of the loop! */ + break; + } + } + + /* Determine if a free mutex was found. */ + if (i >= _MAX_LOCK) + { + + /* Error! No more free mutexes! */ + + /* Increment the no mutexes error counter. */ + __tx_iar_file_lock_no_mutexes++; + + /* Set return pointer to NULL. */ + *m = TX_NULL; + + /* Return. */ + return; + } + + /* Now create the ThreadX mutex for the IAR library. */ + status = _tx_mutex_create(mutex_ptr, "IAR File Library Lock", TX_NO_INHERIT); + + /* Determine if the creation was successful. */ + if (status == TX_SUCCESS) + { + + /* Yes, successful creation, return mutex pointer. */ + *m = (VOID *) mutex_ptr; + } + else + { + + /* Increment the internal error counter. */ + __tx_iar_file_lock_internal_errors++; + + /* Return a NULL pointer to indicate an error. */ + *m = TX_NULL; + } +} + +void __iar_file_Mtxdst(__iar_Rmtx *m) +{ + + /* Simply delete the mutex. */ + _tx_mutex_delete((TX_MUTEX *) *m); +} + +void __iar_file_Mtxlock(__iar_Rmtx *m) +{ + +UINT status; + + + /* Determine the caller's context. Mutex locks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Get the mutex. */ + status = _tx_mutex_get((TX_MUTEX *) *m, TX_WAIT_FOREVER); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_file_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_file_lock_isr_caller++; + } +} + +void __iar_file_Mtxunlock(__iar_Rmtx *m) +{ + +UINT status; + + + /* Determine the caller's context. Mutex unlocks are only available from initialization and + threads. */ + if ((_tx_thread_system_state == 0) || (_tx_thread_system_state >= TX_INITIALIZE_IN_PROGRESS)) + { + + /* Release the mutex. */ + status = _tx_mutex_put((TX_MUTEX *) *m); + + /* Check the status of the mutex release. */ + if (status) + { + + /* Internal error, increment the counter. */ + __tx_iar_file_lock_internal_errors++; + } + } + else + { + + /* Increment the ISR caller error. */ + __tx_iar_file_lock_isr_caller++; + } +} +#endif /* _DLIB_FILE_DESCRIPTOR */ + +#endif /* TX_ENABLE_IAR_LIBRARY_SUPPORT */ + +#endif /* IAR version 8 and above. */ diff --git a/ports/cortex_m3/iar/src/tx_misra.s b/ports/cortex_m3/iar/src/tx_misra.s new file mode 100644 index 0000000..f86d9a6 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_misra.s @@ -0,0 +1,766 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX MISRA Compliance */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + #define SHT_PROGBITS 0x1 + + EXTERN __aeabi_memset + EXTERN _tx_thread_current_ptr + EXTERN _tx_thread_interrupt_disable + EXTERN _tx_thread_interrupt_restore + EXTERN _tx_thread_stack_analyze + EXTERN _tx_thread_stack_error_handler + EXTERN _tx_thread_system_state +#ifdef TX_ENABLE_EVENT_TRACE + EXTERN _tx_trace_buffer_current_ptr + EXTERN _tx_trace_buffer_end_ptr + EXTERN _tx_trace_buffer_start_ptr + EXTERN _tx_trace_event_enable_bits + EXTERN _tx_trace_full_notify_function + EXTERN _tx_trace_header_ptr +#endif + + PUBLIC _tx_misra_always_true + PUBLIC _tx_misra_block_pool_to_uchar_pointer_convert + PUBLIC _tx_misra_byte_pool_to_uchar_pointer_convert + PUBLIC _tx_misra_char_to_uchar_pointer_convert + PUBLIC _tx_misra_const_char_to_char_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + PUBLIC _tx_misra_entry_to_uchar_pointer_convert +#endif + PUBLIC _tx_misra_indirect_void_to_uchar_pointer_convert + PUBLIC _tx_misra_memset + PUBLIC _tx_misra_message_copy +#ifdef TX_ENABLE_EVENT_TRACE + PUBLIC _tx_misra_object_to_uchar_pointer_convert +#endif + PUBLIC _tx_misra_pointer_to_ulong_convert + PUBLIC _tx_misra_status_get + PUBLIC _tx_misra_thread_stack_check +#ifdef TX_ENABLE_EVENT_TRACE + PUBLIC _tx_misra_time_stamp_get +#endif + PUBLIC _tx_misra_timer_indirect_to_void_pointer_convert + PUBLIC _tx_misra_timer_pointer_add + PUBLIC _tx_misra_timer_pointer_dif +#ifdef TX_ENABLE_EVENT_TRACE + PUBLIC _tx_misra_trace_event_insert +#endif + PUBLIC _tx_misra_uchar_pointer_add + PUBLIC _tx_misra_uchar_pointer_dif + PUBLIC _tx_misra_uchar_pointer_sub + PUBLIC _tx_misra_uchar_to_align_type_pointer_convert + PUBLIC _tx_misra_uchar_to_block_pool_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + PUBLIC _tx_misra_uchar_to_entry_pointer_convert + PUBLIC _tx_misra_uchar_to_header_pointer_convert +#endif + PUBLIC _tx_misra_uchar_to_indirect_byte_pool_pointer_convert + PUBLIC _tx_misra_uchar_to_indirect_uchar_pointer_convert +#ifdef TX_ENABLE_EVENT_TRACE + PUBLIC _tx_misra_uchar_to_object_pointer_convert +#endif + PUBLIC _tx_misra_uchar_to_void_pointer_convert + PUBLIC _tx_misra_ulong_pointer_add + PUBLIC _tx_misra_ulong_pointer_dif + PUBLIC _tx_misra_ulong_pointer_sub + PUBLIC _tx_misra_ulong_to_pointer_convert + PUBLIC _tx_misra_ulong_to_thread_pointer_convert + PUBLIC _tx_misra_user_timer_pointer_get + PUBLIC _tx_misra_void_to_block_pool_pointer_convert + PUBLIC _tx_misra_void_to_byte_pool_pointer_convert + PUBLIC _tx_misra_void_to_event_flags_pointer_convert + PUBLIC _tx_misra_void_to_indirect_uchar_pointer_convert + PUBLIC _tx_misra_void_to_mutex_pointer_convert + PUBLIC _tx_misra_void_to_queue_pointer_convert + PUBLIC _tx_misra_void_to_semaphore_pointer_convert + PUBLIC _tx_misra_void_to_thread_pointer_convert + PUBLIC _tx_misra_void_to_uchar_pointer_convert + PUBLIC _tx_misra_void_to_ulong_pointer_convert + PUBLIC _tx_misra_ipsr_get + PUBLIC _tx_misra_control_get + PUBLIC _tx_misra_control_set +#ifdef __ARMVFP__ + PUBLIC _tx_misra_fpccr_get + PUBLIC _tx_misra_vfp_touch +#endif + + PUBLIC _tx_misra_event_flags_group_not_used + PUBLIC _tx_misra_event_flags_set_notify_not_used + PUBLIC _tx_misra_queue_not_used + PUBLIC _tx_misra_queue_send_notify_not_used + PUBLIC _tx_misra_semaphore_not_used + PUBLIC _tx_misra_semaphore_put_notify_not_used + PUBLIC _tx_misra_thread_entry_exit_notify_not_used + PUBLIC _tx_misra_thread_not_used + +#ifdef TX_MISRA_ENABLE + PUBLIC _tx_version_id + + SECTION `.data`:DATA:REORDER:NOROOT(2) + DATA +// 51 CHAR _tx_version_id[100] = "Copyright (c) 2024 Microsoft Corporation. * ThreadX 6.1 MISRA C Compliant *"; +_tx_version_id: + DC8 43H, 6FH, 70H, 79H, 72H, 69H, 67H, 68H + DC8 74H, 20H, 28H, 63H, 29H, 20H, 31H, 39H + DC8 39H, 36H, 2DH, 32H, 30H, 31H, 38H, 20H + DC8 45H, 78H, 70H, 72H, 65H, 73H, 73H, 20H + DC8 4CH, 6FH, 67H, 69H, 63H, 20H, 49H, 6EH + DC8 63H, 2EH, 20H, 2AH, 20H, 54H, 68H, 72H + DC8 65H, 61H, 64H, 58H, 20H, 36H, 2EH, 31H + DC8 20H, 4DH, 49H, 53H, 52H, 41H, 20H, 43H + DC8 20H, 43H, 6FH, 6DH, 70H, 6CH, 69H, 61H + DC8 6EH, 74H, 20H, 2AH, 0 + DC8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +#endif //TX_MISRA_ENABLE + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_memset: + PUSH {R4,LR} + MOVS R4,R0 + MOVS R0,R2 + MOVS R2,R1 + MOVS R1,R0 + MOVS R0,R4 + BL __aeabi_memset + POP {R4,PC} // return + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_uchar_pointer_add: + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_uchar_pointer_sub: + RSBS R1,R1,#+0 + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_uchar_pointer_dif: + SUBS R0,R0,R1 + BX LR // return + + +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ +/** */ +/** This single function serves all of the below prototypes. */ +/** */ +/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */ +/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */ +/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */ +/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */ +/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */ +/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */ +/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */ +/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */ +/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */ +/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */ +/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */ +/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */ +/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */ +/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */ +/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */ +/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */ +/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */ +/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */ +/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */ +/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */ +/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */ +/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */ +/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */ +/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */ +/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */ +/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */ +/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */ +/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */ +/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */ +/** VOID _tx_misra_event_flags_group_not_used(TX_EVENT_FLAGS_GROUP *group_ptr); */ +/** VOID _tx_misra_event_flags_set_notify_not_used(VOID (*events_set_notify)(TX_EVENT_FLAGS_GROUP *notify_group_ptr)); */ +/** VOID _tx_misra_queue_not_used(TX_QUEUE *queue_ptr); */ +/** VOID _tx_misra_queue_send_notify_not_used(VOID (*queue_send_notify)(TX_QUEUE *notify_queue_ptr)); */ +/** VOID _tx_misra_semaphore_not_used(TX_SEMAPHORE *semaphore_ptr); */ +/** VOID _tx_misra_semaphore_put_notify_not_used(VOID (*semaphore_put_notify)(TX_SEMAPHORE *notify_semaphore_ptr)); */ +/** VOID _tx_misra_thread_not_used(TX_THREAD *thread_ptr); */ +/** VOID _tx_misra_thread_entry_exit_notify_not_used(VOID (*thread_entry_exit_notify)(TX_THREAD *notify_thread_ptr, UINT id)); */ +/** */ +/************************************************************************************************************************************/ +/************************************************************************************************************************************/ + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_pointer_to_ulong_convert: +_tx_misra_ulong_to_pointer_convert: +_tx_misra_indirect_void_to_uchar_pointer_convert: +_tx_misra_uchar_to_indirect_uchar_pointer_convert: +_tx_misra_block_pool_to_uchar_pointer_convert: +_tx_misra_void_to_block_pool_pointer_convert: +_tx_misra_void_to_uchar_pointer_convert: +_tx_misra_uchar_to_block_pool_pointer_convert: +_tx_misra_void_to_indirect_uchar_pointer_convert: +_tx_misra_void_to_byte_pool_pointer_convert: +_tx_misra_byte_pool_to_uchar_pointer_convert: +_tx_misra_uchar_to_align_type_pointer_convert: +_tx_misra_uchar_to_indirect_byte_pool_pointer_convert: +_tx_misra_void_to_event_flags_pointer_convert: +_tx_misra_void_to_ulong_pointer_convert: +_tx_misra_void_to_mutex_pointer_convert: +_tx_misra_void_to_queue_pointer_convert: +_tx_misra_void_to_semaphore_pointer_convert: +_tx_misra_uchar_to_void_pointer_convert: +_tx_misra_ulong_to_thread_pointer_convert: +_tx_misra_timer_indirect_to_void_pointer_convert: +_tx_misra_const_char_to_char_pointer_convert: +_tx_misra_void_to_thread_pointer_convert: +#ifdef TX_ENABLE_EVENT_TRACE +_tx_misra_object_to_uchar_pointer_convert: +_tx_misra_uchar_to_object_pointer_convert: +_tx_misra_uchar_to_header_pointer_convert: +_tx_misra_uchar_to_entry_pointer_convert: +_tx_misra_entry_to_uchar_pointer_convert: +#endif +_tx_misra_char_to_uchar_pointer_convert: +_tx_misra_event_flags_group_not_used: +_tx_misra_event_flags_set_notify_not_used: +_tx_misra_queue_not_used: +_tx_misra_queue_send_notify_not_used: +_tx_misra_semaphore_not_used: +_tx_misra_semaphore_put_notify_not_used: +_tx_misra_thread_entry_exit_notify_not_used: +_tx_misra_thread_not_used: + + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_ulong_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_ulong_pointer_sub: + MVNS R2,#+3 + MULS R1,R2,R1 + ADD R0,R0,R1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_ulong_pointer_dif: + SUBS R0,R0,R1 + ASRS R0,R0,#+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */ +/** UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_message_copy: + PUSH {R4,R5} + LDR R3,[R0, #+0] + LDR R4,[R1, #+0] + LDR R5,[R3, #+0] + STR R5,[R4, #+0] + ADDS R4,R4,#+4 + ADDS R3,R3,#+4 + CMP R2,#+2 + BCC.N ??_tx_misra_message_copy_0 + SUBS R2,R2,#+1 + B.N ??_tx_misra_message_copy_1 +??_tx_misra_message_copy_2: + LDR R5,[R3, #+0] + STR R5,[R4, #+0] + ADDS R4,R4,#+4 + ADDS R3,R3,#+4 + SUBS R2,R2,#+1 +??_tx_misra_message_copy_1: + CMP R2,#+0 + BNE.N ??_tx_misra_message_copy_2 +??_tx_misra_message_copy_0: + STR R3,[R0, #+0] + STR R4,[R1, #+0] + POP {R4,R5} + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */ +/** TX_TIMER_INTERNAL **ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_timer_pointer_dif: + SUBS R0,R0,R1 + ASRS R0,R0,#+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */ +/** **ptr1, ULONG size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_timer_pointer_add: + ADD R0,R0,R1, LSL #+2 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */ +/** *internal_timer, TX_TIMER **user_timer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_user_timer_pointer_get: + SUBS R0,#8 + STR R0,[R1, #+0] + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */ +/** VOID **highest_stack); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_thread_stack_check: + PUSH {R3-R5,LR} + MOVS R4,R0 + MOVS R5,R1 + BL _tx_thread_interrupt_disable + CMP R4,#+0 + BEQ.N ??_tx_misra_thread_stack_check_0 + LDR R1,[R4, #+0] + LDR.N R2,??DataTable2 // 0x54485244 + CMP R1,R2 + BNE.N ??_tx_misra_thread_stack_check_0 + LDR R1,[R4, #+8] + LDR R2,[R5, #+0] + CMP R1,R2 + BCS.N ??_tx_misra_thread_stack_check_1 + LDR R1,[R4, #+8] + STR R1,[R5, #+0] +??_tx_misra_thread_stack_check_1: + LDR R1,[R4, #+12] + LDR R1,[R1, #+0] + CMP R1,#-269488145 + BNE.N ??_tx_misra_thread_stack_check_2 + LDR R1,[R4, #+16] + LDR R1,[R1, #+1] + CMP R1,#-269488145 + BNE.N ??_tx_misra_thread_stack_check_2 + LDR R1,[R5, #+0] + LDR R2,[R4, #+12] + CMP R1,R2 + BCS.N ??_tx_misra_thread_stack_check_3 +??_tx_misra_thread_stack_check_2: + BL _tx_thread_interrupt_restore + MOVS R0,R4 + BL _tx_thread_stack_error_handler + BL _tx_thread_interrupt_disable +??_tx_misra_thread_stack_check_3: + LDR R1,[R5, #+0] + LDR R1,[R1, #-4] + CMP R1,#-269488145 + BEQ.N ??_tx_misra_thread_stack_check_0 + BL _tx_thread_interrupt_restore + MOVS R0,R4 + BL _tx_thread_stack_analyze + BL _tx_thread_interrupt_disable +??_tx_misra_thread_stack_check_0: + BL _tx_thread_interrupt_restore + POP {R0,R4,R5,PC} // return + +#ifdef TX_ENABLE_EVENT_TRACE + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_trace_event_insert(ULONG event_id, */ +/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */ +/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_trace_event_insert: + PUSH {R3-R7,LR} + LDR.N R4,??DataTable2_1 + LDR R4,[R4, #+0] + CMP R4,#+0 + BEQ.N ??_tx_misra_trace_event_insert_0 + LDR.N R5,??DataTable2_2 + LDR R5,[R5, #+0] + LDR R6,[SP, #+28] + TST R5,R6 + BEQ.N ??_tx_misra_trace_event_insert_0 + LDR.N R5,??DataTable2_3 + LDR R5,[R5, #+0] + LDR.N R6,??DataTable2_4 + LDR R6,[R6, #+0] + CMP R5,#+0 + BNE.N ??_tx_misra_trace_event_insert_1 + LDR R5,[R6, #+44] + LDR R7,[R6, #+60] + LSLS R7,R7,#+16 + ORRS R7,R7,#0x80000000 + ORRS R5,R7,R5 + B.N ??_tx_misra_trace_event_insert_2 +??_tx_misra_trace_event_insert_1: + CMP R5,#-252645136 + BCS.N ??_tx_misra_trace_event_insert_3 + MOVS R5,R6 + MOVS R6,#-1 + B.N ??_tx_misra_trace_event_insert_2 +??_tx_misra_trace_event_insert_3: + MOVS R6,#-252645136 + MOVS R5,#+0 +??_tx_misra_trace_event_insert_2: + STR R6,[R4, #+0] + STR R5,[R4, #+4] + STR R0,[R4, #+8] + LDR R0,[SP, #+32] + STR R0,[R4, #+12] + STR R1,[R4, #+16] + STR R2,[R4, #+20] + STR R3,[R4, #+24] + LDR R0,[SP, #+24] + STR R0,[R4, #+28] + ADDS R4,R4,#+32 + LDR.N R0,??DataTable2_5 + LDR R0,[R0, #+0] + CMP R4,R0 + BCC.N ??_tx_misra_trace_event_insert_4 + LDR.N R0,??DataTable2_6 + LDR R4,[R0, #+0] + LDR.N R0,??DataTable2_1 + STR R4,[R0, #+0] + LDR.N R0,??DataTable2_7 + LDR R0,[R0, #+0] + STR R4,[R0, #+32] + LDR.N R0,??DataTable2_8 + LDR R0,[R0, #+0] + CMP R0,#+0 + BEQ.N ??_tx_misra_trace_event_insert_0 + LDR.N R0,??DataTable2_7 + LDR R0,[R0, #+0] + LDR.N R1,??DataTable2_8 + LDR R1,[R1, #+0] + BLX R1 + B.N ??_tx_misra_trace_event_insert_0 +??_tx_misra_trace_event_insert_4: + LDR.N R0,??DataTable2_1 + STR R4,[R0, #+0] + LDR.N R0,??DataTable2_7 + LDR R0,[R0, #+0] + STR R4,[R0, #+32] +??_tx_misra_trace_event_insert_0: + POP {R0,R4-R7,PC} // return + + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_1: + DC32 _tx_trace_buffer_current_ptr + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_2: + DC32 _tx_trace_event_enable_bits + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_5: + DC32 _tx_trace_buffer_end_ptr + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_6: + DC32 _tx_trace_buffer_start_ptr + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_7: + DC32 _tx_trace_header_ptr + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_8: + DC32 _tx_trace_full_notify_function + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_time_stamp_get: + MOVS R0,#+0 + BX LR // return + +#endif + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2: + DC32 0x54485244 + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_3: + DC32 _tx_thread_system_state + + SECTION `.text`:CODE:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA +??DataTable2_4: + DC32 _tx_thread_current_ptr + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_always_true: + MOVS R0,#+1 + BX LR // return + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_status_get: + MOVS R0,#+0 + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_ipsr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_ipsr_get: + MRS R0, IPSR + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_control_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_control_get: + MRS R0, CONTROL + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_control_set(ULONG value); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_control_set: + MSR CONTROL, R0 + BX LR // return + + +#ifdef __ARMVFP__ + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** ULONG _tx_misra_fpccr_get(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + SECTION `.text`:CODE:NOROOT(2) + THUMB +_tx_misra_fpccr_get: + LDR r0, =0xE000EF34 // Build FPCCR address + LDR r0, [r0] // Load FPCCR value + BX LR // return + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** void _tx_misra_vfp_touch(void); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ + + SECTION `.text`:CODE:NOROOT(1) + THUMB +_tx_misra_vfp_touch: + vmov.f32 s0, s0 + BX LR // return + +#endif + + + SECTION `.iar_vfe_header`:DATA:NOALLOC:NOROOT(2) + SECTION_TYPE SHT_PROGBITS, 0 + DATA + DC32 0 + + END diff --git a/ports/cortex_m3/iar/src/tx_thread_context_restore.s b/ports/cortex_m3/iar/src/tx_thread_context_restore.s new file mode 100644 index 0000000..35aeaf5 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_context_restore.s @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + EXTERN _tx_execution_isr_exit + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_exit] Execution profiling ISR exit */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_restore(VOID) +// { + PUBLIC _tx_thread_context_restore +_tx_thread_context_restore: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR exit function to indicate an ISR is complete. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_exit // Call the ISR exit function + POP {r0, lr} // Recover return address +#endif + + BX lr +// } + END diff --git a/ports/cortex_m3/iar/src/tx_thread_context_save.s b/ports/cortex_m3/iar/src/tx_thread_context_save.s new file mode 100644 index 0000000..f8bf503 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_context_save.s @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + EXTERN _tx_execution_isr_enter + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_save Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is only needed for legacy applications and it should */ +/* not be called in any new development on a Cortex-M. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_tx_execution_isr_enter] Execution profiling ISR enter */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_context_save(VOID) +// { + PUBLIC _tx_thread_context_save +_tx_thread_context_save: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the ISR enter function to indicate an ISR is starting. */ + PUSH {r0, lr} // Save return address + BL _tx_execution_isr_enter // Call the ISR enter function + POP {r0, lr} // Recover return address +#endif + + /* Context is already saved - just return. */ + + BX lr +// } + END diff --git a/ports/cortex_m3/iar/src/tx_thread_interrupt_control.s b/ports/cortex_m3/iar/src/tx_thread_interrupt_control.s new file mode 100644 index 0000000..a0f3a5d --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_interrupt_control.s @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_control(UINT new_posture) +// { + PUBLIC _tx_thread_interrupt_control +_tx_thread_interrupt_control: +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Pickup current interrupt posture + MSR BASEPRI, r0 // Apply the new interrupt posture + MOV r0, r1 // Transfer old to return register +#else + MRS r1, PRIMASK // Pickup current interrupt lockout + MSR PRIMASK, r0 // Apply the new interrupt lockout + MOV r0, r1 // Transfer old to return register +#endif + BX lr // Return to caller +// } + END diff --git a/ports/cortex_m3/iar/src/tx_thread_interrupt_disable.s b/ports/cortex_m3/iar/src/tx_thread_interrupt_disable.s new file mode 100644 index 0000000..999af96 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_interrupt_disable.s @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_disable Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for disabling interrupts and returning */ +/* the previous interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// UINT _tx_thread_interrupt_disable(VOID) +// { + PUBLIC _tx_thread_interrupt_disable +_tx_thread_interrupt_disable: + /* Return current interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MRS r0, BASEPRI + LDR r1, =TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + MRS r0, PRIMASK + CPSID i +#endif + BX lr +// } + END diff --git a/ports/cortex_m3/iar/src/tx_thread_interrupt_restore.s b/ports/cortex_m3/iar/src/tx_thread_interrupt_restore.s new file mode 100644 index 0000000..2e55ed2 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_interrupt_restore.s @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_restore Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for restoring the previous */ +/* interrupt lockout posture. */ +/* */ +/* INPUT */ +/* */ +/* previous_posture Previous interrupt posture */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_interrupt_restore(UINT previous_posture) +// { + PUBLIC _tx_thread_interrupt_restore +_tx_thread_interrupt_restore: + /* Restore previous interrupt lockout posture. */ +#ifdef TX_PORT_USE_BASEPRI + MSR BASEPRI, r0 +#else + MSR PRIMASK, r0 +#endif + BX lr +// } + END diff --git a/ports/cortex_m3/iar/src/tx_thread_schedule.s b/ports/cortex_m3/iar/src/tx_thread_schedule.s new file mode 100644 index 0000000..882d201 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_schedule.s @@ -0,0 +1,323 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + EXTERN _tx_thread_current_ptr + EXTERN _tx_thread_execute_ptr + EXTERN _tx_timer_time_slice + EXTERN _tx_thread_preempt_disable + EXTERN _tx_execution_thread_enter + EXTERN _tx_execution_thread_exit +#ifdef TX_LOW_POWER + EXTERN tx_low_power_enter + EXTERN tx_low_power_exit +#endif + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* _tx_thread_system_return Return to system from thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 04-25-2022 Scott Larson Added BASEPRI support, */ +/* resulting in version 6.1.11 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_schedule(VOID) +// { + PUBLIC _tx_thread_schedule +_tx_thread_schedule: + + /* This function should only ever be called on Cortex-M + from the first schedule request. Subsequent scheduling occurs + from the PendSV handling routine below. */ + + /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */ + + MOV r0, #0 // Build value for TX_FALSE + LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag + STR r0, [r2, #0] // Clear preempt disable flag + + /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ + +#ifdef __ARMVFP__ + MRS r0, CONTROL // Pickup current CONTROL register + BIC r0, r0, #4 // Clear the FPCA bit + MSR CONTROL, r0 // Setup new CONTROL register +#endif + + /* Enable interrupts */ + CPSIE i + + /* Enter the scheduler for the first time. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + DSB // Complete all memory accesses + ISB // Flush pipeline + + /* Wait here for the PendSV to take place. */ + +__tx_wait_here: + B __tx_wait_here // Wait for the PendSV to happen +// } + + /* Generic context switching PendSV handler. */ + + PUBLIC PendSV_Handler + PUBLIC __tx_PendSVHandler +PendSV_Handler: +__tx_PendSVHandler: + + /* Get current thread value and new thread pointer. */ + +__tx_ts_handler: + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread exit function to indicate the thread is no longer executing. */ +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif /* TX_PORT_USE_BASEPRI */ + PUSH {r0, lr} // Save LR (and r0 just for alignment) + BL _tx_execution_thread_exit // Call the thread exit function + POP {r0, lr} // Recover LR +#ifdef TX_PORT_USE_BASEPRI + MOV r0, 0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r0 +#else + CPSIE i // Enable interrupts +#endif /* TX_PORT_USE_BASEPRI */ +#endif /* EXECUTION PROFILE */ + + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + MOV r3, #0 // Build NULL value + LDR r1, [r0] // Pickup current thread pointer + + /* Determine if there is a current thread to finish preserving. */ + + CBZ r1, __tx_ts_new // If NULL, skip preservation + + /* Recover PSP and preserve current thread context. */ + + STR r3, [r0] // Set _tx_thread_current_ptr to NULL + MRS r12, PSP // Pickup PSP pointer (thread's stack pointer) + STMDB r12!, {r4-r11} // Save its remaining registers +#ifdef __ARMVFP__ + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_save + VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers +_skip_vfp_save: +#endif + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + STMDB r12!, {LR} // Save LR on the stack + + /* Determine if time-slice is active. If it isn't, skip time handling processing. */ + + LDR r5, [r4] // Pickup current time-slice + STR r12, [r1, #8] // Save the thread stack pointer + CBZ r5, __tx_ts_new // If not active, skip processing + + /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */ + + STR r5, [r1, #24] // Save current time-slice + + /* Clear the global time-slice. */ + + STR r3, [r4] // Clear time-slice + + /* Executing thread is now completely preserved!!! */ + +__tx_ts_new: + + /* Now we are looking for a new thread to execute! */ + +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Is there another thread ready to execute? + CBZ r1, __tx_ts_wait // No, skip to the wait processing + + /* Yes, another thread is ready for else, make the current thread the new thread. */ + + STR r1, [r0] // Setup the current thread pointer to the new thread +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + + /* Increment the thread run count. */ + +__tx_ts_restore: + LDR r7, [r1, #4] // Pickup the current thread run count + LDR r4, =_tx_timer_time_slice // Build address of time-slice variable + LDR r5, [r1, #24] // Pickup thread's current time-slice + ADD r7, r7, #1 // Increment the thread run count + STR r7, [r1, #4] // Store the new run count + + /* Setup global time-slice with thread's current time-slice. */ + + STR r5, [r4] // Setup global time-slice + +#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE)) + /* Call the thread entry function to indicate the thread is executing. */ + PUSH {r0, r1} // Save r0 and r1 + BL _tx_execution_thread_enter // Call the thread execution enter function + POP {r0, r1} // Recover r0 and r1 +#endif + + /* Restore the thread context and PSP. */ + + LDR r12, [r1, #8] // Pickup thread's stack pointer + LDMIA r12!, {LR} // Pickup LR +#ifdef __ARMVFP__ + TST LR, #0x10 // Determine if the VFP extended frame is present + BNE _skip_vfp_restore // If not, skip VFP restore + VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers +_skip_vfp_restore: +#endif + LDMIA r12!, {r4-r11} // Recover thread's registers + MSR PSP, r12 // Setup the thread's stack pointer + + /* Return to thread. */ + + BX lr // Return to thread! + + /* The following is the idle wait processing... in this case, no threads are ready for execution and the + system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts + are disabled to allow use of WFI for waiting for a thread to arrive. */ + +__tx_ts_wait: +#ifdef TX_PORT_USE_BASEPRI + LDR r1, =TX_PORT_BASEPRI // Mask interrupt priorities =< TX_PORT_BASEPRI + MSR BASEPRI, r1 +#else + CPSID i // Disable interrupts +#endif + LDR r1, [r2] // Pickup the next thread to execute pointer + STR r1, [r0] // Store it in the current pointer + CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready! + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_enter // Possibly enter low power mode + POP {r0-r3} +#endif + +#ifdef TX_ENABLE_WFI + DSB // Ensure no outstanding memory transactions + WFI // Wait for interrupt + ISB // Ensure pipeline is flushed +#endif + +#ifdef TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_exit // Exit low power mode + POP {r0-r3} +#endif + +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_wait // Loop to continue waiting + + /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are + already in the handler! */ + +__tx_ts_ready: + MOV r7, #0x08000000 // Build clear PendSV value + MOV r8, #0xE000E000 // Build base NVIC address + STR r7, [r8, #0xD04] // Clear any PendSV + + /* Re-enable interrupts and restore new thread. */ +#ifdef TX_PORT_USE_BASEPRI + MOV r4, #0 // Disable BASEPRI masking (enable interrupts) + MSR BASEPRI, r4 +#else + CPSIE i // Enable interrupts +#endif + B __tx_ts_restore // Restore the thread +// } + +#ifdef __ARMVFP__ + + PUBLIC tx_thread_fpu_enable +tx_thread_fpu_enable: + PUBLIC tx_thread_fpu_disable +tx_thread_fpu_disable: + + /* Automatic VPF logic is supported, this function is present only for + backward compatibility purposes and therefore simply returns. */ + + BX LR // Return to caller + +#endif + END diff --git a/ports/cortex_m3/iar/src/tx_thread_stack_build.s b/ports/cortex_m3/iar/src/tx_thread_stack_build.s new file mode 100644 index 0000000..116ba71 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_stack_build.s @@ -0,0 +1,137 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +// { + PUBLIC _tx_thread_stack_build +_tx_thread_stack_build: + + /* Build a fake interrupt frame. The form of the fake interrupt stack + on the Cortex-M should look like the following after it is built: + + Stack Top: + LR Interrupted LR (LR at time of PENDSV) + r4 Initial value for r4 + r5 Initial value for r5 + r6 Initial value for r6 + r7 Initial value for r7 + r8 Initial value for r8 + r9 Initial value for r9 + r10 Initial value for r10 + r11 Initial value for r11 + r0 Initial value for r0 (Hardware stack starts here!!) + r1 Initial value for r1 + r2 Initial value for r2 + r3 Initial value for r3 + r12 Initial value for r12 + lr Initial value for lr + pc Initial value for pc + xPSR Initial value for xPSR + + Stack Bottom: (higher memory address) */ + + LDR r2, [r0, #16] // Pickup end of stack area + BIC r2, r2, #0x7 // Align frame for 8-byte alignment + SUB r2, r2, #68 // Subtract frame size + LDR r3, =0xFFFFFFFD // Build initial LR value + STR r3, [r2, #0] // Save on the stack + + /* Actually build the stack frame. */ + + MOV r3, #0 // Build initial register value + STR r3, [r2, #4] // Store initial r4 + STR r3, [r2, #8] // Store initial r5 + STR r3, [r2, #12] // Store initial r6 + STR r3, [r2, #16] // Store initial r7 + STR r3, [r2, #20] // Store initial r8 + STR r3, [r2, #24] // Store initial r9 + STR r3, [r2, #28] // Store initial r10 + STR r3, [r2, #32] // Store initial r11 + + /* Hardware stack follows. */ + + STR r3, [r2, #36] // Store initial r0 + STR r3, [r2, #40] // Store initial r1 + STR r3, [r2, #44] // Store initial r2 + STR r3, [r2, #48] // Store initial r3 + STR r3, [r2, #52] // Store initial r12 + MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value + STR r3, [r2, #56] // Store initial lr + STR r1, [r2, #60] // Store initial pc + MOV r3, #0x01000000 // Only T-bit need be set + STR r3, [r2, #64] // Store initial xPSR + + /* Setup stack pointer. */ + // thread_ptr -> tx_thread_stack_ptr = r2; + + STR r2, [r0, #8] // Save stack pointer in thread's + // control block + BX lr // Return to caller +// } + END diff --git a/ports/cortex_m3/iar/src/tx_thread_system_return.s b/ports/cortex_m3/iar/src/tx_thread_system_return.s new file mode 100644 index 0000000..a19bd35 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_thread_system_return.s @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the ThreadX system. Only a */ +/* minimal context is saved since the compiler assumes temp registers */ +/* are going to get slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_thread_system_return(VOID) +// { + PUBLIC _tx_thread_system_return +_tx_thread_system_return: + + /* Return to real scheduler via PendSV. Note that this routine is often + replaced with in-line assembly in tx_port.h to improved performance. */ + + MOV r0, #0x10000000 // Load PENDSVSET bit + MOV r1, #0xE000E000 // Load NVIC base + STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR + MRS r0, IPSR // Pickup IPSR + CMP r0, #0 // Is it a thread returning? + BNE _isr_context // If ISR, skip interrupt enable +#ifdef TX_PORT_USE_BASEPRI + MRS r1, BASEPRI // Thread context returning, pickup BASEPRI + MOV r0, #0 + MSR BASEPRI, r0 // Enable interrupts + MSR BASEPRI, r1 // Restore original interrupt posture +#else + MRS r1, PRIMASK // Thread context returning, pickup PRIMASK + CPSIE i // Enable interrupts + MSR PRIMASK, r1 // Restore original interrupt posture +#endif +_isr_context: + BX lr // Return to caller +// } + END diff --git a/ports/cortex_m3/iar/src/tx_timer_interrupt.s b/ports/cortex_m3/iar/src/tx_timer_interrupt.s new file mode 100644 index 0000000..a2d8ca3 --- /dev/null +++ b/ports/cortex_m3/iar/src/tx_timer_interrupt.s @@ -0,0 +1,262 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE +#include "tx_user.h" +#endif + + EXTERN _tx_timer_time_slice + EXTERN _tx_timer_system_clock + EXTERN _tx_timer_current_ptr + EXTERN _tx_timer_list_start + EXTERN _tx_timer_list_end + EXTERN _tx_timer_expired_time_slice + EXTERN _tx_timer_expired + EXTERN _tx_thread_time_slice + EXTERN _tx_timer_expiration_process + EXTERN _tx_thread_current_ptr + EXTERN _tx_thread_execute_ptr + EXTERN _tx_thread_preempt_disable + + SECTION `.text`:CODE:NOROOT(2) + THUMB +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Cortex-M3/IAR */ +/* 6.3.0 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* expiration functions are called. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comment(s), added */ +/* TX_NO_TIMER support, */ +/* resulting in version 6.1.10 */ +/* 10-31-2023 Tiejun Zhou Included tx_user.h, */ +/* resulting in version 6.3.0 */ +/* */ +/**************************************************************************/ +// VOID _tx_timer_interrupt(VOID) +// { +#ifndef TX_NO_TIMER + PUBLIC _tx_timer_interrupt +_tx_timer_interrupt: + + /* Upon entry to this routine, it is assumed that the compiler scratch registers are available + for use. */ + + /* Increment the system clock. */ + // _tx_timer_system_clock++; + + LDR r1, =_tx_timer_system_clock // Pickup address of system clock + LDR r0, [r1, #0] // Pickup system clock + ADD r0, r0, #1 // Increment system clock + STR r0, [r1, #0] // Store new system clock + + /* Test for time-slice expiration. */ + // if (_tx_timer_time_slice) + // { + + LDR r3, =_tx_timer_time_slice // Pickup address of time-slice + LDR r2, [r3, #0] // Pickup time-slice + CBZ r2, __tx_timer_no_time_slice // Is it non-active? + // Yes, skip time-slice processing + + /* Decrement the time_slice. */ + // _tx_timer_time_slice--; + + SUB r2, r2, #1 // Decrement the time-slice + STR r2, [r3, #0] // Store new time-slice value + + /* Check for expiration. */ + // if (__tx_timer_time_slice == 0) + + CBNZ r2, __tx_timer_no_time_slice // Has it expired? + // No, skip expiration processing + + /* Set the time-slice expired flag. */ + // _tx_timer_expired_time_slice = TX_TRUE; + + LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag + MOV r0, #1 // Build expired value + STR r0, [r3, #0] // Set time-slice expiration flag + + // } + +__tx_timer_no_time_slice: + + /* Test for timer expiration. */ + // if (*_tx_timer_current_ptr) + // { + + LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address + LDR r0, [r1, #0] // Pickup current timer + LDR r2, [r0, #0] // Pickup timer list entry + CBZ r2, __tx_timer_no_timer // Is there anything in the list? + // No, just increment the timer + + /* Set expiration flag. */ + // _tx_timer_expired = TX_TRUE; + + LDR r3, =_tx_timer_expired // Pickup expiration flag address + MOV r2, #1 // Build expired value + STR r2, [r3, #0] // Set expired flag + B __tx_timer_done // Finished timer processing + + // } + // else + // { +__tx_timer_no_timer: + + /* No timer expired, increment the timer pointer. */ + // _tx_timer_current_ptr++; + + ADD r0, r0, #4 // Move to next timer + + /* Check for wrap-around. */ + // if (_tx_timer_current_ptr == _tx_timer_list_end) + + LDR r3, =_tx_timer_list_end // Pickup addr of timer list end + LDR r2, [r3, #0] // Pickup list end + CMP r0, r2 // Are we at list end? + BNE __tx_timer_skip_wrap // No, skip wrap-around logic + + /* Wrap to beginning of list. */ + // _tx_timer_current_ptr = _tx_timer_list_start; + + LDR r3, =_tx_timer_list_start // Pickup addr of timer list start + LDR r0, [r3, #0] // Set current pointer to list start + +__tx_timer_skip_wrap: + + STR r0, [r1, #0] // Store new current timer pointer + // } + +__tx_timer_done: + + /* See if anything has expired. */ + // if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag + LDR r2, [r3, #0] // Pickup time-slice expired flag + CBNZ r2, __tx_something_expired // Did a time-slice expire? + // If non-zero, time-slice expired + LDR r1, =_tx_timer_expired // Pickup addr of other expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired // Did a timer expire? + // No, nothing expired + +__tx_something_expired: + + STMDB sp!, {r0, lr} // Save the lr register on the stack + // and save r0 just to keep 8-byte alignment + + /* Did a timer expire? */ + // if (_tx_timer_expired) + // { + + LDR r1, =_tx_timer_expired // Pickup addr of expired flag + LDR r0, [r1, #0] // Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate // Check for timer expiration + // If not set, skip timer activation + + /* Process timer expiration. */ + // _tx_timer_expiration_process(); + + BL _tx_timer_expiration_process // Call the timer expiration handling routine + + // } +__tx_timer_dont_activate: + + /* Did time slice expire? */ + // if (_tx_timer_expired_time_slice) + // { + + LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired + LDR r2, [r3, #0] // Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set + // No, skip time-slice processing + + /* Time slice interrupted thread. */ + // _tx_thread_time_slice(); + + BL _tx_thread_time_slice // Call time-slice processing + LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag + LDR r1, [r0] // Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic + LDR r0, =_tx_thread_current_ptr // Build current thread pointer address + LDR r1, [r0] // Pickup the current thread pointer + LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address + LDR r3, [r2] // Pickup the execute thread pointer + LDR r0, =0xE000ED04 // Build address of control register + LDR r2, =0x10000000 // Build value for PendSV bit + CMP r1, r3 // Are they the same? + BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed + STR r2, [r0] // Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice: + + // } + +__tx_timer_not_ts_expiration: + + LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for + // the 8-byte stack alignment + + // } + +__tx_timer_nothing_expired: + + DSB // Complete all memory access + BX lr // Return to caller +// } +#endif + END diff --git a/ports/cortex_m3/keil/inc/tx_port.h b/ports/cortex_m3/keil/inc/tx_port.h new file mode 100644 index 0000000..04e83be --- /dev/null +++ b/ports/cortex_m3/keil/inc/tx_port.h @@ -0,0 +1,728 @@ +/*************************************************************************** + * Copyright (c) 2024 Microsoft Corporation + * + * 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 + **************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/Keil */ +/* 6.1.12 */ +/* */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the ThreadX */ +/* real-time kernel function identically on a variety of different */ +/* processor architectures. For example, the size or number of bits */ +/* in an "int" data type vary between microprocessor architectures and */ +/* even C compilers for the same microprocessor. ThreadX does not */ +/* directly use native C data types. Instead, ThreadX creates its */ +/* own special types that can be mapped to actual data types by this */ +/* file to guarantee consistency in the interface and functionality. */ +/* */ +/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */ +/* the ARMv7-M architecture and compilers into one common file. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 06-02-2021 Scott Larson Initial Version 6.1.7 */ +/* 01-31-2022 Scott Larson Modified comments, updated */ +/* typedef to fix misra */ +/* violation, */ +/* fixed predefined macro, */ +/* resulting in version 6.1.10 */ +/* 04-25-2022 Scott Larson Modified comments and added */ +/* volatile to registers, */ +/* resulting in version 6.1.11 */ +/* 07-29-2022 Scott Larson Modified comments and */ +/* described BASEPRI usage, */ +/* resulting in version 6.1.12 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +/* Determine if the optional ThreadX user define file should be used. */ + +#ifdef TX_INCLUDE_USER_DEFINE_FILE + +/* Yes, include the user defines in tx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "tx_user.h" +#endif + + +/* Define compiler library include files. */ + +#include +#include + +#ifdef __ICCARM__ +#include /* IAR Intrinsics */ +#define __asm__ __asm /* Define to make all inline asm look similar */ +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#include +#endif +#endif /* __ICCARM__ */ + +#ifdef __ghs__ +#include +#include "tx_ghs.h" +#endif /* __ghs__ */ + + +#if !defined(__GNUC__) && !defined(__CC_ARM) +#define __get_control_value __get_CONTROL +#define __set_control_value __set_CONTROL +#endif + +#ifndef __GNUC__ +#define __get_ipsr_value __get_IPSR +#endif + +/* Define ThreadX basic types for this port. */ + +#define VOID void +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long long ULONG64; +typedef short SHORT; +typedef unsigned short USHORT; +#define ULONG64_DEFINED + +/* Define the priority levels for ThreadX. Legal values range + from 32 to 1024 and MUST be evenly divisible by 32. */ + +#ifndef TX_MAX_PRIORITIES +#define TX_MAX_PRIORITIES 32 +#endif + + +/* Define the minimum stack for a ThreadX thread on this processor. If the size supplied during + thread creation is less than this value, the thread create call will return an error. */ + +#ifndef TX_MINIMUM_STACK +#define TX_MINIMUM_STACK 200 /* Minimum stack size for this port */ +#endif + + +/* Define the system timer thread's default stack size and priority. These are only applicable + if TX_TIMER_PROCESS_IN_ISR is not defined. */ + +#ifndef TX_TIMER_THREAD_STACK_SIZE +#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + +/* By default, ThreadX for Cortex-M uses the PRIMASK register to enable/disable interrupts. +If using BASEPRI is desired, define the following two symbols for both c and assembly files: +TX_PORT_USE_BASEPRI - This tells ThreadX to use BASEPRI instead of PRIMASK. +TX_PORT_BASEPRI = (priority_mask << (8 - number_priority_bits)) - this defines the maximum priority level to mask. +Any interrupt with a higher priority than priority_mask will not be masked, thus the interrupt will run. +*/ + +/* Define various constants for the ThreadX Cortex-M port. */ + +#define TX_INT_DISABLE 1 /* Disable interrupts */ +#define TX_INT_ENABLE 0 /* Enable interrupts */ + + +/* Define the clock source for trace event entry time stamp. The following two item are port specific. + For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock + source constants would be: + +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0x0a800024) +#define TX_TRACE_TIME_MASK 0x0000FFFFUL + +*/ + +#ifndef TX_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((volatile ULONG *) 0xE0001004) +#endif +#else +ULONG _tx_misra_time_stamp_get(VOID); +#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get() +#endif + +#ifndef TX_TRACE_TIME_MASK +#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL +#endif + +#ifdef __ghs__ +/* Define constants for Green Hills EventAnalyzer. */ + +/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps + represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */ + +#define TX_EL_TICKS_PER_SECOND 1000000 + +/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply + simulate the time-stamp source with a counter. */ + +#define read_tbu() _tx_el_time_base_upper +#define read_tbl() ++_tx_el_time_base_lower +#endif /* __ghs__ */ + +/* Define the port specific options for the _tx_build_options variable. This variable indicates + how the ThreadX library was built. */ + +#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0) + + +/* Define the in-line initialization constant so that modules with in-line + initialization capabilities can prevent their initialization from being + a function call. */ + +#ifdef TX_MISRA_ENABLE +#define TX_DISABLE_INLINE +#else +#define TX_INLINE_INITIALIZATION +#endif + + +/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is + disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack + checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING + define is negated, thereby forcing the stack fill which is necessary for the stack checking + logic. */ + +#ifndef TX_MISRA_ENABLE +#ifdef TX_ENABLE_STACK_CHECKING +#undef TX_DISABLE_STACK_FILLING +#endif +#endif + + +/* Define the TX_THREAD control block extensions for this port. The main reason + for the multiple macros is so that backward compatibility can be maintained with + existing ThreadX kernel awareness modules. */ + +#define TX_THREAD_EXTENSION_0 +#define TX_THREAD_EXTENSION_1 +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer; +#elif defined(__ghs__) +#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \ + int Errno; /* errno. */ \ + char * strtok_saved_pos; /* strtok() position. */ +#else +#define TX_THREAD_EXTENSION_2 +#endif + + +#define TX_THREAD_EXTENSION_3 + + + +/* Define the port extensions of the remaining ThreadX objects. */ + +#define TX_BLOCK_POOL_EXTENSION +#define TX_BYTE_POOL_EXTENSION +#define TX_EVENT_FLAGS_GROUP_EXTENSION +#define TX_MUTEX_EXTENSION +#define TX_QUEUE_EXTENSION +#define TX_SEMAPHORE_EXTENSION +#define TX_TIMER_EXTENSION + + +/* Define the user extension field of the thread control block. Nothing + additional is needed for this port so it is defined as white space. */ + +#ifndef TX_THREAD_USER_EXTENSION +#define TX_THREAD_USER_EXTENSION +#endif + + +/* Define the macros for processing extensions in tx_thread_create, tx_thread_delete, + tx_thread_shell_entry, and tx_thread_terminate. */ + + +#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT +#if (__VER__ < 8000000) +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0); +#else +void *_tx_iar_create_per_thread_tls_area(void); +void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr); +void __iar_Initlocks(void); + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area(); +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \ + thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0); +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0); +#endif +#else +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#endif + +#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) + +#ifdef TX_MISRA_ENABLE + +ULONG _tx_misra_control_get(void); +void _tx_misra_control_set(ULONG value); +ULONG _tx_misra_fpccr_get(void); +void _tx_misra_vfp_touch(void); + +#else /* TX_MISRA_ENABLE not defined */ + +/* Define some helper functions (these are intrinsics in some compilers). */ +#ifdef __GNUC__ /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + +__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value) +{ + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); + +#elif defined(__CC_ARM) /* ARM Compiler 5 */ + +__attribute__( ( always_inline ) ) ULONG __get_control_value(void) +{ +ULONG control_value; + + __asm volatile ("MRS control_value,CONTROL"); + return(control_value); +} + +__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value) +{ + __asm__ volatile ("MSR CONTROL,control_value"); +} +/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */ +void _tx_vfp_access(void); +#define TX_VFP_TOUCH() _tx_vfp_access(); + +#elif defined(__ICCARM__) /* IAR */ +#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0"); +#endif /* Helper functions for different compilers */ + +#endif /* TX_MISRA_ENABLE */ + + +/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA + in order to ensure no lazy stacking will occur. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } +#else + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } + +#endif + +/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR. + If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating + this one, so if the FPCCR.LSPACT bit is set, we need to save the CONTROL.FPCA state, touch the FPU to flush + the lazy FPU save, then restore the CONTROL.FPCA state. */ + +#ifndef TX_MISRA_ENABLE + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((volatile ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + TX_VFP_TOUCH(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control_value(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control_value(_tx_vfp_state); \ + } \ + } \ + } \ + } +#else + +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \ + ULONG _tx_system_state; \ + _tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \ + if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = _tx_misra_fpccr_get(); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + _tx_misra_vfp_touch(); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = _tx_misra_control_get(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + _tx_misra_control_set(_tx_vfp_state); \ + } \ + } \ + } \ + } +#endif + +#else /* No VFP in use */ + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__ARM_FP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */ + + +/* Define the ThreadX object creation extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_CREATE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_CREATE_EXTENSION(group_ptr) +#define TX_MUTEX_CREATE_EXTENSION(mutex_ptr) +#define TX_QUEUE_CREATE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_CREATE_EXTENSION(semaphore_ptr) +#define TX_TIMER_CREATE_EXTENSION(timer_ptr) + + +/* Define the ThreadX object deletion extensions for the remaining objects. */ + +#define TX_BLOCK_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_BYTE_POOL_DELETE_EXTENSION(pool_ptr) +#define TX_EVENT_FLAGS_GROUP_DELETE_EXTENSION(group_ptr) +#define TX_MUTEX_DELETE_EXTENSION(mutex_ptr) +#define TX_QUEUE_DELETE_EXTENSION(queue_ptr) +#define TX_SEMAPHORE_DELETE_EXTENSION(semaphore_ptr) +#define TX_TIMER_DELETE_EXTENSION(timer_ptr) + + +/* Define the get system state macro. */ + +#ifndef TX_THREAD_GET_SYSTEM_STATE +#ifndef TX_MISRA_ENABLE + +#ifdef __CC_ARM /* ARM Compiler 5 */ + +register unsigned int _ipsr __asm("ipsr"); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr) + +#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void) +{ +unsigned int ipsr_value; + __asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) ); + return(ipsr_value); +} + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value()) + +#elif defined(__ICCARM__) /* IAR */ + +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR()) + +#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */ + +#else /* TX_MISRA_ENABLE is defined, use MISRA function. */ +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif /* TX_MISRA_ENABLE */ +#endif /* TX_THREAD_GET_SYSTEM_STATE */ + + +/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value + indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h + for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always + zero after initialization for Cortex-M ports. */ + +#ifndef TX_THREAD_SYSTEM_RETURN_CHECK +#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable); +#endif + +/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to + prevent early scheduling on Cortex-M parts. */ + +#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++; + + + + +#ifndef TX_DISABLE_INLINE + +/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */ +#ifdef __ICCARM__ /* IAR Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m))); +#elif defined(__CC_ARM) /* AC5 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m))); +#elif defined(__GNUC__) /* GCC and AC6 Compiler */ +#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); +#endif + + + +/* Define the interrupt disable/restore macros for each compiler. */ + +#if defined(__GNUC__) || defined(__ICCARM__) + +/*** GCC/AC6 and IAR ***/ + +__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture)); +#else + __asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture)); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +__attribute__( ( always_inline ) ) static inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value)); +} +#else +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + __asm__ volatile ("CPSIE i": : : "memory"); +} +#endif + +__attribute__( ( always_inline ) ) static inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); + //__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory"); +#else + __asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory"); +#endif +} + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i" : : : "memory"); +#endif + return(int_posture); +} + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_interrupt_posture(); +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(0); +#else + __enable_interrupts(); +#endif + __restore_interrupt(interrupt_save); + } +} + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End GCC/AC6 and IAR ***/ + +#elif defined(__CC_ARM) + +/*** AC5 ***/ + +static __inline unsigned int __get_interrupt_posture(void) +{ +unsigned int posture; +#ifdef TX_PORT_USE_BASEPRI + __asm__ volatile ("MRS #posture, BASEPRI"); +#else + __asm__ volatile ("MRS #posture, PRIMASK"); +#endif + return(posture); +} + +#ifdef TX_PORT_USE_BASEPRI +static __inline void __set_basepri_value(unsigned int basepri_value) +{ + __asm__ volatile ("MSR BASEPRI, #basepri_value"); +} +#endif + +static __inline unsigned int __disable_interrupts(void) +{ +unsigned int int_posture; + + int_posture = __get_interrupt_posture(); + +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(TX_PORT_BASEPRI); +#else + __asm__ volatile ("CPSID i"); +#endif + return(int_posture); +} + +static __inline void __restore_interrupt(unsigned int int_posture) +{ +#ifdef TX_PORT_USE_BASEPRI + __set_basepri_value(int_posture); +#else + __asm__ volatile ("MSR PRIMASK, #int_posture"); +#endif +} + +static void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + /* Set PendSV to invoke ThreadX scheduler. */ + *((volatile ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (_ipsr == 0) + { +#ifdef TX_PORT_USE_BASEPRI + interrupt_save = __get_interrupt_posture(); + __set_basepri_value(0); + __set_basepri_value(interrupt_save); +#else + interrupt_save = __disable_irq(); + __enable_irq(); + if (interrupt_save != 0) + __disable_irq(); +#endif + } +} + + +#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save; +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupt(interrupt_save); + +/*** End AC5 ***/ + +#endif /* Interrupt disable/restore macros for each compiler. */ + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else /* TX_DISABLE_INLINE is defined */ + +UINT _tx_thread_interrupt_disable(VOID); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable(); +#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save); +#endif /* TX_DISABLE_INLINE */ + + +/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing + thread. These are no longer needed, but are preserved for backward compatibility only. */ + +void tx_thread_fpu_enable(void); +void tx_thread_fpu_disable(void); + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) 2024 Microsoft Corporation. * ThreadX Cortex-M3/Keil Version 6.4.2 *"; +#else +#ifdef TX_MISRA_ENABLE +extern CHAR _tx_version_id[100]; +#else +extern CHAR _tx_version_id[]; +#endif +#endif + + +#endif diff --git a/ports/cortex_m3/keil/src/tx_thread_context_restore.s b/ports/cortex_m3/keil/src/tx_thread_context_restore.s new file mode 100644 index 0000000..c7cd720 --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_context_restore.s @@ -0,0 +1,90 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_isr_exit + ENDIF +; +; + AREA ||.text||, CODE, READONLY + PRESERVE8 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_restore Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is only needed for legacy applications and it should */ +;/* not be called in any new development on a Cortex-M. */ +;/* This function restores the interrupt context if it is processing a */ +;/* nested interrupt. If not, it returns to the interrupt thread if no */ +;/* preemption is necessary. Otherwise, if preemption is necessary or */ +;/* if no thread was running, the function returns to the scheduler. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling routine */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs Interrupt Service Routines */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_restore(VOID) +;{ + EXPORT _tx_thread_context_restore +_tx_thread_context_restore + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the ISR exit function to indicate an ISR is complete. */ +; + PUSH {r0,lr} ; Save ISR lr + BL _tx_execution_isr_exit ; Call the ISR exit function + POP {r0,lr} ; Restore ISR lr + ENDIF +; + POP {lr} + BX lr +;} + ALIGN + LTORG + END diff --git a/ports/cortex_m3/keil/src/tx_thread_context_save.s b/ports/cortex_m3/keil/src/tx_thread_context_save.s new file mode 100644 index 0000000..e6fe47c --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_context_save.s @@ -0,0 +1,90 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_isr_enter + ENDIF +; +; + AREA ||.text||, CODE, READONLY + PRESERVE8 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_context_save Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is only needed for legacy applications and it should */ +;/* not be called in any new development on a Cortex-M. */ +;/* This function saves the context of an executing thread in the */ +;/* beginning of interrupt processing. The function also ensures that */ +;/* the system stack is used upon return to the calling ISR. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ISRs */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_context_save(VOID) +;{ + EXPORT _tx_thread_context_save +_tx_thread_context_save + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the ISR enter function to indicate an ISR is executing. */ +; + PUSH {r0, lr} ; Save ISR lr + BL _tx_execution_isr_enter ; Call the ISR enter function + POP {r0, lr} ; Recover ISR lr + ENDIF +; +; /* Return to interrupt processing. */ +; + BX lr ; Return to interrupt processing caller +;} + ALIGN + LTORG + END diff --git a/ports/cortex_m3/keil/src/tx_thread_interrupt_control.s b/ports/cortex_m3/keil/src/tx_thread_interrupt_control.s new file mode 100644 index 0000000..2d7fa49 --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_interrupt_control.s @@ -0,0 +1,75 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + AREA ||.text||, CODE, READONLY +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_control Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for changing the interrupt lockout */ +;/* posture of the system. */ +;/* */ +;/* INPUT */ +;/* */ +;/* new_posture New interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_control(UINT new_posture) +;{ + EXPORT _tx_thread_interrupt_control +_tx_thread_interrupt_control +; +; /* Pickup current interrupt lockout posture. */ +; + MRS r1, PRIMASK + MSR PRIMASK, r0 + MOV r0, r1 + BX lr +; +;} + END diff --git a/ports/cortex_m3/keil/src/tx_thread_interrupt_disable.s b/ports/cortex_m3/keil/src/tx_thread_interrupt_disable.s new file mode 100644 index 0000000..a63737a --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_interrupt_disable.s @@ -0,0 +1,74 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + AREA ||.text||, CODE, READONLY +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_disable Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for disabling interrupts and returning */ +;/* the previous interrupt lockout posture. */ +;/* */ +;/* INPUT */ +;/* */ +;/* old_posture Old interrupt lockout posture */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;UINT _tx_thread_interrupt_disable(UINT new_posture) +;{ + EXPORT _tx_thread_interrupt_disable +_tx_thread_interrupt_disable +; +; /* Return current interrupt lockout posture. */ +; + MRS r0, PRIMASK + CPSID i + BX lr +; +;} + END diff --git a/ports/cortex_m3/keil/src/tx_thread_interrupt_restore.s b/ports/cortex_m3/keil/src/tx_thread_interrupt_restore.s new file mode 100644 index 0000000..29ff36e --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_interrupt_restore.s @@ -0,0 +1,73 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + AREA ||.text||, CODE, READONLY +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_interrupt_restore Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is responsible for restoring the previous */ +;/* interrupt lockout posture. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* previous_posture Previous interrupt posture */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* Application Code */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_interrupt_restore(UINT new_posture) +;{ + EXPORT _tx_thread_interrupt_restore +_tx_thread_interrupt_restore +; +; /* Restore previous interrupt lockout posture. */ +; + MSR PRIMASK, r0 + BX lr +; +;} + END diff --git a/ports/cortex_m3/keil/src/tx_thread_schedule.s b/ports/cortex_m3/keil/src/tx_thread_schedule.s new file mode 100644 index 0000000..afaa308 --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_schedule.s @@ -0,0 +1,263 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_execute_ptr + IMPORT _tx_timer_time_slice + IMPORT _tx_thread_system_stack_ptr + IMPORT _tx_thread_preempt_disable + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY + IMPORT _tx_execution_thread_enter + IMPORT _tx_execution_thread_exit + ENDIF + IF :DEF:TX_LOW_POWER + IMPORT tx_low_power_enter + IMPORT tx_low_power_exit + ENDIF +; +; + AREA ||.text||, CODE, READONLY + PRESERVE8 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_schedule Cortex-M3/AC5 */ +;/* 6.1.5 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function waits for a thread control block pointer to appear in */ +;/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +;/* in the variable, the corresponding thread is resumed. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_initialize_kernel_enter ThreadX entry function */ +;/* _tx_thread_system_return Return to system from thread */ +;/* _tx_thread_context_restore Restore thread's context */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* 03-02-2021 Scott Larson Modified comment(s), add */ +;/* low power code, */ +;/* resulting in version 6.1.5 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_schedule(VOID) +;{ + EXPORT _tx_thread_schedule +_tx_thread_schedule +; +; /* This function should only ever be called on Cortex-M +; from the first schedule request. Subsequent scheduling occurs +; from the PendSV handling routines below. */ +; +; /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */ +; + MOV r0, #0 ; Build value for TX_FALSE + LDR r2, =_tx_thread_preempt_disable ; Build address of preempt disable flag + STR r0, [r2, #0] ; Clear preempt disable flag +; +; /* Enable the interrupts */ +; + CPSIE i +; +; /* Enter the scheduler for the first time. */ +; + MOV r0, #0x10000000 ; Load PENDSVSET bit + MOV r1, #0xE000E000 ; Load NVIC base + STR r0, [r1, #0xD04] ; Set PENDSVBIT in ICSR + DSB ; Complete all memory accesses + ISB ; Flush pipeline +; +; /* Wait here for the PendSV to take place. */ +; +__tx_wait_here + B __tx_wait_here ; Wait for the PendSV to happen +;} +; +; /* Generic context switching PendSV handler. */ +; + EXPORT __tx_PendSVHandler + EXPORT PendSV_Handler +__tx_PendSVHandler +PendSV_Handler +; +; /* Get current thread value and new thread pointer. */ +; +__tx_ts_handler + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the thread exit function to indicate the thread is no longer executing. */ +; + CPSID i ; Disable interrupts + PUSH {r0, lr} ; Save LR (and r0 just for alignment) + BL _tx_execution_thread_exit ; Call the thread exit function + POP {r0, lr} ; Recover LR + CPSIE i ; Enable interrupts + ENDIF + MOV32 r0, _tx_thread_current_ptr ; Build current thread pointer address + MOV32 r2, _tx_thread_execute_ptr ; Build execute thread pointer address + MOV r3, #0 ; Build NULL value + LDR r1, [r0] ; Pickup current thread pointer +; +; /* Determine if there is a current thread to finish preserving. */ +; + CBZ r1, __tx_ts_new ; If NULL, skip preservation +; +; /* Recover PSP and preserve current thread context. */ +; + STR r3, [r0] ; Set _tx_thread_current_ptr to NULL + MRS r12, PSP ; Pickup PSP pointer (thread's stack pointer) + STMDB r12!, {r4-r11} ; Save its remaining registers + MOV32 r4, _tx_timer_time_slice ; Build address of time-slice variable + STMDB r12!, {LR} ; Save LR on the stack +; +; /* Determine if time-slice is active. If it isn't, skip time handling processing. */ +; + LDR r5, [r4] ; Pickup current time-slice + STR r12, [r1, #8] ; Save the thread stack pointer + CBZ r5, __tx_ts_new ; If not active, skip processing +; +; /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */ +; + STR r5, [r1, #24] ; Save current time-slice +; +; /* Clear the global time-slice. */ +; + STR r3, [r4] ; Clear time-slice +; +; /* Executing thread is now completely preserved!!! */ +; +__tx_ts_new +; +; /* Now we are looking for a new thread to execute! */ +; + CPSID i ; Disable interrupts + LDR r1, [r2] ; Is there another thread ready to execute? + CBZ r1, __tx_ts_wait ; No, skip to the wait processing +; +; /* Yes, another thread is ready for else, make the current thread the new thread. */ +; + STR r1, [r0] ; Setup the current thread pointer to the new thread + CPSIE i ; Enable interrupts +; +; /* Increment the thread run count. */ +; +__tx_ts_restore + LDR r7, [r1, #4] ; Pickup the current thread run count + MOV32 r4, _tx_timer_time_slice ; Build address of time-slice variable + LDR r5, [r1, #24] ; Pickup thread's current time-slice + ADD r7, r7, #1 ; Increment the thread run count + STR r7, [r1, #4] ; Store the new run count +; +; /* Setup global time-slice with thread's current time-slice. */ +; + STR r5, [r4] ; Setup global time-slice + + IF :DEF:TX_ENABLE_EXECUTION_CHANGE_NOTIFY +; +; /* Call the thread entry function to indicate the thread is executing. */ +; + PUSH {r0, r1} ; Save r0/r1 + BL _tx_execution_thread_enter ; Call the thread execution enter function + POP {r0, r1} ; Recover r3 + ENDIF +; +; /* Restore the thread context and PSP. */ +; + LDR r12, [r1, #8] ; Pickup thread's stack pointer + LDMIA r12!, {LR} ; Pickup LR + LDMIA r12!, {r4-r11} ; Recover thread's registers + MSR PSP, r12 ; Setup the thread's stack pointer +; +; /* Return to thread. */ +; + BX lr ; Return to thread! +; +; /* The following is the idle wait processing... in this case, no threads are ready for execution and the +; system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts +; are disabled to allow use of WFI for waiting for a thread to arrive. */ +; +__tx_ts_wait + CPSID i ; Disable interrupts + LDR r1, [r2] ; Pickup the next thread to execute pointer + STR r1, [r0] ; Store it in the current pointer + CBNZ r1, __tx_ts_ready ; If non-NULL, a new thread is ready! + + IF :DEF:TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_enter ; Possibly enter low power mode + POP {r0-r3} + ENDIF + + IF :DEF:TX_ENABLE_WFI + DSB ; Ensure no outstanding memory transactions + WFI ; Wait for interrupt + ISB ; Ensure pipeline is flushed + ENDIF + + IF :DEF:TX_LOW_POWER + PUSH {r0-r3} + BL tx_low_power_exit ; Exit low power mode + POP {r0-r3} + ENDIF + + CPSIE i ; Enable interrupts + B __tx_ts_wait ; Loop to continue waiting +; +; /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are +; already in the handler! */ +; +__tx_ts_ready + MOV r7, #0x08000000 ; Build clear PendSV value + MOV r8, #0xE000E000 ; Build base NVIC address + STR r7, [r8, #0xD04] ; Clear any PendSV +; +; /* Re-enable interrupts and restore new thread. */ +; + CPSIE i ; Enable interrupts + B __tx_ts_restore ; Restore the thread + + ALIGN + LTORG + END diff --git a/ports/cortex_m3/keil/src/tx_thread_stack_build.s b/ports/cortex_m3/keil/src/tx_thread_stack_build.s new file mode 100644 index 0000000..cf5cf6a --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_stack_build.s @@ -0,0 +1,132 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + AREA ||.text||, CODE, READONLY +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_stack_build Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function builds a stack frame on the supplied thread's stack. */ +;/* The stack frame results in a fake interrupt return to the supplied */ +;/* function pointer. */ +;/* */ +;/* INPUT */ +;/* */ +;/* thread_ptr Pointer to thread control blk */ +;/* function_ptr Pointer to return function */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* None */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* _tx_thread_create Create thread service */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +;{ + EXPORT _tx_thread_stack_build +_tx_thread_stack_build +; +; +; /* Build a fake interrupt frame. The form of the fake interrupt stack +; on the Cortex-M3 should look like the following after it is built: +; +; Stack Top: +; LR Interrupted LR (LR at time of PENDSV) +; r4 Initial value for r4 +; r5 Initial value for r5 +; r6 Initial value for r6 +; r7 Initial value for r7 +; r8 Initial value for r8 +; r9 Initial value for r9 +; r10 Initial value for r10 +; r11 Initial value for r11 +; r0 Initial value for r0 (Hardware stack starts here!!) +; r1 Initial value for r1 +; r2 Initial value for r2 +; r3 Initial value for r3 +; r12 Initial value for r12 +; lr Initial value for lr +; pc Initial value for pc +; xPSR Initial value for xPSR +; +; Stack Bottom: (higher memory address) */ +; + LDR r2, [r0, #16] ; Pickup end of stack area + BIC r2, r2, #0x7 ; Align frame for 8-byte alignment + SUB r2, r2, #68 ; Subtract frame size + LDR r3, =0xFFFFFFFD ; Build initial LR value + STR r3, [r2, #0] ; Save on the stack +; +; /* Actually build the stack frame. */ +; + MOV r3, #0 ; Build initial register value + STR r3, [r2, #4] ; Store initial r4 + STR r3, [r2, #8] ; Store initial r5 + STR r3, [r2, #12] ; Store initial r6 + STR r3, [r2, #16] ; Store initial r7 + STR r3, [r2, #20] ; Store initial r8 + STR r3, [r2, #24] ; Store initial r9 + STR r3, [r2, #28] ; Store initial r10 + STR r3, [r2, #32] ; Store initial r11 +; +; /* Hardware stack follows. */ +; + STR r3, [r2, #36] ; Store initial r0 + STR r3, [r2, #40] ; Store initial r1 + STR r3, [r2, #44] ; Store initial r2 + STR r3, [r2, #48] ; Store initial r3 + STR r3, [r2, #52] ; Store initial r12 + MOV r3, #0xFFFFFFFF ; Poison EXC_RETURN value + STR r3, [r2, #56] ; Store initial lr + STR r1, [r2, #60] ; Store initial pc + MOV r3, #0x01000000 ; Only T-bit need be set + STR r3, [r2, #64] ; Store initial xPSR +; +; /* Setup stack pointer. */ +; thread_ptr -> tx_thread_stack_ptr = r2; +; + STR r2, [r0, #8] ; Save stack pointer in thread's + ; control block + BX lr ; Return to caller +;} + END diff --git a/ports/cortex_m3/keil/src/tx_thread_system_return.s b/ports/cortex_m3/keil/src/tx_thread_system_return.s new file mode 100644 index 0000000..80bb525 --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_thread_system_return.s @@ -0,0 +1,84 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Thread */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + AREA ||.text||, CODE, READONLY +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_thread_system_return Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function is target processor specific. It is used to transfer */ +;/* control from a thread back to the ThreadX system. Only a */ +;/* minimal context is saved since the compiler assumes temp registers */ +;/* are going to get slicked by a function call anyway. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_thread_schedule Thread scheduling loop */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* ThreadX components */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_thread_system_return(VOID) +;{ + EXPORT _tx_thread_system_return +_tx_thread_system_return +; +; /* Return to real scheduler via PendSV. Note that this routine is often +; replaced with in-line assembly in tx_port.h to improved performance. */ +; + MOV r0, #0x10000000 ; Load PENDSVSET bit + MOV r1, #0xE000E000 ; Load NVIC base + STR r0, [r1, #0xD04] ; Set PENDSVBIT in ICSR + MRS r0, IPSR ; Pickup IPSR + CMP r0, #0 ; Is it a thread returning? + BNE _isr_context ; If ISR, skip interrupt enable + MRS r1, PRIMASK ; Thread context returning, pickup PRIMASK + CPSIE i ; Enable interrupts + MSR PRIMASK, r1 ; Restore original interrupt posture +_isr_context + BX lr ; Return to caller +;} + END diff --git a/ports/cortex_m3/keil/src/tx_timer_interrupt.s b/ports/cortex_m3/keil/src/tx_timer_interrupt.s new file mode 100644 index 0000000..2ad0ac8 --- /dev/null +++ b/ports/cortex_m3/keil/src/tx_timer_interrupt.s @@ -0,0 +1,258 @@ +;/*************************************************************************** +; * Copyright (c) 2024 Microsoft Corporation +; * +; * 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 +; **************************************************************************/ +; +; +;/**************************************************************************/ +;/**************************************************************************/ +;/** */ +;/** ThreadX Component */ +;/** */ +;/** Timer */ +;/** */ +;/**************************************************************************/ +;/**************************************************************************/ +; +; + IMPORT _tx_timer_time_slice + IMPORT _tx_timer_system_clock + IMPORT _tx_timer_current_ptr + IMPORT _tx_timer_list_start + IMPORT _tx_timer_list_end + IMPORT _tx_timer_expired_time_slice + IMPORT _tx_timer_expired + IMPORT _tx_thread_time_slice + IMPORT _tx_timer_expiration_process + IMPORT _tx_thread_preempt_disable + IMPORT _tx_thread_current_ptr + IMPORT _tx_thread_execute_ptr +; +; + AREA ||.text||, CODE, READONLY + PRESERVE8 +;/**************************************************************************/ +;/* */ +;/* FUNCTION RELEASE */ +;/* */ +;/* _tx_timer_interrupt Cortex-M3/AC5 */ +;/* 6.1 */ +;/* AUTHOR */ +;/* */ +;/* William E. Lamie, Microsoft Corporation */ +;/* */ +;/* DESCRIPTION */ +;/* */ +;/* This function processes the hardware timer interrupt. This */ +;/* processing includes incrementing the system clock and checking for */ +;/* time slice and/or timer expiration. If either is found, the */ +;/* interrupt context save/restore functions are called along with the */ +;/* expiration functions. */ +;/* */ +;/* INPUT */ +;/* */ +;/* None */ +;/* */ +;/* OUTPUT */ +;/* */ +;/* None */ +;/* */ +;/* CALLS */ +;/* */ +;/* _tx_timer_expiration_process Timer expiration processing */ +;/* _tx_thread_time_slice Time slice interrupted thread */ +;/* */ +;/* CALLED BY */ +;/* */ +;/* interrupt vector */ +;/* */ +;/* RELEASE HISTORY */ +;/* */ +;/* DATE NAME DESCRIPTION */ +;/* */ +;/* 09-30-2020 William E. Lamie Initial Version 6.1 */ +;/* */ +;/**************************************************************************/ +;VOID _tx_timer_interrupt(VOID) +;{ + EXPORT _tx_timer_interrupt +_tx_timer_interrupt +; +; /* Upon entry to this routine, it is assumed that context save has already +; been called, and therefore the compiler scratch registers are available +; for use. */ +; +; /* Increment the system clock. */ +; _tx_timer_system_clock++; +; + MOV32 r1, _tx_timer_system_clock ; Pickup address of system clock + LDR r0, [r1, #0] ; Pickup system clock + ADD r0, r0, #1 ; Increment system clock + STR r0, [r1, #0] ; Store new system clock +; +; /* Test for time-slice expiration. */ +; if (_tx_timer_time_slice) +; { +; + MOV32 r3, _tx_timer_time_slice ; Pickup address of time-slice + LDR r2, [r3, #0] ; Pickup time-slice + CBZ r2, __tx_timer_no_time_slice ; Is it non-active? + ; Yes, skip time-slice processing +; +; /* Decrement the time_slice. */ +; _tx_timer_time_slice--; +; + SUB r2, r2, #1 ; Decrement the time-slice + STR r2, [r3, #0] ; Store new time-slice value +; +; /* Check for expiration. */ +; if (__tx_timer_time_slice == 0) +; + CBNZ r2, __tx_timer_no_time_slice ; Has it expired? +; +; /* Set the time-slice expired flag. */ +; _tx_timer_expired_time_slice = TX_TRUE; +; + MOV32 r3, _tx_timer_expired_time_slice ; Pickup address of expired flag + MOV r0, #1 ; Build expired value + STR r0, [r3, #0] ; Set time-slice expiration flag +; +; } +; +__tx_timer_no_time_slice +; +; /* Test for timer expiration. */ +; if (*_tx_timer_current_ptr) +; { +; + MOV32 r1, _tx_timer_current_ptr ; Pickup current timer pointer address + LDR r0, [r1, #0] ; Pickup current timer + LDR r2, [r0, #0] ; Pickup timer list entry + CBZ r2, __tx_timer_no_timer ; Is there anything in the list? + ; No, just increment the timer +; +; /* Set expiration flag. */ +; _tx_timer_expired = TX_TRUE; +; + MOV32 r3, _tx_timer_expired ; Pickup expiration flag address + MOV r2, #1 ; Build expired value + STR r2, [r3, #0] ; Set expired flag + B __tx_timer_done ; Finished timer processing +; +; } +; else +; { +__tx_timer_no_timer +; +; /* No timer expired, increment the timer pointer. */ +; _tx_timer_current_ptr++; +; + ADD r0, r0, #4 ; Move to next timer +; +; /* Check for wrap-around. */ +; if (_tx_timer_current_ptr == _tx_timer_list_end) +; + MOV32 r3, _tx_timer_list_end ; Pickup addr of timer list end + LDR r2, [r3, #0] ; Pickup list end + CMP r0, r2 ; Are we at list end? + BNE __tx_timer_skip_wrap ; No, skip wrap-around logic +; +; /* Wrap to beginning of list. */ +; _tx_timer_current_ptr = _tx_timer_list_start; +; + MOV32 r3, _tx_timer_list_start ; Pickup addr of timer list start + LDR r0, [r3, #0] ; Set current pointer to list start +; +__tx_timer_skip_wrap +; + STR r0, [r1, #0] ; Store new current timer pointer +; } +; +__tx_timer_done +; +; +; /* See if anything has expired. */ +; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) +; { +; + MOV32 r3, _tx_timer_expired_time_slice ; Pickup addr of expired flag + LDR r2, [r3, #0] ; Pickup time-slice expired flag + CBNZ r2, __tx_something_expired ; Did a time-slice expire? + ; If non-zero, time-slice expired + MOV32 r1, _tx_timer_expired ; Pickup addr of other expired flag + LDR r0, [r1, #0] ; Pickup timer expired flag + CBZ r0, __tx_timer_nothing_expired ; Did a timer expire? + ; No, nothing expired +; +__tx_something_expired +; +; + STMDB sp!, {r0, lr} ; Save the lr register on the stack + ; and save r0 just to keep 8-byte alignment +; +; /* Did a timer expire? */ +; if (_tx_timer_expired) +; { +; + MOV32 r1, _tx_timer_expired ; Pickup addr of expired flag + LDR r0, [r1, #0] ; Pickup timer expired flag + CBZ r0, __tx_timer_dont_activate ; Check for timer expiration + ; If not set, skip timer activation +; +; /* Process timer expiration. */ +; _tx_timer_expiration_process(); +; + BL _tx_timer_expiration_process ; Call the timer expiration handling routine +; +; } +__tx_timer_dont_activate +; +; /* Did time slice expire? */ +; if (_tx_timer_expired_time_slice) +; { +; + MOV32 r3, _tx_timer_expired_time_slice ; Pickup addr of time-slice expired + LDR r2, [r3, #0] ; Pickup the actual flag + CBZ r2, __tx_timer_not_ts_expiration ; See if the flag is set + ; No, skip time-slice processing +; +; /* Time slice interrupted thread. */ +; _tx_thread_time_slice(); + + BL _tx_thread_time_slice ; Call time-slice processing + MOV32 r0, _tx_thread_preempt_disable ; Build address of preempt disable flag + LDR r1, [r0] ; Is the preempt disable flag set? + CBNZ r1, __tx_timer_skip_time_slice ; Yes, skip the PendSV logic + MOV32 r0, _tx_thread_current_ptr ; Build current thread pointer address + LDR r1, [r0] ; Pickup the current thread pointer + MOV32 r2, _tx_thread_execute_ptr ; Build execute thread pointer address + LDR r3, [r2] ; Pickup the execute thread pointer + MOV32 r0, 0xE000ED04 ; Build address of control register + MOV32 r2, 0x10000000 ; Build value for PendSV bit + CMP r1, r3 ; Are they the same? + BEQ __tx_timer_skip_time_slice ; If the same, there was no time-slice performed + STR r2, [r0] ; Not the same, issue the PendSV for preemption +__tx_timer_skip_time_slice +; +; } +; +__tx_timer_not_ts_expiration +; + LDMIA sp!, {r0, lr} ; Recover lr register (r0 is just there for +; +; } +; +__tx_timer_nothing_expired + + DSB ; Complete all memory access + BX lr ; Return to caller +; +;} + ALIGN + LTORG + END