From 852421fda03a7722d7adb45b187235cd66fa264e Mon Sep 17 00:00:00 2001 From: PProvost Date: Mon, 11 May 2020 08:55:07 -0600 Subject: [PATCH] Initial commit --- .gitattributes | 40 + .gitignore | 14 + CMakeLists.txt | 44 + LICENSE.txt | 246 ++ LICENSED-HARDWARE.txt | 16 + README.md | 1 + TODO | 2 + common/CMakeLists.txt | 208 ++ common/inc/tx_api.h | 2208 +++++++++++++++++ common/inc/tx_block_pool.h | 146 ++ common/inc/tx_byte_pool.h | 177 ++ common/inc/tx_event_flags.h | 147 ++ common/inc/tx_initialize.h | 111 + common/inc/tx_mutex.h | 160 ++ common/inc/tx_queue.h | 173 ++ common/inc/tx_semaphore.h | 144 ++ common/inc/tx_thread.h | 524 ++++ common/inc/tx_timer.h | 213 ++ common/inc/tx_trace.h | 559 +++++ common/inc/tx_user_sample.h | 257 ++ common/src/tx_block_allocate.c | 372 +++ common/src/tx_block_pool_cleanup.c | 213 ++ common/src/tx_block_pool_create.c | 213 ++ common/src/tx_block_pool_delete.c | 207 ++ common/src/tx_block_pool_info_get.c | 146 ++ common/src/tx_block_pool_initialize.c | 129 + .../src/tx_block_pool_performance_info_get.c | 201 ++ ...x_block_pool_performance_system_info_get.c | 173 ++ common/src/tx_block_pool_prioritize.c | 249 ++ common/src/tx_block_release.c | 204 ++ common/src/tx_byte_allocate.c | 409 +++ common/src/tx_byte_pool_cleanup.c | 212 ++ common/src/tx_byte_pool_create.c | 197 ++ common/src/tx_byte_pool_delete.c | 211 ++ common/src/tx_byte_pool_info_get.c | 146 ++ common/src/tx_byte_pool_initialize.c | 147 ++ .../src/tx_byte_pool_performance_info_get.c | 253 ++ ...tx_byte_pool_performance_system_info_get.c | 221 ++ common/src/tx_byte_pool_prioritize.c | 249 ++ common/src/tx_byte_pool_search.c | 350 +++ common/src/tx_byte_release.c | 376 +++ common/src/tx_event_flags_cleanup.c | 237 ++ common/src/tx_event_flags_create.c | 141 ++ common/src/tx_event_flags_delete.c | 207 ++ common/src/tx_event_flags_get.c | 401 +++ common/src/tx_event_flags_info_get.c | 143 ++ common/src/tx_event_flags_initialize.c | 130 + .../src/tx_event_flags_performance_info_get.c | 202 ++ ..._event_flags_performance_system_info_get.c | 174 ++ common/src/tx_event_flags_set.c | 620 +++++ common/src/tx_event_flags_set_notify.c | 107 + common/src/tx_initialize_high_level.c | 150 ++ common/src/tx_initialize_kernel_enter.c | 148 ++ common/src/tx_initialize_kernel_setup.c | 100 + common/src/tx_misra.c | 833 +++++++ common/src/tx_mutex_cleanup.c | 313 +++ common/src/tx_mutex_create.c | 146 ++ common/src/tx_mutex_delete.c | 243 ++ common/src/tx_mutex_get.c | 409 +++ common/src/tx_mutex_info_get.c | 147 ++ common/src/tx_mutex_initialize.c | 141 ++ common/src/tx_mutex_performance_info_get.c | 230 ++ .../tx_mutex_performance_system_info_get.c | 205 ++ common/src/tx_mutex_prioritize.c | 265 ++ common/src/tx_mutex_priority_change.c | 328 +++ common/src/tx_mutex_put.c | 654 +++++ common/src/tx_queue_cleanup.c | 225 ++ common/src/tx_queue_create.c | 170 ++ common/src/tx_queue_delete.c | 206 ++ common/src/tx_queue_flush.c | 205 ++ common/src/tx_queue_front_send.c | 421 ++++ common/src/tx_queue_info_get.c | 145 ++ common/src/tx_queue_initialize.c | 138 ++ common/src/tx_queue_performance_info_get.c | 229 ++ .../tx_queue_performance_system_info_get.c | 205 ++ common/src/tx_queue_prioritize.c | 249 ++ common/src/tx_queue_receive.c | 486 ++++ common/src/tx_queue_send.c | 426 ++++ common/src/tx_queue_send_notify.c | 107 + common/src/tx_semaphore_ceiling_put.c | 243 ++ common/src/tx_semaphore_cleanup.c | 215 ++ common/src/tx_semaphore_create.c | 142 ++ common/src/tx_semaphore_delete.c | 207 ++ common/src/tx_semaphore_get.c | 232 ++ common/src/tx_semaphore_info_get.c | 139 ++ common/src/tx_semaphore_initialize.c | 129 + .../src/tx_semaphore_performance_info_get.c | 201 ++ ...tx_semaphore_performance_system_info_get.c | 174 ++ common/src/tx_semaphore_prioritize.c | 251 ++ common/src/tx_semaphore_put.c | 222 ++ common/src/tx_semaphore_put_notify.c | 107 + common/src/tx_thread_create.c | 360 +++ common/src/tx_thread_delete.c | 166 ++ common/src/tx_thread_entry_exit_notify.c | 109 + common/src/tx_thread_identify.c | 103 + common/src/tx_thread_info_get.c | 163 ++ common/src/tx_thread_initialize.c | 448 ++++ common/src/tx_thread_performance_info_get.c | 297 +++ .../tx_thread_performance_system_info_get.c | 287 +++ common/src/tx_thread_preemption_change.c | 280 +++ common/src/tx_thread_priority_change.c | 280 +++ common/src/tx_thread_relinquish.c | 169 ++ common/src/tx_thread_reset.c | 163 ++ common/src/tx_thread_resume.c | 581 +++++ common/src/tx_thread_shell_entry.c | 201 ++ common/src/tx_thread_sleep.c | 198 ++ common/src/tx_thread_stack_analyze.c | 181 ++ common/src/tx_thread_stack_error_handler.c | 105 + common/src/tx_thread_stack_error_notify.c | 125 + common/src/tx_thread_suspend.c | 843 +++++++ common/src/tx_thread_system_preempt_check.c | 127 + common/src/tx_thread_system_resume.c | 1002 ++++++++ common/src/tx_thread_system_suspend.c | 1218 +++++++++ common/src/tx_thread_terminate.c | 310 +++ common/src/tx_thread_time_slice.c | 184 ++ common/src/tx_thread_time_slice_change.c | 117 + common/src/tx_thread_timeout.c | 164 ++ common/src/tx_thread_wait_abort.c | 235 ++ common/src/tx_time_get.c | 100 + common/src/tx_time_set.c | 92 + common/src/tx_timer_activate.c | 135 + common/src/tx_timer_change.c | 103 + common/src/tx_timer_create.c | 167 ++ common/src/tx_timer_deactivate.c | 250 ++ common/src/tx_timer_delete.c | 142 ++ common/src/tx_timer_expiration_process.c | 477 ++++ common/src/tx_timer_info_get.c | 248 ++ common/src/tx_timer_initialize.c | 304 +++ common/src/tx_timer_performance_info_get.c | 214 ++ .../tx_timer_performance_system_info_get.c | 187 ++ common/src/tx_timer_system_activate.c | 164 ++ common/src/tx_timer_system_deactivate.c | 132 + common/src/tx_timer_thread_entry.c | 480 ++++ common/src/tx_trace_buffer_full_notify.c | 109 + common/src/tx_trace_disable.c | 103 + common/src/tx_trace_enable.c | 442 ++++ common/src/tx_trace_event_filter.c | 106 + common/src/tx_trace_event_unfilter.c | 106 + common/src/tx_trace_initialize.c | 152 ++ common/src/tx_trace_interrupt_control.c | 104 + common/src/tx_trace_isr_enter_insert.c | 108 + common/src/tx_trace_isr_exit_insert.c | 108 + common/src/tx_trace_object_register.c | 291 +++ common/src/tx_trace_object_unregister.c | 131 + common/src/tx_trace_user_event_insert.c | 160 ++ common/src/txe_block_allocate.c | 160 ++ common/src/txe_block_pool_create.c | 227 ++ common/src/txe_block_pool_delete.c | 146 ++ common/src/txe_block_pool_info_get.c | 114 + common/src/txe_block_pool_prioritize.c | 101 + common/src/txe_block_release.c | 123 + common/src/txe_byte_allocate.c | 199 ++ common/src/txe_byte_pool_create.c | 222 ++ common/src/txe_byte_pool_delete.c | 144 ++ common/src/txe_byte_pool_info_get.c | 113 + common/src/txe_byte_pool_prioritize.c | 101 + common/src/txe_byte_release.c | 135 + common/src/txe_event_flags_create.c | 203 ++ common/src/txe_event_flags_delete.c | 146 ++ common/src/txe_event_flags_get.c | 177 ++ common/src/txe_event_flags_info_get.c | 115 + common/src/txe_event_flags_set.c | 126 + common/src/txe_event_flags_set_notify.c | 104 + common/src/txe_mutex_create.c | 221 ++ common/src/txe_mutex_delete.c | 146 ++ common/src/txe_mutex_get.c | 168 ++ common/src/txe_mutex_info_get.c | 114 + common/src/txe_mutex_prioritize.c | 101 + common/src/txe_mutex_put.c | 124 + common/src/txe_queue_create.c | 237 ++ common/src/txe_queue_delete.c | 142 ++ common/src/txe_queue_flush.c | 102 + common/src/txe_queue_front_send.c | 158 ++ common/src/txe_queue_info_get.c | 112 + common/src/txe_queue_prioritize.c | 98 + common/src/txe_queue_receive.c | 160 ++ common/src/txe_queue_send.c | 158 ++ common/src/txe_queue_send_notify.c | 103 + common/src/txe_semaphore_ceiling_put.c | 113 + common/src/txe_semaphore_create.c | 208 ++ common/src/txe_semaphore_delete.c | 143 ++ common/src/txe_semaphore_get.c | 148 ++ common/src/txe_semaphore_info_get.c | 113 + common/src/txe_semaphore_prioritize.c | 101 + common/src/txe_semaphore_put.c | 101 + common/src/txe_semaphore_put_notify.c | 104 + common/src/txe_thread_create.c | 311 +++ common/src/txe_thread_delete.c | 110 + common/src/txe_thread_entry_exit_notify.c | 104 + common/src/txe_thread_info_get.c | 117 + common/src/txe_thread_preemption_change.c | 130 + common/src/txe_thread_priority_change.c | 131 + common/src/txe_thread_relinquish.c | 92 + common/src/txe_thread_reset.c | 136 + common/src/txe_thread_resume.c | 101 + common/src/txe_thread_suspend.c | 103 + common/src/txe_thread_terminate.c | 112 + common/src/txe_thread_time_slice_change.c | 122 + common/src/txe_thread_wait_abort.c | 101 + common/src/txe_timer_activate.c | 101 + common/src/txe_timer_change.c | 124 + common/src/txe_timer_create.c | 237 ++ common/src/txe_timer_deactivate.c | 102 + common/src/txe_timer_delete.c | 143 ++ common/src/txe_timer_info_get.c | 110 + docs/ThreadX_User_Guide.pdf | Bin 0 -> 2836943 bytes ports/cortex_m0/gnu/CMakeLists.txt | 21 + ports/cortex_m0/gnu/inc/tx_port.h | 371 +++ .../gnu/src/tx_initialize_low_level_sample.S | 185 ++ .../gnu/src/tx_thread_context_restore.S | 96 + .../gnu/src/tx_thread_context_save.S | 90 + .../gnu/src/tx_thread_interrupt_control.S | 94 + .../gnu/src/tx_thread_interrupt_disable.S | 88 + .../gnu/src/tx_thread_interrupt_restore.S | 86 + ports/cortex_m0/gnu/src/tx_thread_schedule.S | 278 +++ .../cortex_m0/gnu/src/tx_thread_stack_build.S | 149 ++ .../gnu/src/tx_thread_system_return.S | 97 + ports/cortex_m0/gnu/src/tx_timer_interrupt.S | 271 ++ .../gnu/src/tx_vector_table_sample.S | 102 + ports/cortex_m3/gnu/CMakeLists.txt | 19 + ports/cortex_m3/gnu/inc/tx_port.h | 357 +++ .../gnu/src/tx_initialize_low_level_sample.S | 244 ++ .../gnu/src/tx_thread_context_restore.S | 96 + .../gnu/src/tx_thread_context_save.S | 89 + .../gnu/src/tx_thread_interrupt_control.S | 92 + ports/cortex_m3/gnu/src/tx_thread_schedule.S | 252 ++ .../cortex_m3/gnu/src/tx_thread_stack_build.S | 148 ++ .../gnu/src/tx_thread_system_return.S | 98 + ports/cortex_m3/gnu/src/tx_timer_interrupt.S | 270 ++ .../gnu/src/tx_vector_table_sample.S | 84 + ports/cortex_m4/gnu/CMakeLists.txt | 19 + ports/cortex_m4/gnu/inc/tx_port.h | 499 ++++ .../gnu/src/tx_initialize_low_level_sample.S | 240 ++ .../gnu/src/tx_thread_context_restore.S | 96 + .../gnu/src/tx_thread_context_save.S | 89 + .../gnu/src/tx_thread_interrupt_control.S | 92 + ports/cortex_m4/gnu/src/tx_thread_schedule.S | 296 +++ .../cortex_m4/gnu/src/tx_thread_stack_build.S | 148 ++ .../gnu/src/tx_thread_system_return.S | 98 + ports/cortex_m4/gnu/src/tx_timer_interrupt.S | 270 ++ .../gnu/src/tx_vector_table_sample.S | 84 + ports/cortex_m7/gnu/CMakeLists.txt | 17 + ports/cortex_m7/gnu/inc/tx_port.h | 496 ++++ .../gnu/src/tx_initialize_low_level_sample.S | 239 ++ .../gnu/src/tx_thread_context_restore.S | 96 + .../gnu/src/tx_thread_context_save.S | 89 + .../gnu/src/tx_thread_interrupt_control.S | 92 + ports/cortex_m7/gnu/src/tx_thread_schedule.S | 296 +++ .../cortex_m7/gnu/src/tx_thread_stack_build.S | 148 ++ .../gnu/src/tx_thread_system_return.S | 98 + ports/cortex_m7/gnu/src/tx_timer_interrupt.S | 270 ++ .../gnu/src/tx_vector_table_sample.S | 84 + ports/linux/gnu/CMakeLists.txt | 25 + ports/linux/gnu/inc/tx_port.h | 575 +++++ .../gnu/src/tx_initialize_low_level_sample.c | 443 ++++ .../linux/gnu/src/tx_thread_context_restore.c | 163 ++ ports/linux/gnu/src/tx_thread_context_save.c | 107 + .../gnu/src/tx_thread_interrupt_control.c | 183 ++ ports/linux/gnu/src/tx_thread_schedule.c | 264 ++ ports/linux/gnu/src/tx_thread_stack_build.c | 153 ++ ports/linux/gnu/src/tx_thread_system_return.c | 207 ++ ports/linux/gnu/src/tx_timer_interrupt.c | 153 ++ ports/win32/gnu/CMakeLists.txt | 18 + samples/demo_threadx.c | 370 +++ 264 files changed, 54459 insertions(+) create mode 100755 .gitattributes create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE.txt create mode 100644 LICENSED-HARDWARE.txt create mode 100644 README.md create mode 100644 TODO create mode 100644 common/CMakeLists.txt 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 100755 docs/ThreadX_User_Guide.pdf create mode 100644 ports/cortex_m0/gnu/CMakeLists.txt create mode 100644 ports/cortex_m0/gnu/inc/tx_port.h create mode 100755 ports/cortex_m0/gnu/src/tx_initialize_low_level_sample.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_context_restore.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_context_save.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_interrupt_control.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_interrupt_disable.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_interrupt_restore.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_schedule.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_stack_build.S create mode 100755 ports/cortex_m0/gnu/src/tx_thread_system_return.S create mode 100755 ports/cortex_m0/gnu/src/tx_timer_interrupt.S create mode 100644 ports/cortex_m0/gnu/src/tx_vector_table_sample.S create mode 100644 ports/cortex_m3/gnu/CMakeLists.txt create mode 100644 ports/cortex_m3/gnu/inc/tx_port.h create mode 100644 ports/cortex_m3/gnu/src/tx_initialize_low_level_sample.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_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/gnu/src/tx_vector_table_sample.S create mode 100644 ports/cortex_m4/gnu/CMakeLists.txt create mode 100644 ports/cortex_m4/gnu/inc/tx_port.h create mode 100644 ports/cortex_m4/gnu/src/tx_initialize_low_level_sample.S create mode 100644 ports/cortex_m4/gnu/src/tx_thread_context_restore.S create mode 100644 ports/cortex_m4/gnu/src/tx_thread_context_save.S create mode 100644 ports/cortex_m4/gnu/src/tx_thread_interrupt_control.S create mode 100644 ports/cortex_m4/gnu/src/tx_thread_schedule.S create mode 100644 ports/cortex_m4/gnu/src/tx_thread_stack_build.S create mode 100644 ports/cortex_m4/gnu/src/tx_thread_system_return.S create mode 100644 ports/cortex_m4/gnu/src/tx_timer_interrupt.S create mode 100644 ports/cortex_m4/gnu/src/tx_vector_table_sample.S create mode 100644 ports/cortex_m7/gnu/CMakeLists.txt create mode 100644 ports/cortex_m7/gnu/inc/tx_port.h create mode 100755 ports/cortex_m7/gnu/src/tx_initialize_low_level_sample.S create mode 100755 ports/cortex_m7/gnu/src/tx_thread_context_restore.S create mode 100755 ports/cortex_m7/gnu/src/tx_thread_context_save.S create mode 100755 ports/cortex_m7/gnu/src/tx_thread_interrupt_control.S create mode 100755 ports/cortex_m7/gnu/src/tx_thread_schedule.S create mode 100755 ports/cortex_m7/gnu/src/tx_thread_stack_build.S create mode 100755 ports/cortex_m7/gnu/src/tx_thread_system_return.S create mode 100755 ports/cortex_m7/gnu/src/tx_timer_interrupt.S create mode 100644 ports/cortex_m7/gnu/src/tx_vector_table_sample.S create mode 100644 ports/linux/gnu/CMakeLists.txt create mode 100644 ports/linux/gnu/inc/tx_port.h create mode 100644 ports/linux/gnu/src/tx_initialize_low_level_sample.c create mode 100644 ports/linux/gnu/src/tx_thread_context_restore.c create mode 100644 ports/linux/gnu/src/tx_thread_context_save.c create mode 100644 ports/linux/gnu/src/tx_thread_interrupt_control.c create mode 100644 ports/linux/gnu/src/tx_thread_schedule.c create mode 100644 ports/linux/gnu/src/tx_thread_stack_build.c create mode 100644 ports/linux/gnu/src/tx_thread_system_return.c create mode 100644 ports/linux/gnu/src/tx_timer_interrupt.c create mode 100644 ports/win32/gnu/CMakeLists.txt create mode 100644 samples/demo_threadx.c diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 00000000..ee9315d0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,40 @@ +.git* export-ignore +.hooks* export-ignore + +# Custom attribute to mark sources as using our C code style. +[attr]our-c-style whitespace=tab-in-indent eol=lf format.clang-format-6.0 + +# Custom attribute to mark sources as generated. +# Do not perform whitespace checks. Do not format. +[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-6.0 + +bootstrap eol=lf +configure eol=lf +*.[1-9] eol=lf +*.bash eol=lf +*.sh eol=lf +*.sh.in eol=lf + +*.bat eol=crlf +*.bat.in eol=crlf +*.sln eol=crlf +*.vcproj eol=crlf + +*.pfx -text +*.png -text +*.png.in -text + +*.c our-c-style +*.cc our-c-style +*.cpp our-c-style +*.cu our-c-style +*.cxx our-c-style +*.h our-c-style +*.hh our-c-style +*.hpp our-c-style +*.hxx our-c-style +*.notcu our-c-style + +*.cmake whitespace=tab-in-indent +*.rst whitespace=tab-in-indent conflict-marker-size=79 +*.txt whitespace=tab-in-indent \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9c33dc7f --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.vscode/ +_deps/ +build/ +CMakeFiles/ +CMakeScripts/ +CMakeLists.txt.user +CMakeCache.txt +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..a6a08241 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +# Set up the project +project(threadx + VERSION 6.0.0 + LANGUAGES C ASM +) + +if(NOT DEFINED THREADX_ARCH) + message(FATAL_ERROR "Error: THREADX_ARCH not defined") +endif() +if(NOT DEFINED THREADX_TOOLCHAIN) + message(FATAL_ERROR "Error: THREADX_TOOLCHAIN not defined") +endif() + +# Define our target library and an alias for consumers +add_library(${PROJECT_NAME}) +add_library("azrtos::${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) + +# A place for generated/copied include files (no need to change) +set(CUSTOM_INC_DIR ${CMAKE_CURRENT_BINARY_DIR}/custom_inc) + +# Pick up the port specific variables and apply them +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}) + +# Pick up the common stuff +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common) + + + + +# If the user provided an override, copy it to the custom directory +if (NOT TX_USER_FILE) + message(STATUS "Using default tx_user.h file") + set(TX_USER_FILE ${CMAKE_CURRENT_LIST_DIR}/common/inc/tx_user_sample.h) +else() + message(STATUS "Using custom tx_user.h file from ${UX_USER_FILE}") +endif() +configure_file(${TX_USER_FILE} ${CUSTOM_INC_DIR}/tx_user.h COPYONLY) +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CUSTOM_INC_DIR} +) +target_compile_definitions(${PROJECT_NAME} PUBLIC "TX_INCLUDE_USER_DEFINE_FILE" ) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..76974a36 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,246 @@ +MICROSOFT SOFTWARE LICENSE TERMS + +MICROSOFT AZURE RTOS + +Shape + +These license terms are an agreement between you and Microsoft Corporation (or +one of its affiliates). They apply to the software named above and any Microsoft +services or software updates (except to the extent such services or updates are +accompanied by new or additional terms, in which case those different terms +apply prospectively and do not alter your or Microsoft’s rights relating to +pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU +HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. + +INSTALLATION AND USE RIGHTS. + +General. You may install and use the software and the included Microsoft +applications solely for internal development, testing and evaluation purposes. +Any distribution or production use requires a separate license as set forth in +Section 2. + +Contributions. Microsoft welcomes contributions to this software. In the event +that you make a contribution to this software you will be required to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and +actually do, grant Microsoft the rights to use your contribution. For details, +visit https://cla.microsoft.com. + +Included Microsoft Applications. The software includes other Microsoft +applications which are governed by the licenses embedded in or made available +with those applications. + +Third Party Components. The software may include third party components with +separate legal notices or governed by other agreements, as may be described +within the software or in the ThirdPartyNotices file(s) accompanying the +software. + +Competitive Benchmarking. If you are a direct competitor, and you access or use +the software for purposes of competitive benchmarking, analysis, or intelligence +gathering, you waive as against Microsoft, its subsidiaries, and its affiliated +companies (including prospectively) any competitive use, access, and +benchmarking test restrictions in the terms governing your software to the +extent your terms of use are, or purport to be, more restrictive than +Microsoft’s terms. If you do not waive any such purported restrictions in the +terms governing your software, you are not allowed to access or use this +software, and will not do so. + +DISTRIBUTION AND PRODUCTION USE. If you have obtained and/or are developing on +microprocessor(s) and/or microcontroller(s) (“hardware”) listed in the file +named “LICENSED-HARDWARE.txt” included in the repository and/or distributed with +the software you have the following rights in and to the software solely when +used in combination with the hardware. In the event hardware is not listed in +the LICENSED-HARDWARE.txt file, you do not have the rights in this Section 2. + +Distribution and Production Use Rights. + +You may use the software in production (e.g. program the modified or unmodified +software to devices you own or control) and distribute (i.e. make available to +third parties) the modified or unmodified binary image produced from this code. + + +You may permit your device distributors or developers to copy and distribute the +binary image as programmed or to be programmed to your devices. + +You may redistribute the unmodified or modified source to your device +distributors or developers. Modifications must be clearly marked. Any +redistribution in source code form must contain this license and any other +licenses that accompany the software. + +Requirements. For any code you distribute, you must: + +when distributed in binary form, except as embedded in a device, include with +such distribution the terms of this agreement; + +when distributed in source code form to distributors or developers of your +devices, include with such distribution the terms of this agreement; and + +indemnify, defend and hold harmless Microsoft from any claims, including +attorneys’ fees, related to the distribution or use of your devices, except to +the extent that any claim is based solely on the unmodified software. + +Restrictions. You may not: + +use or modify the software to create a competing real time operating system +software; + +remove any copyright notices or licenses contained in the software; + +use Microsoft’s trademarks or trade dress in your application in any way that +suggests your device or application comes from or is endorsed by Microsoft; + +transfer individual components, specific libraries, classes, functions or code +fragments of the software separately for purposes unrelated to the software; or + +use or distribute the software in any way that would subject the software or +Microsoft’s intellectual property or technology to any other license terms. + +SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all +other rights. Unless applicable law gives you more rights despite this +limitation, you will not (and have no right to): + +remove, minimize, block, or modify any notices of Microsoft or its suppliers in +the software; + +use the software in any way that is against the law or to create or propagate +malware; or + +share, publish, distribute, or lease the software (except as permitted in +Section 2 above), or provide the software as a stand-alone offering for others +to use. + +DATA. This software may interact with other Microsoft products that collect data +that is transmitted to Microsoft. To learn more about how Microsoft processes +personal data we collect, please see the Microsoft Privacy Statement at +https://go.microsoft.com/fwlink/?LinkId=248681. + +EXPORT RESTRICTIONS. You must comply with all domestic and international export +laws and regulations that apply to the software, which include restrictions on +destinations, end users, and end use. For further information on export +restrictions, visit https://aka.ms/exporting. + +SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any +support services for the software. Any support provided is “as is”, “with all +faults”, and without warranty of any kind. + +UPDATES. Microsoft may periodically update the software. You may obtain updates +only from Microsoft or Microsoft-authorized sources. Updates may not include or +support all existing software features, services, or peripheral devices. + +TERMINATION. Without prejudice to any other rights, Microsoft may terminate this +agreement if you fail to comply with any of its terms or conditions. In such +event, you must destroy all copies of the software and all of its component +parts. + +ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for +supplements, updates, or third-party applications, is the entire agreement for +the software. To the extent you have entered into a separate agreement with +Microsoft relating specifically to the software, the terms in such agreement +shall control. + +APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in +the United States or Canada, the laws of the state or province where you live +(or, if a business, where your principal place of business is located) govern +the interpretation of this agreement, claims for its breach, and all other +claims (including consumer protection, unfair competition, and tort claims), +regardless of conflict of laws principles. If you acquired the software in any +other country, its laws apply. If U.S. federal jurisdiction exists, you and +Microsoft consent to exclusive jurisdiction and venue in the federal court in +King County, Washington for all disputes heard in court. If not, you and +Microsoft consent to exclusive jurisdiction and venue in the Superior Court of +King County, Washington for all disputes heard in court. + +CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal +rights. You may have other rights, including consumer rights, under the laws of +your state or country. Separate and apart from your relationship with Microsoft, +you may also have rights with respect to the party from which you acquired the +software. This agreement does not change those other rights if the laws of your +state or country do not permit it to do so. For example, if you acquired the +software in one of the below regions, or mandatory country law applies, then the +following provisions apply to you: + +Australia. You have statutory guarantees under the Australian Consumer Law and +nothing in this agreement is intended to affect those rights. + +Germany and Austria. + +i.Warranty. The properly licensed software will perform substantially as +described in any Microsoft materials that accompany the software. However, +Microsoft gives no contractual guarantee in relation to the licensed software. + +ii.Limitation of Liability. In case of intentional conduct, gross negligence, +claims based on the Product Liability Act, as well as, in case of death or +personal or physical injury, Microsoft is liable according to the statutory law. + + +Subject to the foregoing clause ii., Microsoft will only be liable for slight +negligence if Microsoft is in breach of such material contractual obligations, +the fulfillment of which facilitate the due performance of this agreement, the +breach of which would endanger the purpose of this agreement and the compliance +with which a party may constantly trust in (so-called "cardinal obligations"). +In other cases of slight negligence, Microsoft will not be liable for slight +negligence. + +DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF +USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO +THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED +WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. + +LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING +DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM +MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT +RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, +INDIRECT, OR INCIDENTAL DAMAGES. + +This limitation applies to (a) anything related to the software, services, +content (including code) on third party Internet sites, or third party +applications; and (b) claims for breach of contract, warranty, guarantee, or +condition; strict liability, negligence, or other tort; or any other claim; in +each case to the extent permitted by applicable law. + +It also applies even if Microsoft knew or should have known about the +possibility of the damages. The above limitation or exclusion may not apply to +you because your state, province, or country may not allow the exclusion or +limitation of incidental, consequential, or other damages. + + + +Please note: As this software is distributed in Canada, some of the clauses in +this agreement are provided below in French. + +Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce +contrat sont fournies ci-dessous en français. + +EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel +». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft +n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits +additionnels en vertu du droit local sur la protection des consommateurs, que ce +contrat ne peut modifier. La ou elles sont permises par le droit locale, les +garanties implicites de qualité marchande, d’adéquation à un usage particulier +et d’absence de contrefaçon sont exclues. + +LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES +DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une +indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous +ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris +les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. + +Cette limitation concerne: + +•tout ce qui est relié au logiciel, aux services ou au contenu (y compris le +code) figurant sur des sites Internet tiers ou dans des programmes tiers; et + +•les réclamations au titre de violation de contrat ou de garantie, ou au titre +de responsabilité stricte, de négligence ou d’une autre faute dans la limite +autorisée par la loi en vigueur. + +Elle s’applique également, même si Microsoft connaissait ou devrait connaître +l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la +limitation de responsabilité pour les dommages indirects, accessoires ou de +quelque nature que ce soit, il se peut que la limitation ou l’exclusion +ci-dessus ne s’appliquera pas à votre égard. + +EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous +pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent +contrat ne modifie pas les droits que vous confèrent les lois de votre pays si +celles-ci ne le permettent pas. \ No newline at end of file diff --git a/LICENSED-HARDWARE.txt b/LICENSED-HARDWARE.txt new file mode 100644 index 00000000..77dd1abf --- /dev/null +++ b/LICENSED-HARDWARE.txt @@ -0,0 +1,16 @@ +LICENSED HARDWARE LIST + +Last Updated: 2020-05-08 + +Microsoft has entered into OEM Agreements with manufacturers of the following +microprocessors and microcontrollers (the “hardware”) to enable those +manufacturers to include and distribute Azure RTOS in certain hardware. If you +have obtained and/or are developing on microprocessor(s) and/or +microcontroller(s) (“hardware”) listed below you inherit the “Distribution and +Production Use” rights in Section 2 of the Microsoft Software License Terms for +Microsoft Azure RTOS. If hardware is not listed below, you do not have those +rights. + +-------------------------------------------------------------------------------- + +More coming soon. Please check back frequently for updates. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..bf9a068d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# ThreadX \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 00000000..22e66890 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +TODO: + diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 00000000..1df4e845 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,208 @@ +function(target_sources_if_not_overridden filename) + list(FIND TX_SRC_OVERRIDES ${filename} OVERRIDE_FOUND) + if( OVERRIDE_FOUND EQUAL -1 ) + message(STATUS "** Using original ${filename} from common/src **") + target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/${filename}) + endif() +endfunction() + +# These files can be overridden by setting them in the variable list named TX_SRC_OVERRIDES +target_sources_if_not_overridden("tx_thread_delete.c") +target_sources_if_not_overridden("tx_thread_reset.c") + +target_sources(${PROJECT_NAME} + PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_pool_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_block_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_pool_search.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_byte_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_event_flags_set_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_high_level.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_kernel_enter.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_kernel_setup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_misra.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_priority_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_mutex_put.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_flush.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_front_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_queue_send_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_ceiling_put.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_put.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_semaphore_put_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_entry_exit_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_identify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_preemption_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_priority_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_relinquish.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_resume.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_shell_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_sleep.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_analyze.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_error_handler.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_error_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_suspend.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_preempt_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_resume.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_suspend.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_terminate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_time_slice.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_time_slice_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_timeout.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_wait_abort.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_time_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_time_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_activate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_deactivate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_expiration_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_performance_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_performance_system_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_system_activate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_system_deactivate.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_thread_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_buffer_full_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_event_filter.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_event_unfilter.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_interrupt_control.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_isr_enter_insert.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_isr_exit_insert.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_object_register.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_object_unregister.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_trace_user_event_insert.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_block_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_block_pool_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_block_pool_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_block_pool_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_block_pool_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_block_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_byte_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_byte_pool_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_byte_pool_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_byte_pool_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_byte_pool_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_byte_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_event_flags_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_event_flags_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_event_flags_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_event_flags_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_event_flags_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_event_flags_set_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_mutex_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_mutex_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_mutex_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_mutex_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_mutex_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_mutex_put.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_flush.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_front_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_queue_send_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_ceiling_put.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_prioritize.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_put.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_semaphore_put_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_entry_exit_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_preemption_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_priority_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_relinquish.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_reset.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_resume.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_suspend.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_terminate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_time_slice_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_thread_wait_abort.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_timer_activate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_timer_change.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_timer_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_timer_deactivate.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_timer_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/txe_timer_info_get.c + + # {{END_TARGET_SOURCES}} +) + +# Add the Common/inc directory to the project include list +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) + diff --git a/common/inc/tx_api.h b/common/inc/tx_api.h new file mode 100644 index 00000000..d73d995d --- /dev/null +++ b/common/inc/tx_api.h @@ -0,0 +1,2208 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Application Interface (API) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* tx_api.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 + + +/* Include the port-specific data type file. */ + +#include "tx_port.h" + + +/* 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 EL_PRODUCT_THREADX +#define THREADX_MAJOR_VERSION 6 +#define THREADX_MINOR_VERSION 0 + + +/* 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) +#define TX_STACK_FILL ((ULONG) 0xEFEFEFEFUL) + + +/* 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) + + +/* API return values. */ + +#define TX_SUCCESS ((UINT) 0x00) +#define TX_DELETED ((UINT) 0x01) +#define TX_NO_MEMORY ((UINT) 0x10) +#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_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) + + +/* 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 ((ULONG) 100) +#endif + + +/* Event numbers 0 through 4095 are reserved by Express Logic. 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. */ + VOID *tx_thread_filex_ptr; + + /* 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 suspension sequence number. This is used to ensure suspension is still valid when + cleanup routine executes. */ + ULONG tx_thread_suspension_sequence; + + /* 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 + + +/* 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_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 + + + +/* 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 00000000..1000c4b6 --- /dev/null +++ b/common/inc/tx_block_pool.h @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_block_pool.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..408a0924 --- /dev/null +++ b/common/inc/tx_byte_pool.h @@ -0,0 +1,177 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_byte_pool.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..c3fa8e44 --- /dev/null +++ b/common/inc/tx_event_flags.h @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_event_flags.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..f41eee48 --- /dev/null +++ b/common/inc/tx_initialize.h @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_initialize.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..4ee63e55 --- /dev/null +++ b/common/inc/tx_mutex.h @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_mutex.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..d6997cbc --- /dev/null +++ b/common/inc/tx_queue.h @@ -0,0 +1,173 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_queue.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..78a2f78f --- /dev/null +++ b/common/inc/tx_semaphore.h @@ -0,0 +1,144 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_semaphore.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..f7e462b7 --- /dev/null +++ b/common/inc/tx_thread.h @@ -0,0 +1,524 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_thread.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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. */ + +#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; + + +#ifdef TX_ENABLE_STACK_CHECKING + +/* Define the global function pointer for stack error handling. If a stack error is + detected and the application has registered a stack error handler, it will be + called via this function pointer. */ + +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 00000000..9d0522c9 --- /dev/null +++ b/common/inc/tx_timer.h @@ -0,0 +1,213 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_timer.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + +#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 00000000..f8e98cf7 --- /dev/null +++ b/common/inc/tx_trace.h @@ -0,0 +1,559 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* tx_trace.h PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ + + +/* 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 Express Logic. 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 00000000..8a2e5166 --- /dev/null +++ b/common/inc/tx_user_sample.h @@ -0,0 +1,257 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** User Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_user.h PORTABLE C */ +/* 6.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 */ +/* */ +/**************************************************************************/ + +#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_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 ???? +*/ + +/* 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 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. */ + +/* +#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 +*/ + +#endif + diff --git a/common/src/tx_block_allocate.c b/common/src/tx_block_allocate.c new file mode 100644 index 00000000..1035e681 --- /dev/null +++ b/common/src/tx_block_allocate.c @@ -0,0 +1,372 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_trace.h" +#endif +#include "tx_thread.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_allocate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6578e5c5 --- /dev/null +++ b/common/src/tx_block_pool_cleanup.c @@ -0,0 +1,213 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_cleanup PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..4d74cc03 --- /dev/null +++ b/common/src/tx_block_pool_create.c @@ -0,0 +1,213 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_create PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..8e52e444 --- /dev/null +++ b/common/src/tx_block_pool_delete.c @@ -0,0 +1,207 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..20b2d130 --- /dev/null +++ b/common/src/tx_block_pool_info_get.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..26c6a561 --- /dev/null +++ b/common/src/tx_block_pool_initialize.c @@ -0,0 +1,129 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" + + +#ifndef TX_INLINE_INITIALIZATION + +/* Locate block pool component data in this file. */ + +/* Define the head pointer of the created block pool list. */ + +TX_BLOCK_POOL * _tx_block_pool_created_ptr; + + +/* Define the variable that holds the number of created block pools. */ + +ULONG _tx_block_pool_created_count; + + +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO + +/* Define the total number of block allocates. */ + +ULONG _tx_block_pool_performance_allocate_count; + + +/* Define the total number of block releases. */ + +ULONG _tx_block_pool_performance_release_count; + + +/* Define the total number of block pool suspensions. */ + +ULONG _tx_block_pool_performance_suspension_count; + + +/* Define the total number of block pool timeouts. */ + +ULONG _tx_block_pool_performance_timeout_count; + +#endif +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block pool_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..9c0cf098 --- /dev/null +++ b/common/src/tx_block_pool_performance_info_get.c @@ -0,0 +1,201 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..317003b9 --- /dev/null +++ b/common/src/tx_block_pool_performance_system_info_get.c @@ -0,0 +1,173 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" +#ifdef TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..d78f53e5 --- /dev/null +++ b/common/src/tx_block_pool_prioritize.c @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ce69a53f --- /dev/null +++ b/common/src/tx_block_release.c @@ -0,0 +1,204 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_release PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..caa15f4c --- /dev/null +++ b/common/src/tx_byte_allocate.c @@ -0,0 +1,409 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_trace.h" +#endif +#include "tx_thread.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_allocate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..c013c2ae --- /dev/null +++ b/common/src/tx_byte_pool_cleanup.c @@ -0,0 +1,212 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_cleanup PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..7c19823c --- /dev/null +++ b/common/src/tx_byte_pool_create.c @@ -0,0 +1,197 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_create PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5e63ad45 --- /dev/null +++ b/common/src/tx_byte_pool_delete.c @@ -0,0 +1,211 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6797263c --- /dev/null +++ b/common/src/tx_byte_pool_info_get.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..7b1ce011 --- /dev/null +++ b/common/src/tx_byte_pool_initialize.c @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" + + +#ifndef TX_INLINE_INITIALIZATION + +/* Locate byte pool component data in this file. */ + +/* Define the head pointer of the created byte pool list. */ + +TX_BYTE_POOL * _tx_byte_pool_created_ptr; + + +/* Define the variable that holds the number of created byte pools. */ + +ULONG _tx_byte_pool_created_count; + + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + +/* Define the total number of allocates. */ + +ULONG _tx_byte_pool_performance_allocate_count; + + +/* Define the total number of releases. */ + +ULONG _tx_byte_pool_performance_release_count; + + +/* Define the total number of adjacent memory fragment merges. */ + +ULONG _tx_byte_pool_performance_merge_count; + + +/* Define the total number of memory fragment splits. */ + +ULONG _tx_byte_pool_performance_split_count; + + +/* Define the total number of memory fragments searched during allocation. */ + +ULONG _tx_byte_pool_performance_search_count; + + +/* Define the total number of byte pool suspensions. */ + +ULONG _tx_byte_pool_performance_suspension_count; + + +/* Define the total number of byte pool timeouts. */ + +ULONG _tx_byte_pool_performance_timeout_count; + +#endif +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..53af8211 --- /dev/null +++ b/common/src/tx_byte_pool_performance_info_get.c @@ -0,0 +1,253 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..02d0cc5b --- /dev/null +++ b/common/src/tx_byte_pool_performance_system_info_get.c @@ -0,0 +1,221 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..b39d6214 --- /dev/null +++ b/common/src/tx_byte_pool_prioritize.c @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3455d5f1 --- /dev/null +++ b/common/src/tx_byte_pool_search.c @@ -0,0 +1,350 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_search PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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; + + + /* Disable interrupts. */ + TX_DISABLE + + /* First, determine if there are enough bytes in the pool. */ + if (memory_size >= pool_ptr -> tx_byte_pool_available) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Not enough memory, return a NULL pointer. */ + current_ptr = TX_NULL; + } + else + { + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(thread_ptr) + + /* Setup ownership of the byte pool. */ + pool_ptr -> tx_byte_pool_owner = thread_ptr; + + /* Walk through the memory pool in search for a large enough block. */ + current_ptr = pool_ptr -> tx_byte_pool_search; + examine_blocks = pool_ptr -> tx_byte_pool_fragments + ((UINT) 1); + available_bytes = ((ULONG) 0); + do + { + + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + + /* Increment the total fragment search counter. */ + _tx_byte_pool_performance_search_count++; + + /* Increment the number of fragments searched on this pool. */ + pool_ptr -> tx_byte_pool_performance_search_count++; +#endif + + /* Check to see if this block is free. */ + work_ptr = TX_UCHAR_POINTER_ADD(current_ptr, (sizeof(UCHAR *))); + free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr); + if ((*free_ptr) == TX_BYTE_BLOCK_FREE) + { + + /* Determine if this is the first free block. */ + if (first_free_block_found == TX_FALSE) + { + + /* This is the first free block. */ + pool_ptr->tx_byte_pool_search = current_ptr; + + /* Set the flag to indicate we have found the first free + block. */ + first_free_block_found = TX_TRUE; + } + + /* Block is free, see if it is large enough. */ + + /* Pickup the next block's pointer. */ + this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr); + next_ptr = *this_block_link_ptr; + + /* Calculate the number of bytes available in this block. */ + available_bytes = TX_UCHAR_POINTER_DIF(next_ptr, current_ptr); + available_bytes = available_bytes - ((sizeof(UCHAR *)) + (sizeof(ALIGN_TYPE))); + + /* If this is large enough, we are done because our first-fit algorithm + has been satisfied! */ + if (available_bytes >= memory_size) + { + /* Get out of the search loop! */ + break; + } + else + { + + /* Clear the available bytes variable. */ + available_bytes = ((ULONG) 0); + + /* Not enough memory, check to see if the neighbor is + free and can be merged. */ + work_ptr = TX_UCHAR_POINTER_ADD(next_ptr, (sizeof(UCHAR *))); + free_ptr = TX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr); + if ((*free_ptr) == TX_BYTE_BLOCK_FREE) + { + + /* Yes, neighbor block can be merged! This is quickly accomplished + by updating the current block with the next blocks pointer. */ + next_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr); + *this_block_link_ptr = *next_block_link_ptr; + + /* Reduce the fragment total. We don't need to increase the bytes + available because all free headers are also included in the available + count. */ + pool_ptr -> tx_byte_pool_fragments--; + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + + /* Increment the total merge counter. */ + _tx_byte_pool_performance_merge_count++; + + /* Increment the number of blocks merged on this pool. */ + pool_ptr -> tx_byte_pool_performance_merge_count++; +#endif + + /* See if the search pointer is affected. */ + if (pool_ptr -> tx_byte_pool_search == next_ptr) + { + + /* Yes, update the search pointer. */ + pool_ptr -> tx_byte_pool_search = current_ptr; + } + } + else + { + + /* Neighbor is not free so we can skip over it! */ + next_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr); + current_ptr = *next_block_link_ptr; + + /* Decrement the examined block count to account for this one. */ + if (examine_blocks != ((UINT) 0)) + { + + examine_blocks--; + +#ifdef TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO + + /* Increment the total fragment search counter. */ + _tx_byte_pool_performance_search_count++; + + /* Increment the number of fragments searched on this pool. */ + pool_ptr -> tx_byte_pool_performance_search_count++; +#endif + } + } + } + } + else + { + + /* Block is not free, move to next block. */ + this_block_link_ptr = TX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr); + current_ptr = *this_block_link_ptr; + } + + /* Another block has been searched... decrement counter. */ + if (examine_blocks != ((UINT) 0)) + { + + examine_blocks--; + } + + /* 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 00000000..404f1eb0 --- /dev/null +++ b/common/src/tx_byte_release.c @@ -0,0 +1,376 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_release PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..1b58df24 --- /dev/null +++ b/common/src/tx_event_flags_cleanup.c @@ -0,0 +1,237 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_cleanup PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..aa0e7269 --- /dev/null +++ b/common/src/tx_event_flags_create.c @@ -0,0 +1,141 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_create PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..d495c938 --- /dev/null +++ b/common/src/tx_event_flags_delete.c @@ -0,0 +1,207 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ed3bba20 --- /dev/null +++ b/common/src/tx_event_flags_get.c @@ -0,0 +1,401 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +UINT _tx_event_flags_get(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG requested_flags, + UINT get_option, ULONG *actual_flags_ptr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +UINT and_request; +UINT clear_request; +ULONG current_flags; +ULONG flags_satisfied; +#ifndef TX_NOT_INTERRUPTABLE +ULONG delayed_clear_flags; +#endif +UINT suspended_count; +TX_THREAD *thread_ptr; +TX_THREAD *next_thread; +TX_THREAD *previous_thread; +#ifndef TX_NOT_INTERRUPTABLE +UINT interrupted_set_request; +#endif + + + /* Disable interrupts to examine the event flags group. */ + TX_DISABLE + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + + /* Increment the total event flags get counter. */ + _tx_event_flags_performance_get_count++; + + /* Increment the number of event flags gets on this semaphore. */ + group_ptr -> tx_event_flags_group__performance_get_count++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_GET, group_ptr, requested_flags, group_ptr -> tx_event_flags_group_current, get_option, TX_TRACE_EVENT_FLAGS_EVENTS) + + /* Log this kernel call. */ + TX_EL_EVENT_FLAGS_GET_INSERT + + /* Pickup current flags. */ + current_flags = group_ptr -> tx_event_flags_group_current; + + /* Apply the event flag option mask. */ + and_request = (get_option & TX_AND); + +#ifdef TX_NOT_INTERRUPTABLE + + /* Check for AND condition. All flags must be present to satisfy request. */ + if (and_request == TX_AND) + { + + /* AND request is present. */ + + /* Calculate the flags present. */ + flags_satisfied = (current_flags & requested_flags); + + /* Determine if they satisfy the AND request. */ + if (flags_satisfied != requested_flags) + { + + /* No, not all the requested flags are present. Clear the flags present variable. */ + flags_satisfied = ((ULONG) 0); + } + } + else + { + + /* OR request is present. Simply or the requested flags and the current flags. */ + flags_satisfied = (current_flags & requested_flags); + } + + /* Determine if the request is satisfied. */ + if (flags_satisfied != ((ULONG) 0)) + { + + /* Return the actual event flags that satisfied the request. */ + *actual_flags_ptr = current_flags; + + /* Pickup the clear bit. */ + clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK); + + /* Determine whether or not clearing needs to take place. */ + if (clear_request == TX_TRUE) + { + + /* Yes, clear the flags that satisfied this request. */ + group_ptr -> tx_event_flags_group_current = + group_ptr -> tx_event_flags_group_current & (~requested_flags); + } + + /* Return success. */ + status = TX_SUCCESS; + } + +#else + + /* Pickup delayed clear flags. */ + delayed_clear_flags = group_ptr -> tx_event_flags_group_delayed_clear; + + /* Determine if there are any delayed clear operations pending. */ + if (delayed_clear_flags != ((ULONG) 0)) + { + + /* Yes, apply them to the current flags. */ + current_flags = current_flags & (~delayed_clear_flags); + } + + /* Check for AND condition. All flags must be present to satisfy request. */ + if (and_request == TX_AND) + { + + /* AND request is present. */ + + /* Calculate the flags present. */ + flags_satisfied = (current_flags & requested_flags); + + /* Determine if they satisfy the AND request. */ + if (flags_satisfied != requested_flags) + { + + /* No, not all the requested flags are present. Clear the flags present variable. */ + flags_satisfied = ((ULONG) 0); + } + } + else + { + + /* OR request is present. Simply AND together the requested flags and the current flags + to see if any are present. */ + flags_satisfied = (current_flags & requested_flags); + } + + /* Determine if the request is satisfied. */ + if (flags_satisfied != ((ULONG) 0)) + { + + /* Yes, this request can be handled immediately. */ + + /* Return the actual event flags that satisfied the request. */ + *actual_flags_ptr = current_flags; + + /* Pickup the clear bit. */ + clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK); + + /* Determine whether or not clearing needs to take place. */ + if (clear_request == TX_TRUE) + { + + /* Set interrupted set request flag to false. */ + interrupted_set_request = TX_FALSE; + + /* Determine if the suspension list is being processed by an interrupted + set request. */ + if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS) + { + + if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL) + { + + /* Set the interrupted set request flag. */ + interrupted_set_request = TX_TRUE; + } + } + + /* Was a set request interrupted? */ + if (interrupted_set_request == TX_TRUE) + { + + /* A previous set operation is was interrupted, we need to defer the + event clearing until the set operation is complete. */ + + /* Remember the events to clear. */ + group_ptr -> tx_event_flags_group_delayed_clear = + group_ptr -> tx_event_flags_group_delayed_clear | requested_flags; + } + else + { + + /* Yes, clear the flags that satisfied this request. */ + group_ptr -> tx_event_flags_group_current = + group_ptr -> tx_event_flags_group_current & ~requested_flags; + } + } + + /* Set status to success. */ + status = TX_SUCCESS; + } + +#endif + else + { + + /* Determine if the request specifies suspension. */ + if (wait_option != TX_NO_WAIT) + { + + /* Determine if the preempt disable flag is non-zero. */ + if (_tx_thread_preempt_disable != ((UINT) 0)) + { + + /* Suspension is not allowed if the preempt disable flag is non-zero at this point, return error completion. */ + status = TX_NO_EVENTS; + } + else + { + + /* Prepare for suspension of this thread. */ + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + + /* Increment the total event flags suspensions counter. */ + _tx_event_flags_performance_suspension_count++; + + /* Increment the number of event flags suspensions on this semaphore. */ + group_ptr -> tx_event_flags_group___performance_suspension_count++; +#endif + + /* Pickup thread pointer. */ + TX_THREAD_GET_CURRENT(thread_ptr) + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = &(_tx_event_flags_cleanup); + + /* Remember which event flags we are looking for. */ + thread_ptr -> tx_thread_suspend_info = requested_flags; + + /* Save the get option as well. */ + thread_ptr -> tx_thread_suspend_option = get_option; + + /* Save the destination for the current events. */ + thread_ptr -> tx_thread_additional_suspend_info = (VOID *) actual_flags_ptr; + + /* Setup cleanup information, i.e. this event flags group control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (VOID *) group_ptr; + +#ifndef TX_NOT_INTERRUPTABLE + + /* Increment the suspension sequence number, which is used to identify + this suspension event. */ + thread_ptr -> tx_thread_suspension_sequence++; +#endif + + /* Pickup the suspended count. */ + suspended_count = group_ptr -> tx_event_flags_group_suspended_count; + + /* Setup suspension list. */ + if (suspended_count == TX_NO_SUSPENSIONS) + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + group_ptr -> tx_event_flags_group_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* This list is not NULL, add current thread to the end. */ + next_thread = group_ptr -> tx_event_flags_group_suspension_list; + thread_ptr -> tx_thread_suspended_next = next_thread; + previous_thread = next_thread -> tx_thread_suspended_previous; + thread_ptr -> tx_thread_suspended_previous = previous_thread; + previous_thread -> tx_thread_suspended_next = thread_ptr; + next_thread -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the number of threads suspended. */ + group_ptr -> tx_event_flags_group_suspended_count++; + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_EVENT_FLAG; + +#ifdef TX_NOT_INTERRUPTABLE + + /* Call actual non-interruptable thread suspension routine. */ + _tx_thread_system_ni_suspend(thread_ptr, wait_option); + + /* Return the completion status. */ + status = thread_ptr -> tx_thread_suspend_status; +#else + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Setup the timeout period. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); + + /* Disable interrupts. */ + TX_DISABLE + + /* Return the completion status. */ + status = thread_ptr -> tx_thread_suspend_status; +#endif + } + } + else + { + + /* Immediate return, return error completion. */ + status = TX_NO_EVENTS; + } + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(status); +} + 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 00000000..608be7df --- /dev/null +++ b/common/src/tx_event_flags_info_get.c @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..99800fe1 --- /dev/null +++ b/common/src/tx_event_flags_initialize.c @@ -0,0 +1,130 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" + + +#ifndef TX_INLINE_INITIALIZATION + +/* Locate event flags component data in this file. */ +/* Define the head pointer of the created event flags list. */ + +TX_EVENT_FLAGS_GROUP * _tx_event_flags_created_ptr; + + +/* Define the variable that holds the number of created event flag groups. */ + +ULONG _tx_event_flags_created_count; + + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + +/* Define the total number of event flag sets. */ + +ULONG _tx_event_flags_performance_set_count; + + +/* Define the total number of event flag gets. */ + +ULONG _tx_event_flags_performance_get_count; + + +/* Define the total number of event flag suspensions. */ + +ULONG _tx_event_flags_performance_suspension_count; + + +/* Define the total number of event flag timeouts. */ + +ULONG _tx_event_flags_performance_timeout_count; + + +#endif +#endif + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..5607469d --- /dev/null +++ b/common/src/tx_event_flags_performance_info_get.c @@ -0,0 +1,202 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..b421dd77 --- /dev/null +++ b/common/src/tx_event_flags_performance_system_info_get.c @@ -0,0 +1,174 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..aebe7d19 --- /dev/null +++ b/common/src/tx_event_flags_set.c @@ -0,0 +1,620 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_set PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +UINT _tx_event_flags_set(TX_EVENT_FLAGS_GROUP *group_ptr, ULONG flags_to_set, UINT set_option) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; +TX_THREAD *next_thread_ptr; +TX_THREAD *next_thread; +TX_THREAD *previous_thread; +TX_THREAD *satisfied_list; +TX_THREAD *last_satisfied; +TX_THREAD *suspended_list; +UINT suspended_count; +ULONG current_event_flags; +ULONG requested_flags; +ULONG flags_satisfied; +ULONG *suspend_info_ptr; +UINT and_request; +UINT get_option; +UINT clear_request; +UINT preempt_check; +#ifndef TX_NOT_INTERRUPTABLE +UINT interrupted_set_request; +#endif +#ifndef TX_DISABLE_NOTIFY_CALLBACKS +VOID (*events_set_notify)(struct TX_EVENT_FLAGS_GROUP_STRUCT *notify_group_ptr); +#endif + + + /* Disable interrupts to remove the semaphore from the created list. */ + TX_DISABLE + +#ifdef TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO + + /* Increment the total event flags set counter. */ + _tx_event_flags_performance_set_count++; + + /* Increment the number of event flags sets on this semaphore. */ + group_ptr -> tx_event_flags_group_performance_set_count++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_EVENT_FLAGS_SET, group_ptr, flags_to_set, set_option, group_ptr -> tx_event_flags_group_suspended_count, TX_TRACE_EVENT_FLAGS_EVENTS) + + /* Log this kernel call. */ + TX_EL_EVENT_FLAGS_SET_INSERT + + /* Determine how to set this group's event flags. */ + if ((set_option & TX_EVENT_FLAGS_AND_MASK) == TX_AND) + { + +#ifndef TX_NOT_INTERRUPTABLE + + /* Set interrupted set request flag to false. */ + interrupted_set_request = TX_FALSE; + + /* Determine if the suspension list is being processed by an interrupted + set request. */ + if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS) + { + + if (group_ptr -> tx_event_flags_group_suspension_list == TX_NULL) + { + + /* Set the interrupted set request flag. */ + interrupted_set_request = TX_TRUE; + } + } + + /* Was a set request interrupted? */ + if (interrupted_set_request == TX_TRUE) + { + + /* A previous set operation was interrupted, we need to defer the + event clearing until the set operation is complete. */ + + /* Remember the events to clear. */ + group_ptr -> tx_event_flags_group_delayed_clear = + group_ptr -> tx_event_flags_group_delayed_clear | ~flags_to_set; + } + else + { +#endif + + /* Previous set operation was not interrupted, simply clear the + specified flags by "ANDing" the flags into the current events + of the group. */ + group_ptr -> tx_event_flags_group_current = + group_ptr -> tx_event_flags_group_current & flags_to_set; + +#ifndef TX_NOT_INTERRUPTABLE + + } +#endif + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + +#ifndef TX_DISABLE_NOTIFY_CALLBACKS + + /* Pickup the notify callback routine for this event flag group. */ + events_set_notify = group_ptr -> tx_event_flags_group_set_notify; +#endif + + /* "OR" the flags into the current events of the group. */ + group_ptr -> tx_event_flags_group_current = + group_ptr -> tx_event_flags_group_current | flags_to_set; + +#ifndef TX_NOT_INTERRUPTABLE + + /* Determine if there are any delayed flags to clear. */ + if (group_ptr -> tx_event_flags_group_delayed_clear != ((ULONG) 0)) + { + + /* Yes, we need to neutralize the delayed clearing as well. */ + group_ptr -> tx_event_flags_group_delayed_clear = + group_ptr -> tx_event_flags_group_delayed_clear & ~flags_to_set; + } +#endif + + /* Clear the preempt check flag. */ + preempt_check = TX_FALSE; + + /* Pickup the thread suspended count. */ + suspended_count = group_ptr -> tx_event_flags_group_suspended_count; + + /* Determine if there are any threads suspended on the event flag group. */ + if (group_ptr -> tx_event_flags_group_suspension_list != TX_NULL) + { + + /* Determine if there is just a single thread waiting on the event + flag group. */ + if (suspended_count == ((UINT) 1)) + { + + /* Single thread waiting for event flags. Bypass the multiple thread + logic. */ + + /* Setup thread pointer. */ + thread_ptr = group_ptr -> tx_event_flags_group_suspension_list; + + /* Pickup the current event flags. */ + current_event_flags = group_ptr -> tx_event_flags_group_current; + + /* Pickup the suspend information. */ + requested_flags = thread_ptr -> tx_thread_suspend_info; + + /* Pickup the suspend option. */ + get_option = thread_ptr -> tx_thread_suspend_option; + + /* Isolate the AND selection. */ + and_request = (get_option & TX_AND); + + /* Check for AND condition. All flags must be present to satisfy request. */ + if (and_request == TX_AND) + { + + /* AND request is present. */ + + /* Calculate the flags present. */ + flags_satisfied = (current_event_flags & requested_flags); + + /* Determine if they satisfy the AND request. */ + if (flags_satisfied != requested_flags) + { + + /* No, not all the requested flags are present. Clear the flags present variable. */ + flags_satisfied = ((ULONG) 0); + } + } + else + { + + /* OR request is present. Simply or the requested flags and the current flags. */ + flags_satisfied = (current_event_flags & requested_flags); + } + + /* Determine if the request is satisfied. */ + if (flags_satisfied != ((ULONG) 0)) + { + + /* Yes, resume the thread and apply any event flag + clearing. */ + + /* Set the preempt check flag. */ + preempt_check = TX_TRUE; + + /* Return the actual event flags that satisfied the request. */ + suspend_info_ptr = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info); + *suspend_info_ptr = current_event_flags; + + /* Pickup the clear bit. */ + clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK); + + /* Determine whether or not clearing needs to take place. */ + if (clear_request == TX_TRUE) + { + + /* Yes, clear the flags that satisfied this request. */ + group_ptr -> tx_event_flags_group_current = group_ptr -> tx_event_flags_group_current & (~requested_flags); + } + + /* Clear the suspension information in the event flag group. */ + group_ptr -> tx_event_flags_group_suspension_list = TX_NULL; + group_ptr -> tx_event_flags_group_suspended_count = TX_NO_SUSPENSIONS; + + /* Clear cleanup routine to avoid timeout. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = TX_SUCCESS; + +#ifdef TX_NOT_INTERRUPTABLE + + /* Resume the thread! */ + _tx_thread_system_ni_resume(thread_ptr); +#else + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + + /* Disable interrupts to remove the semaphore from the created list. */ + TX_DISABLE +#endif + } + } + else + { + + /* Otherwise, the event flag requests of multiple threads must be + examined. */ + + /* Setup thread pointer, keep a local copy of the head pointer. */ + suspended_list = group_ptr -> tx_event_flags_group_suspension_list; + thread_ptr = suspended_list; + + /* Clear the suspended list head pointer to thwart manipulation of + the list in ISR's while we are processing here. */ + group_ptr -> tx_event_flags_group_suspension_list = TX_NULL; + + /* Setup the satisfied thread pointers. */ + satisfied_list = TX_NULL; + last_satisfied = TX_NULL; + + /* Pickup the current event flags. */ + current_event_flags = group_ptr -> tx_event_flags_group_current; + + /* Disable preemption while we process the suspended list. */ + _tx_thread_preempt_disable++; + + /* Loop to examine all of the suspended threads. */ + do + { + +#ifndef TX_NOT_INTERRUPTABLE + + /* Restore interrupts temporarily. */ + TX_RESTORE + + /* Disable interrupts again. */ + TX_DISABLE +#endif + + /* Determine if we need to reset the search. */ + if (group_ptr -> tx_event_flags_group_reset_search != TX_FALSE) + { + + /* Clear the reset search flag. */ + group_ptr -> tx_event_flags_group_reset_search = TX_FALSE; + + /* Move the thread pointer to the beginning of the search list. */ + thread_ptr = suspended_list; + + /* Reset the suspended count. */ + suspended_count = group_ptr -> tx_event_flags_group_suspended_count; + + /* Update the current events with any new ones that might + have been set in a nested set events call from an ISR. */ + current_event_flags = current_event_flags | group_ptr -> tx_event_flags_group_current; + } + + /* Save next thread pointer. */ + next_thread_ptr = thread_ptr -> tx_thread_suspended_next; + + /* Pickup the suspend information. */ + requested_flags = thread_ptr -> tx_thread_suspend_info; + + /* Pickup this thread's suspension get option. */ + get_option = thread_ptr -> tx_thread_suspend_option; + + /* Isolate the AND selection. */ + and_request = (get_option & TX_AND); + + /* Check for AND condition. All flags must be present to satisfy request. */ + if (and_request == TX_AND) + { + + /* AND request is present. */ + + /* Calculate the flags present. */ + flags_satisfied = (current_event_flags & requested_flags); + + /* Determine if they satisfy the AND request. */ + if (flags_satisfied != requested_flags) + { + + /* No, not all the requested flags are present. Clear the flags present variable. */ + flags_satisfied = ((ULONG) 0); + } + } + else + { + + /* OR request is present. Simply or the requested flags and the current flags. */ + flags_satisfied = (current_event_flags & requested_flags); + } + + /* Check to see if the thread had a timeout or wait abort during the event search processing. + If so, just set the flags satisfied to ensure the processing here removes the thread from + the suspension list. */ + if (thread_ptr -> tx_thread_state != TX_EVENT_FLAG) + { + + /* Simply set the satisfied flags to 1 in order to remove the thread from the suspension list. */ + flags_satisfied = ((ULONG) 1); + } + + /* Determine if the request is satisfied. */ + if (flags_satisfied != ((ULONG) 0)) + { + + /* Yes, this request can be handled now. */ + + /* Set the preempt check flag. */ + preempt_check = TX_TRUE; + + /* Determine if the thread is still suspended on the event flag group. If not, a wait + abort must have been done from an ISR. */ + if (thread_ptr -> tx_thread_state == TX_EVENT_FLAG) + { + + /* Return the actual event flags that satisfied the request. */ + suspend_info_ptr = TX_VOID_TO_ULONG_POINTER_CONVERT(thread_ptr -> tx_thread_additional_suspend_info); + *suspend_info_ptr = current_event_flags; + + /* Pickup the clear bit. */ + clear_request = (get_option & TX_EVENT_FLAGS_CLEAR_MASK); + + /* Determine whether or not clearing needs to take place. */ + if (clear_request == TX_TRUE) + { + + /* Yes, clear the flags that satisfied this request. */ + group_ptr -> tx_event_flags_group_current = group_ptr -> tx_event_flags_group_current & ~requested_flags; + } + + /* Prepare for resumption of the first thread. */ + + /* Clear cleanup routine to avoid timeout. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = TX_SUCCESS; + } + + /* We need to remove the thread from the suspension list and place it in the + expired list. */ + + /* See if this is the only suspended thread on the list. */ + if (thread_ptr == thread_ptr -> tx_thread_suspended_next) + { + + /* Yes, the only suspended thread. */ + + /* Update the head pointer. */ + suspended_list = TX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the links of the adjacent threads. */ + next_thread = thread_ptr -> tx_thread_suspended_next; + previous_thread = thread_ptr -> tx_thread_suspended_previous; + next_thread -> tx_thread_suspended_previous = previous_thread; + previous_thread -> tx_thread_suspended_next = next_thread; + + /* Update the list head pointer, if removing the head of the + list. */ + if (suspended_list == thread_ptr) + { + + /* Yes, head pointer needs to be updated. */ + suspended_list = thread_ptr -> tx_thread_suspended_next; + } + } + + /* Decrement the suspension count. */ + group_ptr -> tx_event_flags_group_suspended_count--; + + /* Place this thread on the expired list. */ + if (satisfied_list == TX_NULL) + { + + /* First thread on the satisfied list. */ + satisfied_list = thread_ptr; + last_satisfied = thread_ptr; + + /* Setup initial next pointer. */ + thread_ptr -> tx_thread_suspended_next = TX_NULL; + } + else + { + + /* Not the first thread on the satisfied list. */ + + /* Link it up at the end. */ + last_satisfied -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_next = TX_NULL; + last_satisfied = thread_ptr; + } + } + + /* Copy next thread pointer to working thread ptr. */ + thread_ptr = next_thread_ptr; + + /* Decrement the suspension count. */ + suspended_count--; + + } while (suspended_count != TX_NO_SUSPENSIONS); + + /* Setup the group's suspension list head again. */ + group_ptr -> tx_event_flags_group_suspension_list = suspended_list; + +#ifndef TX_NOT_INTERRUPTABLE + + /* Determine if there is any delayed event clearing to perform. */ + if (group_ptr -> tx_event_flags_group_delayed_clear != ((ULONG) 0)) + { + + /* Perform the delayed event clearing. */ + group_ptr -> tx_event_flags_group_current = + group_ptr -> tx_event_flags_group_current & ~(group_ptr -> tx_event_flags_group_delayed_clear); + + /* Clear the delayed event flag clear value. */ + group_ptr -> tx_event_flags_group_delayed_clear = ((ULONG) 0); + } +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* Walk through the satisfied list, setup initial thread pointer. */ + thread_ptr = satisfied_list; + while(thread_ptr != TX_NULL) + { + + /* Get next pointer first. */ + next_thread_ptr = thread_ptr -> tx_thread_suspended_next; + + /* Disable interrupts. */ + TX_DISABLE + +#ifdef TX_NOT_INTERRUPTABLE + + /* Resume the thread! */ + _tx_thread_system_ni_resume(thread_ptr); + + /* Restore interrupts. */ + TX_RESTORE +#else + + /* Disable preemption again. */ + _tx_thread_preempt_disable++; + + /* Restore interrupt posture. */ + TX_RESTORE + + /* Resume the thread. */ + _tx_thread_system_resume(thread_ptr); +#endif + + /* Move next thread to current. */ + thread_ptr = next_thread_ptr; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Release thread preemption disable. */ + _tx_thread_preempt_disable--; + } + } + else + { + + /* Determine if we need to set the reset search field. */ + if (group_ptr -> tx_event_flags_group_suspended_count != TX_NO_SUSPENSIONS) + { + + /* We interrupted a search of an event flag group suspension + list. Make sure we reset the search. */ + group_ptr -> tx_event_flags_group_reset_search = TX_TRUE; + } + } + + /* Restore interrupts. */ + TX_RESTORE + +#ifndef TX_DISABLE_NOTIFY_CALLBACKS + + /* Determine if a notify callback is required. */ + if (events_set_notify != TX_NULL) + { + + /* Call application event flags set notification. */ + (events_set_notify)(group_ptr); + } +#endif + + /* Determine if a check for preemption is necessary. */ + if (preempt_check == TX_TRUE) + { + + /* Yes, one or more threads were resumed, check for preemption. */ + _tx_thread_system_preempt_check(); + } + } + + /* Return completion status. */ + return(TX_SUCCESS); +} + 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 00000000..b65cd30b --- /dev/null +++ b/common/src/tx_event_flags_set_notify.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_event_flags_set_notify PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..12dbd143 --- /dev/null +++ b/common/src/tx_initialize_high_level.c @@ -0,0 +1,150 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" + +/* Determine if in-line initialization is required. */ +#ifdef TX_INLINE_INITIALIZATION +#define TX_INVOKE_INLINE_INITIALIZATION +#endif + +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_semaphore.h" +#include "tx_queue.h" +#include "tx_event_flags.h" +#include "tx_mutex.h" +#include "tx_block_pool.h" +#include "tx_byte_pool.h" + + +/* Define the unused memory pointer. The value of the first available + memory address is placed in this variable in the low-level + initialization function. The content of this variable is passed + to the application's system definition function. */ + +VOID *_tx_initialize_unused_memory; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_high_level PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5f9af949 --- /dev/null +++ b/common/src/tx_initialize_kernel_enter.c @@ -0,0 +1,148 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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" + + +/* 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.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 */ +/* */ +/**************************************************************************/ +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; + + /* 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 + + /* 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 00000000..b961007e --- /dev/null +++ b/common/src/tx_initialize_kernel_setup.c @@ -0,0 +1,100 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..814205a7 --- /dev/null +++ b/common/src/tx_misra.c @@ -0,0 +1,833 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** ThreadX MISRA Compliance */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** _tx_version_id */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifdef TX_MISRA_ENABLE +#define TX_THREAD_INIT +//CHAR _tx_version_id[100] = "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX 6.0 MISRA C Compliant *"; +#endif + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_memset(VOID *ptr, UINT value, UINT size) +{ + memset(ptr, value, size); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UCHAR *_tx_misra_uchar_pointer_add(UCHAR *ptr, ULONG amount) +{ + ptr = ptr + amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UCHAR *_tx_misra_uchar_pointer_sub(UCHAR *ptr, ULONG amount) +{ + ptr = ptr - amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_uchar_pointer_dif(UCHAR *ptr1, UCHAR *ptr2) +{ + +ULONG value; + + value = ptr1 - ptr2; + return(value); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_pointer_to_ulong_convert(VOID *ptr) +{ + return((ULONG) ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG *_tx_misra_ulong_pointer_add(ULONG *ptr, ULONG amount) +{ + ptr = ptr + amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG *_tx_misra_ulong_pointer_sub(ULONG *ptr, ULONG amount) +{ + + ptr = ptr - amount; + return(ptr); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_ulong_pointer_dif(ULONG *ptr1, ULONG *ptr2) +{ +ULONG value; + + value = ptr1 - ptr2; + return(value); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID *_tx_misra_ulong_to_pointer_convert(ULONG input); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID *_tx_misra_ulong_to_pointer_convert(ULONG input) +{ + + return((VOID *) input); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, */ +/** UINT size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_message_copy(ULONG **source, ULONG **destination, UINT size) +{ + +ULONG *s, *d; +UINT z; + + s = *source; + d = *destination; + z = size; + + *(d) = *(s); + (d)++; + (s)++; + if ((z) > ((UINT) 1)) + { + (z)--; + while ((z)) + { + *(d) = *(s); + (d)++; + (s)++; + (z)--; + } + } + + *source = s; + *destination = d; +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, */ +/** TX_TIMER_INTERNAL **ptr2); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_timer_pointer_dif(TX_TIMER_INTERNAL **ptr1, TX_TIMER_INTERNAL **ptr2) +{ + +ULONG value; + + value = ptr1 - ptr2; + return(value); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL */ +/** **ptr1, ULONG size); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +TX_TIMER_INTERNAL **_tx_misra_timer_pointer_add(TX_TIMER_INTERNAL **ptr1, ULONG amount) +{ + ptr1 = ptr1 + amount; + return(ptr1); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL */ +/** *internal_timer, TX_TIMER **user_timer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_user_timer_pointer_get(TX_TIMER_INTERNAL *internal_timer, TX_TIMER **user_timer) +{ + +UCHAR *working_ptr; +TX_TIMER *temp_timer; + + + working_ptr = (UCHAR *) internal_timer; + + temp_timer = (TX_TIMER *) working_ptr; + working_ptr = working_ptr - (((UCHAR *) &temp_timer -> tx_timer_internal) - ((UCHAR *) &temp_timer -> tx_timer_id)); + *user_timer = (TX_TIMER *) working_ptr; +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, */ +/** VOID **highest_stack); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_thread_stack_check(TX_THREAD *thread_ptr, VOID **highest_stack) +{ + +TX_INTERRUPT_SAVE_AREA + + TX_DISABLE + if (((thread_ptr)) && ((thread_ptr) -> tx_thread_id == TX_THREAD_ID)) + { + if (((ULONG *) (thread_ptr) -> tx_thread_stack_ptr) < ((ULONG *) *highest_stack)) + { + *highest_stack = (thread_ptr) -> tx_thread_stack_ptr; + } + if ((*((ULONG *) (thread_ptr) -> tx_thread_stack_start) != TX_STACK_FILL) || + (*((ULONG *) (((UCHAR *) (thread_ptr) -> tx_thread_stack_end) + 1)) != TX_STACK_FILL) || + (((ULONG *) *highest_stack) < ((ULONG *) (thread_ptr) -> tx_thread_stack_start))) + { + TX_RESTORE + _tx_thread_stack_error_handler((thread_ptr)); + TX_DISABLE + } + if (*(((ULONG *) *highest_stack) - 1) != TX_STACK_FILL) + { + TX_RESTORE + _tx_thread_stack_analyze((thread_ptr)); + TX_DISABLE + } + } + TX_RESTORE +} + + +#ifdef TX_ENABLE_EVENT_TRACE + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID _tx_misra_trace_event_insert(ULONG event_id, */ +/** VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, */ +/** ULONG info_field_4, ULONG filter, ULONG time_stamp); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID _tx_misra_trace_event_insert(ULONG event_id, VOID *info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4, ULONG filter, ULONG time_stamp) +{ + +TX_TRACE_BUFFER_ENTRY *trace_event_ptr; +ULONG trace_system_state; +ULONG trace_priority; +TX_THREAD *trace_thread_ptr; + + + trace_event_ptr = _tx_trace_buffer_current_ptr; + if ((trace_event_ptr) && (_tx_trace_event_enable_bits & ((ULONG) (filter)))) + { + TX_TRACE_PORT_EXTENSION + trace_system_state = (ULONG) _tx_thread_system_state; + trace_thread_ptr = _tx_thread_current_ptr; + + if (trace_system_state == 0) + { + trace_priority = trace_thread_ptr -> tx_thread_priority; + trace_priority = trace_priority | 0x80000000UL | (trace_thread_ptr -> tx_thread_preempt_threshold << 16); + } + else if (trace_system_state < 0xF0F0F0F0UL) + { + trace_priority = (ULONG) trace_thread_ptr; + trace_thread_ptr = (TX_THREAD *) 0xFFFFFFFFUL; + } + else + { + trace_thread_ptr = (TX_THREAD *) 0xF0F0F0F0UL; + trace_priority = 0; + } + trace_event_ptr -> tx_trace_buffer_entry_thread_pointer = (ULONG) trace_thread_ptr; + trace_event_ptr -> tx_trace_buffer_entry_thread_priority = (ULONG) trace_priority; + trace_event_ptr -> tx_trace_buffer_entry_event_id = (ULONG) (event_id); + trace_event_ptr -> tx_trace_buffer_entry_time_stamp = (ULONG) (time_stamp); +#ifdef TX_MISRA_ENABLE + trace_event_ptr -> tx_trace_buffer_entry_info_1 = (ULONG) (info_field_1); + trace_event_ptr -> tx_trace_buffer_entry_info_2 = (ULONG) (info_field_2); + trace_event_ptr -> tx_trace_buffer_entry_info_3 = (ULONG) (info_field_3); + trace_event_ptr -> tx_trace_buffer_entry_info_4 = (ULONG) (info_field_4); +#else + trace_event_ptr -> tx_trace_buffer_entry_information_field_1 = (ULONG) (info_field_1); + trace_event_ptr -> tx_trace_buffer_entry_information_field_2 = (ULONG) (info_field_2); + trace_event_ptr -> tx_trace_buffer_entry_information_field_3 = (ULONG) (info_field_3); + trace_event_ptr -> tx_trace_buffer_entry_information_field_4 = (ULONG) (info_field_4); +#endif + trace_event_ptr++; + if (trace_event_ptr >= _tx_trace_buffer_end_ptr) + { + trace_event_ptr = _tx_trace_buffer_start_ptr; + _tx_trace_buffer_current_ptr = trace_event_ptr; + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr; + if (_tx_trace_full_notify_function) + (_tx_trace_full_notify_function)((VOID *) _tx_trace_header_ptr); + } + else + { + _tx_trace_buffer_current_ptr = trace_event_ptr; + _tx_trace_header_ptr -> tx_trace_header_buffer_current_pointer = (ULONG) trace_event_ptr; + } + } +} + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ULONG _tx_misra_time_stamp_get(VOID); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +ULONG _tx_misra_time_stamp_get(VOID) +{ + + /* Return time stamp. */ + return(0); +} + +#endif + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_always_true(void); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UINT _tx_misra_always_true(void) +{ + return(TX_TRUE); +} + + +/******************************************************************************************/ +/******************************************************************************************/ +/** */ +/** UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr); */ +/** */ +/******************************************************************************************/ +/******************************************************************************************/ +UCHAR **_tx_misra_indirect_void_to_uchar_pointer_convert(VOID **return_ptr) +{ + + /* Return an indirect UCHAR pointer. */ + return((UCHAR **) ((VOID *) return_ptr)); +} + + +/***************************************************************************************/ +/***************************************************************************************/ +/** */ +/** UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer); */ +/** */ +/***************************************************************************************/ +/***************************************************************************************/ +UCHAR **_tx_misra_uchar_to_indirect_uchar_pointer_convert(UCHAR *pointer) +{ + + /* Return an indirect UCHAR pointer. */ + return((UCHAR **) ((VOID *) pointer)); +} + + +/***********************************************************************************/ +/***********************************************************************************/ +/** */ +/** UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool); */ +/** */ +/***********************************************************************************/ +/***********************************************************************************/ +UCHAR *_tx_misra_block_pool_to_uchar_pointer_convert(TX_BLOCK_POOL *pool) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pool)); +} + + +/******************************************************************************************/ +/******************************************************************************************/ +/** */ +/** TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer); */ +/** */ +/******************************************************************************************/ +/******************************************************************************************/ +TX_BLOCK_POOL *_tx_misra_void_to_block_pool_pointer_convert(VOID *pointer) +{ + + /* Return a block pool pointer. */ + return((TX_BLOCK_POOL *) ((VOID *) pointer)); +} + + +/*****************************************************************************/ +/*****************************************************************************/ +/** */ +/** UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer); */ +/** */ +/*****************************************************************************/ +/*****************************************************************************/ +UCHAR *_tx_misra_void_to_uchar_pointer_convert(VOID *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + + +/************************************************************************************/ +/************************************************************************************/ +/** */ +/** TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer); */ +/** */ +/************************************************************************************/ +/************************************************************************************/ +TX_BLOCK_POOL *_tx_misra_uchar_to_block_pool_pointer_convert(UCHAR *pointer) +{ + + /* Return a UCHAR pointer. */ + return((TX_BLOCK_POOL *) ((VOID *) pointer)); +} + + +/**************************************************************************************/ +/**************************************************************************************/ +/** */ +/** UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer); */ +/** */ +/**************************************************************************************/ +/**************************************************************************************/ +UCHAR **_tx_misra_void_to_indirect_uchar_pointer_convert(VOID *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR **) ((VOID *) pointer)); +} + + +/*****************************************************************************************/ +/*****************************************************************************************/ +/** */ +/** TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer); */ +/** */ +/*****************************************************************************************/ +/*****************************************************************************************/ +TX_BYTE_POOL *_tx_misra_void_to_byte_pool_pointer_convert(VOID *pointer) +{ + + /* Return a byte pool pointer. */ + return((TX_BYTE_POOL *) ((VOID *) pointer)); +} + + +/***************************************************************************************/ +/***************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool); */ +/** */ +/***************************************************************************************/ +/***************************************************************************************/ +UCHAR *_tx_misra_byte_pool_to_uchar_pointer_convert(TX_BYTE_POOL *pool) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pool)); +} + + +/*****************************************************************************************/ +/*****************************************************************************************/ +/** */ +/** ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer); */ +/** */ +/*****************************************************************************************/ +/*****************************************************************************************/ +ALIGN_TYPE *_tx_misra_uchar_to_align_type_pointer_convert(UCHAR *pointer) +{ + + /* Return an align time pointer. */ + return((ALIGN_TYPE *) ((VOID *) pointer)); +} + + +/****************************************************************************************************/ +/****************************************************************************************************/ +/** */ +/** TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer); */ +/** */ +/****************************************************************************************************/ +/****************************************************************************************************/ +TX_BYTE_POOL **_tx_misra_uchar_to_indirect_byte_pool_pointer_convert(UCHAR *pointer) +{ + + /* Return a byte pool pointer. */ + return((TX_BYTE_POOL **) ((VOID *) pointer)); +} + + +/**************************************************************************************************/ +/**************************************************************************************************/ +/** */ +/** TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer); */ +/** */ +/**************************************************************************************************/ +/**************************************************************************************************/ +TX_EVENT_FLAGS_GROUP *_tx_misra_void_to_event_flags_pointer_convert(VOID *pointer) +{ + + /* Return event flags pointer. */ + return((TX_EVENT_FLAGS_GROUP *) ((VOID *) pointer)); +} + + +/*****************************************************************************/ +/*****************************************************************************/ +/** */ +/** ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer); */ +/** */ +/*****************************************************************************/ +/*****************************************************************************/ +ULONG *_tx_misra_void_to_ulong_pointer_convert(VOID *pointer) +{ + + /* Return a ULONG pointer. */ + return((ULONG *) ((VOID *) pointer)); +} + + +/********************************************************************************/ +/********************************************************************************/ +/** */ +/** TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer); */ +/** */ +/********************************************************************************/ +/********************************************************************************/ +TX_MUTEX *_tx_misra_void_to_mutex_pointer_convert(VOID *pointer) +{ + + /* Return a mutex pointer. */ + return((TX_MUTEX *) ((VOID *) pointer)); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** UINT _tx_misra_status_get(UINT status); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +UINT _tx_misra_status_get(UINT status) +{ + + /* Return a successful status. */ + return(TX_SUCCESS); +} + + +/********************************************************************************/ +/********************************************************************************/ +/** */ +/** TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer); */ +/** */ +/********************************************************************************/ +/********************************************************************************/ +TX_QUEUE *_tx_misra_void_to_queue_pointer_convert(VOID *pointer) +{ + + /* Return queue pointer. */ + return((TX_QUEUE *) ((VOID *) pointer)); +} + + +/****************************************************************************************/ +/****************************************************************************************/ +/** */ +/** TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer); */ +/** */ +/****************************************************************************************/ +/****************************************************************************************/ +TX_SEMAPHORE *_tx_misra_void_to_semaphore_pointer_convert(VOID *pointer) +{ + + /* Return semaphore pointer. */ + return((TX_SEMAPHORE *) ((VOID *) pointer)); +} + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer); */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +VOID *_tx_misra_uchar_to_void_pointer_convert(UCHAR *pointer) +{ + + /* Return a VOID pointer. */ + return((VOID *) ((VOID *) pointer)); +} + + +/*********************************************************************************/ +/*********************************************************************************/ +/** */ +/** TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value); */ +/** */ +/*********************************************************************************/ +/*********************************************************************************/ +TX_THREAD *_tx_misra_ulong_to_thread_pointer_convert(ULONG value) +{ + + /* Return a thread pointer. */ + return((TX_THREAD *) ((VOID *) value)); +} + + +/***************************************************************************************************/ +/***************************************************************************************************/ +/** */ +/** VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer); */ +/** */ +/***************************************************************************************************/ +/***************************************************************************************************/ +VOID *_tx_misra_timer_indirect_to_void_pointer_convert(TX_TIMER_INTERNAL **pointer) +{ + + /* Return a void pointer. */ + return((VOID *) ((VOID *) pointer)); +} + + +/***************************************************************************************/ +/***************************************************************************************/ +/** */ +/** CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer); */ +/** */ +/***************************************************************************************/ +/***************************************************************************************/ +CHAR *_tx_misra_const_char_to_char_pointer_convert(const char *pointer) +{ + + /* Return a CHAR pointer. */ + return((CHAR *) ((VOID *) pointer)); +} + + +/**********************************************************************************/ +/**********************************************************************************/ +/** */ +/** TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer); */ +/** */ +/**********************************************************************************/ +/**********************************************************************************/ +TX_THREAD *_tx_misra_void_to_thread_pointer_convert(void *pointer) +{ + + /* Return thread pointer. */ + return((TX_THREAD *) ((VOID *) pointer)); +} + + +#ifdef TX_ENABLE_EVENT_TRACE + +/************************************************************************************************/ +/************************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer); */ +/** */ +/************************************************************************************************/ +/************************************************************************************************/ +UCHAR *_tx_misra_object_to_uchar_pointer_convert(TX_TRACE_OBJECT_ENTRY *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + + +/************************************************************************************************/ +/************************************************************************************************/ +/** */ +/** TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer); */ +/** */ +/************************************************************************************************/ +/************************************************************************************************/ +TX_TRACE_OBJECT_ENTRY *_tx_misra_uchar_to_object_pointer_convert(UCHAR *pointer) +{ + + /* Return an object entry pointer. */ + return((TX_TRACE_OBJECT_ENTRY *) ((VOID *) pointer)); +} + + +/******************************************************************************************/ +/******************************************************************************************/ +/** */ +/** TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer); */ +/** */ +/******************************************************************************************/ +/******************************************************************************************/ +TX_TRACE_HEADER *_tx_misra_uchar_to_header_pointer_convert(UCHAR *pointer) +{ + + /* Return a trace header pointer. */ + return((TX_TRACE_HEADER *) ((VOID *) pointer)); +} + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ +TX_TRACE_BUFFER_ENTRY *_tx_misra_uchar_to_entry_pointer_convert(UCHAR *pointer) +{ + + /* Return a trace buffer entry pointer. */ + return((TX_TRACE_BUFFER_ENTRY *) ((VOID *) pointer)); +} + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ +UCHAR *_tx_misra_entry_to_uchar_pointer_convert(TX_TRACE_BUFFER_ENTRY *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + +#endif + + +/***********************************************************************************************/ +/***********************************************************************************************/ +/** */ +/** UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer); */ +/** */ +/***********************************************************************************************/ +/***********************************************************************************************/ +UCHAR *_tx_misra_char_to_uchar_pointer_convert(CHAR *pointer) +{ + + /* Return a UCHAR pointer. */ + return((UCHAR *) ((VOID *) pointer)); +} + + + diff --git a/common/src/tx_mutex_cleanup.c b/common/src/tx_mutex_cleanup.c new file mode 100644 index 00000000..f076c772 --- /dev/null +++ b/common/src/tx_mutex_cleanup.c @@ -0,0 +1,313 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_cleanup PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +VOID _tx_mutex_cleanup(TX_THREAD *thread_ptr, ULONG suspension_sequence) +{ + +#ifndef TX_NOT_INTERRUPTABLE +TX_INTERRUPT_SAVE_AREA +#endif + +TX_MUTEX *mutex_ptr; +UINT suspended_count; +TX_THREAD *next_thread; +TX_THREAD *previous_thread; + + +#ifndef TX_NOT_INTERRUPTABLE + + /* Disable interrupts to remove the suspended thread from the mutex. */ + TX_DISABLE + + /* Determine if the cleanup is still required. */ + if (thread_ptr -> tx_thread_suspend_cleanup == &(_tx_mutex_cleanup)) + { + + /* Check for valid suspension sequence. */ + if (suspension_sequence == thread_ptr -> tx_thread_suspension_sequence) + { + + /* Setup pointer to mutex control block. */ + mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block); + + /* Check for NULL mutex pointer. */ + if (mutex_ptr != TX_NULL) + { + + /* Determine if the mutex ID is valid. */ + if (mutex_ptr -> tx_mutex_id == TX_MUTEX_ID) + { + + /* Determine if there are any thread suspensions. */ + if (mutex_ptr -> tx_mutex_suspended_count != TX_NO_SUSPENSIONS) + { +#else + + /* Setup pointer to mutex control block. */ + mutex_ptr = TX_VOID_TO_MUTEX_POINTER_CONVERT(thread_ptr -> tx_thread_suspend_control_block); +#endif + + /* Yes, we still have thread suspension! */ + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Decrement the suspension count. */ + mutex_ptr -> tx_mutex_suspended_count--; + + /* Pickup the suspended count. */ + suspended_count = mutex_ptr -> tx_mutex_suspended_count; + + /* Remove the suspended thread from the list. */ + + /* See if this is the only suspended thread on the list. */ + if (suspended_count == TX_NO_SUSPENSIONS) + { + + /* Yes, the only suspended thread. */ + + /* Update the head pointer. */ + mutex_ptr -> tx_mutex_suspension_list = TX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the links of the adjacent threads. */ + next_thread = thread_ptr -> tx_thread_suspended_next; + previous_thread = thread_ptr -> tx_thread_suspended_previous; + next_thread -> tx_thread_suspended_previous = previous_thread; + previous_thread -> tx_thread_suspended_next = next_thread; + + /* Determine if we need to update the head pointer. */ + if (mutex_ptr -> tx_mutex_suspension_list == thread_ptr) + { + + /* Update the list head pointer. */ + mutex_ptr -> tx_mutex_suspension_list = next_thread; + } + } + + /* Now we need to determine if this cleanup is from a terminate, timeout, + or from a wait abort. */ + if (thread_ptr -> tx_thread_state == TX_MUTEX_SUSP) + { + + /* Timeout condition and the thread still suspended on the mutex. + Setup return error status and resume the thread. */ + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + + /* Increment the total timeouts counter. */ + _tx_mutex_performance_timeout_count++; + + /* Increment the number of timeouts on this semaphore. */ + mutex_ptr -> tx_mutex_performance_timeout_count++; +#endif + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = TX_NOT_AVAILABLE; + +#ifdef TX_NOT_INTERRUPTABLE + + /* Resume the thread! */ + _tx_thread_system_ni_resume(thread_ptr); +#else + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Resume the thread! */ + _tx_thread_system_resume(thread_ptr); + + /* Disable interrupts. */ + TX_DISABLE +#endif + } +#ifndef TX_NOT_INTERRUPTABLE + } + } + } + } + } + + /* Restore interrupts. */ + TX_RESTORE +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_thread_release PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3b70289d --- /dev/null +++ b/common/src/tx_mutex_create.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_trace.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_create PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..0b2dc079 --- /dev/null +++ b/common/src/tx_mutex_delete.c @@ -0,0 +1,243 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..1d805c84 --- /dev/null +++ b/common/src/tx_mutex_get.c @@ -0,0 +1,409 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..a148850b --- /dev/null +++ b/common/src/tx_mutex_info_get.c @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3b546ee7 --- /dev/null +++ b/common/src/tx_mutex_initialize.c @@ -0,0 +1,141 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" + + +#ifndef TX_INLINE_INITIALIZATION + +/* Locate mutex component data in this file. */ + +/* Define the head pointer of the created mutex list. */ + +TX_MUTEX * _tx_mutex_created_ptr; + + +/* Define the variable that holds the number of created mutexes. */ + +ULONG _tx_mutex_created_count; + + +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO + +/* Define the total number of mutex puts. */ + +ULONG _tx_mutex_performance_put_count; + + +/* Define the total number of mutex gets. */ + +ULONG _tx_mutex_performance_get_count; + + +/* Define the total number of mutex suspensions. */ + +ULONG _tx_mutex_performance_suspension_count; + + +/* Define the total number of mutex timeouts. */ + +ULONG _tx_mutex_performance_timeout_count; + + +/* Define the total number of priority inversions. */ + +ULONG _tx_mutex_performance_priority_inversion_count; + + +/* Define the total number of priority inheritance conditions. */ + +ULONG _tx_mutex_performance__priority_inheritance_count; + +#endif +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..3dbd35e4 --- /dev/null +++ b/common/src/tx_mutex_performance_info_get.c @@ -0,0 +1,230 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..f2cb61fb --- /dev/null +++ b/common/src/tx_mutex_performance_system_info_get.c @@ -0,0 +1,205 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" +#ifdef TX_MUTEX_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..dddc7e54 --- /dev/null +++ b/common/src/tx_mutex_prioritize.c @@ -0,0 +1,265 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6bb905d1 --- /dev/null +++ b/common/src/tx_mutex_priority_change.c @@ -0,0 +1,328 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_priority_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 suspended. */ + thread_ptr -> tx_thread_state = TX_SUSPENDED; + + /* Call actual non-interruptable thread suspension routine. */ + _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0)); + + /* At this point, the preempt disable flag is still set, so we still have + protection against all preemption. */ + + /* Change thread priority to the new mutex priority-inheritance priority. */ + thread_ptr -> tx_thread_priority = new_priority; + + /* Determine how to setup the thread's preemption-threshold. */ + if (thread_ptr -> tx_thread_user_preempt_threshold < new_priority) + { + + /* Change thread preemption-threshold to the user's preemption-threshold. */ + thread_ptr -> tx_thread_preempt_threshold = thread_ptr -> tx_thread_user_preempt_threshold; + } + else + { + + /* Change the thread preemption-threshold to the new threshold. */ + thread_ptr -> tx_thread_preempt_threshold = new_priority; + } + + /* Resume the thread with the new priority. */ + _tx_thread_system_ni_resume(thread_ptr); + + /* Decrement the preempt disable flag. */ + _tx_thread_preempt_disable--; +#else + + /* Increment the preempt disable flag. */ + _tx_thread_preempt_disable = _tx_thread_preempt_disable + ((UINT) 2); + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_SUSPENDED; + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Setup the timeout period. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = ((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 = (next_execute_ptr -> tx_thread_priority)/ ((UINT) 32); + + /* Set the active bit to remember that the preempt map has something set. */ + TX_DIV32_BIT_SET(next_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(next_execute_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 00000000..93cfad07 --- /dev/null +++ b/common/src/tx_mutex_put.c @@ -0,0 +1,654 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_put PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6583ec6e --- /dev/null +++ b/common/src/tx_queue_cleanup.c @@ -0,0 +1,225 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_cleanup PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ae105019 --- /dev/null +++ b/common/src/tx_queue_create.c @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_create PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..343af731 --- /dev/null +++ b/common/src/tx_queue_delete.c @@ -0,0 +1,206 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ca338e8a --- /dev/null +++ b/common/src/tx_queue_flush.c @@ -0,0 +1,205 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_flush PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3becd09d --- /dev/null +++ b/common/src/tx_queue_front_send.c @@ -0,0 +1,421 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_front_send PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..e0496929 --- /dev/null +++ b/common/src/tx_queue_info_get.c @@ -0,0 +1,145 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..0e9bb622 --- /dev/null +++ b/common/src/tx_queue_initialize.c @@ -0,0 +1,138 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +#ifndef TX_INLINE_INITIALIZATION + +/* Define the head pointer of the created queue list. */ + +TX_QUEUE * _tx_queue_created_ptr; + + +/* Define the variable that holds the number of created queues. */ + +ULONG _tx_queue_created_count; + + +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO + +/* Define the total number of messages sent. */ + +ULONG _tx_queue_performance_messages_sent_count; + + +/* Define the total number of messages received. */ + +ULONG _tx_queue_performance__messages_received_count; + + +/* Define the total number of queue empty suspensions. */ + +ULONG _tx_queue_performance_empty_suspension_count; + + +/* Define the total number of queue full suspensions. */ + +ULONG _tx_queue_performance_full_suspension_count; + + +/* Define the total number of queue full errors. */ + +ULONG _tx_queue_performance_full_error_count; + + +/* Define the total number of queue timeouts. */ + +ULONG _tx_queue_performance_timeout_count; + +#endif +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..48d561b4 --- /dev/null +++ b/common/src/tx_queue_performance_info_get.c @@ -0,0 +1,229 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ebc58815 --- /dev/null +++ b/common/src/tx_queue_performance_system_info_get.c @@ -0,0 +1,205 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" +#ifdef TX_QUEUE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..632e03b6 --- /dev/null +++ b/common/src/tx_queue_prioritize.c @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..72555df8 --- /dev/null +++ b/common/src/tx_queue_receive.c @@ -0,0 +1,486 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_receive PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..4d242947 --- /dev/null +++ b/common/src/tx_queue_send.c @@ -0,0 +1,426 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_send PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..67b26dea --- /dev/null +++ b/common/src/tx_queue_send_notify.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_queue_send_notify PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..7b101228 --- /dev/null +++ b/common/src/tx_semaphore_ceiling_put.c @@ -0,0 +1,243 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_ceiling_put PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..498f9d7d --- /dev/null +++ b/common/src/tx_semaphore_cleanup.c @@ -0,0 +1,215 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_cleanup PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..377a7777 --- /dev/null +++ b/common/src/tx_semaphore_create.c @@ -0,0 +1,142 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_create PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..a8297463 --- /dev/null +++ b/common/src/tx_semaphore_delete.c @@ -0,0 +1,207 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..9e1072dc --- /dev/null +++ b/common/src/tx_semaphore_get.c @@ -0,0 +1,232 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..8f983072 --- /dev/null +++ b/common/src/tx_semaphore_info_get.c @@ -0,0 +1,139 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ff97845c --- /dev/null +++ b/common/src/tx_semaphore_initialize.c @@ -0,0 +1,129 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +#ifndef TX_INLINE_INITIALIZATION + +/* Locate semaphore component data in this file. */ + +/* Define the head pointer of the created semaphore list. */ + +TX_SEMAPHORE * _tx_semaphore_created_ptr; + + +/* Define the variable that holds the number of created semaphores. */ + +ULONG _tx_semaphore_created_count; + + +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO + +/* Define the total number of semaphore puts. */ + +ULONG _tx_semaphore_performance_put_count; + + +/* Define the total number of semaphore gets. */ + +ULONG _tx_semaphore_performance_get_count; + + +/* Define the total number of semaphore suspensions. */ + +ULONG _tx_semaphore_performance_suspension_count; + + +/* Define the total number of semaphore timeouts. */ + +ULONG _tx_semaphore_performance_timeout_count; + +#endif +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..fcef0321 --- /dev/null +++ b/common/src/tx_semaphore_performance_info_get.c @@ -0,0 +1,201 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6d37b310 --- /dev/null +++ b/common/src/tx_semaphore_performance_system_info_get.c @@ -0,0 +1,174 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" +#ifdef TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..0072b7e6 --- /dev/null +++ b/common/src/tx_semaphore_prioritize.c @@ -0,0 +1,251 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..09ae09cb --- /dev/null +++ b/common/src/tx_semaphore_put.c @@ -0,0 +1,222 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_put PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..b5b71e7f --- /dev/null +++ b/common/src/tx_semaphore_put_notify.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_put_notify PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..4169d362 --- /dev/null +++ b/common/src/tx_thread_create.c @@ -0,0 +1,360 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_initialize.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_create PORTABLE C */ +/* 6.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 */ +/* */ +/**************************************************************************/ +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 +ULONG new_stack_start; +ULONG updated_stack_start; +#endif + +#ifndef TX_DISABLE_STACK_FILLING + + /* Set the thread stack to a pattern prior to creating the initial + stack frame. This pattern is used by the stack checking routines + to see how much has been used. */ + TX_MEMSET(stack_start, ((UCHAR) TX_STACK_FILL), stack_size); +#endif + +#ifdef TX_ENABLE_STACK_CHECKING + + /* Ensure that there are two ULONG of 0xEF patterns at the top and + bottom of the thread's stack. This will be used to check for stack + overflow conditions during run-time. */ + stack_size = ((stack_size/(sizeof(ULONG))) * (sizeof(ULONG))) - (sizeof(ULONG)); + + /* Ensure the starting stack address is evenly aligned. */ + new_stack_start = TX_POINTER_TO_ULONG_CONVERT(stack_start); + updated_stack_start = ((((ULONG) new_stack_start) + ((sizeof(ULONG)) - ((ULONG) 1)) ) & (~((sizeof(ULONG)) - ((ULONG) 1)))); + + /* Determine if the starting stack address is different. */ + if (new_stack_start != updated_stack_start) + { + + /* Yes, subtract another ULONG from the size to avoid going past the stack area. */ + stack_size = stack_size - (sizeof(ULONG)); + } + + /* Update the starting stack pointer. */ + stack_start = TX_ULONG_TO_POINTER_CONVERT(updated_stack_start); +#endif + + /* Prepare the thread control block prior to placing it on the created + list. */ + + /* Initialize thread control block to all zeros. */ + TX_MEMSET(thread_ptr, 0, (sizeof(TX_THREAD))); + + /* Place the supplied parameters into the thread's control block. */ + thread_ptr -> tx_thread_name = name_ptr; + thread_ptr -> tx_thread_entry = entry_function; + thread_ptr -> tx_thread_entry_parameter = entry_input; + thread_ptr -> tx_thread_stack_start = stack_start; + thread_ptr -> tx_thread_stack_size = stack_size; + thread_ptr -> tx_thread_priority = priority; + thread_ptr -> tx_thread_user_priority = priority; + thread_ptr -> tx_thread_time_slice = time_slice; + thread_ptr -> tx_thread_new_time_slice = time_slice; + thread_ptr -> tx_thread_inherit_priority = ((UINT) TX_MAX_PRIORITIES); + + /* 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 00000000..3d384966 --- /dev/null +++ b/common/src/tx_thread_delete.c @@ -0,0 +1,166 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..273864f2 --- /dev/null +++ b/common/src/tx_thread_entry_exit_notify.c @@ -0,0 +1,109 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_entry_exit_notify PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..49f9b338 --- /dev/null +++ b/common/src/tx_thread_identify.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_trace.h" +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_identify PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..1f0acc83 --- /dev/null +++ b/common/src/tx_thread_info_get.c @@ -0,0 +1,163 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..99127066 --- /dev/null +++ b/common/src/tx_thread_initialize.c @@ -0,0 +1,448 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +#ifndef TX_MISRA_ENABLE +#define TX_THREAD_INIT +#endif + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" + + +/* Define the pointer that contains the system stack pointer. This is + utilized when control returns from a thread to the system to reset the + current stack. This is setup in the low-level initialization function. */ + +VOID * _tx_thread_system_stack_ptr; + + +/* Define the current thread pointer. This variable points to the currently + executing thread. If this variable is NULL, no thread is executing. */ + +TX_THREAD * _tx_thread_current_ptr; + + +/* Define the variable that holds the next thread to execute. It is important + to remember that this is not necessarily equal to the current thread + pointer. */ + +TX_THREAD * _tx_thread_execute_ptr; + + +/* Define the head pointer of the created thread list. */ + +TX_THREAD * _tx_thread_created_ptr; + + +/* Define the variable that holds the number of created threads. */ + +ULONG _tx_thread_created_count; + + +/* Define the current state variable. When this value is 0, a thread + is executing or the system is idle. Other values indicate that + interrupt or initialization processing is active. This variable is + initialized to TX_INITIALIZE_IN_PROGRESS to indicate initialization is + active. */ + +volatile ULONG _tx_thread_system_state = TX_INITIALIZE_IN_PROGRESS; + + +/* Define the 32-bit priority bit-maps. There is one priority bit map for each + 32 priority levels supported. If only 32 priorities are supported there is + only one bit map. Each bit within a priority bit map represents that one + or more threads at the associated thread priority are ready. */ + +ULONG _tx_thread_priority_maps[TX_MAX_PRIORITIES/32]; + + +/* Define the priority map active bit map that specifies which of the previously + defined priority maps have something set. This is only necessary if more than + 32 priorities are supported. */ + +#if TX_MAX_PRIORITIES > 32 +ULONG _tx_thread_priority_map_active; +#endif + + +#ifndef TX_DISABLE_PREEMPTION_THRESHOLD + +/* Define the 32-bit preempt priority bit maps. There is one preempt bit map + for each 32 priority levels supported. If only 32 priorities are supported + there is only one bit map. Each set set bit corresponds to a preempted priority + level that had preemption-threshold active to protect against preemption of a + range of relatively higher priority threads. */ + +ULONG _tx_thread_preempted_maps[TX_MAX_PRIORITIES/32]; + + +/* Define the preempt map active bit map that specifies which of the previously + defined preempt maps have something set. This is only necessary if more than + 32 priorities are supported. */ + +#if TX_MAX_PRIORITIES > 32 +ULONG _tx_thread_preempted_map_active; +#endif +#endif + +/* Define the variable that holds the highest priority group ready for + execution. It is important to note that this is not necessarily the same + as the priority of the thread pointed to by _tx_execute_thread. */ + +UINT _tx_thread_highest_priority; + + +/* Define the array of thread pointers. Each entry represents the threads that + are ready at that priority group. For example, index 10 in this array + represents the first thread ready at priority 10. If this entry is NULL, + no threads are ready at that priority. */ + +TX_THREAD * _tx_thread_priority_list[TX_MAX_PRIORITIES]; + + +/* Define the global preempt disable variable. If this is non-zero, preemption is + disabled. It is used internally by ThreadX to prevent preemption of a thread in + the middle of a service that is resuming or suspending another thread. */ + +volatile UINT _tx_thread_preempt_disable; + + +/* Define the global function pointer for mutex cleanup on thread completion or + termination. This pointer is setup during mutex initialization. */ + +VOID (*_tx_thread_mutex_release)(TX_THREAD *thread_ptr); + + +/* Define the global build options variable. This contains a bit map representing + how the ThreadX library was built. The following are the bit field definitions: + + Bit(s) Meaning + + 31 TX_NOT_INTERRUPTABLE defined + 30 TX_INLINE_THREAD_RESUME_SUSPEND define + 29-24 Priority groups 1 -> 32 priorities + 2 -> 64 priorities + 3 -> 96 priorities + + ... + + 32 -> 1024 priorities + 23 TX_TIMER_PROCESS_IN_ISR defined + 22 TX_REACTIVATE_INLINE defined + 21 TX_DISABLE_STACK_FILLING defined + 20 TX_ENABLE_STACK_CHECKING defined + 19 TX_DISABLE_PREEMPTION_THRESHOLD defined + 18 TX_DISABLE_REDUNDANT_CLEARING defined + 17 TX_DISABLE_NOTIFY_CALLBACKS defined + 16 TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO defined + 15 TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO defined + 14 TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO defined + 13 TX_MUTEX_ENABLE_PERFORMANCE_INFO defined + 12 TX_QUEUE_ENABLE_PERFORMANCE_INFO defined + 11 TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO defined + 10 TX_THREAD_ENABLE_PERFORMANCE_INFO defined + 9 TX_TIMER_ENABLE_PERFORMANCE_INFO defined + 8 TX_ENABLE_EVENT_TRACE defined + 7 TX_ENABLE_EXECUTION_CHANGE_NOTIFY defined + 6-0 Port Specific */ + +ULONG _tx_build_options; + + +#ifdef TX_ENABLE_STACK_CHECKING + +/* Define the global function pointer for stack error handling. If a stack error is + detected and the application has registered a stack error handler, it will be + called via this function pointer. */ + +VOID (*_tx_thread_application_stack_error_handler)(TX_THREAD *thread_ptr); + +#endif + +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO + +/* Define the total number of thread resumptions. Each time a thread enters the + ready state this variable is incremented. */ + +ULONG _tx_thread_performance_resume_count; + + +/* Define the total number of thread suspensions. Each time a thread enters a + suspended state this variable is incremented. */ + +ULONG _tx_thread_performance_suspend_count; + + +/* Define the total number of solicited thread preemptions. Each time a thread is + preempted by directly calling a ThreadX service, this variable is incremented. */ + +ULONG _tx_thread_performance_solicited_preemption_count; + + +/* Define the total number of interrupt thread preemptions. Each time a thread is + preempted as a result of an ISR calling a ThreadX service, this variable is + incremented. */ + +ULONG _tx_thread_performance_interrupt_preemption_count; + + +/* Define the total number of priority inversions. Each time a thread is blocked by + a mutex owned by a lower-priority thread, this variable is incremented. */ + +ULONG _tx_thread_performance_priority_inversion_count; + + +/* Define the total number of time-slices. Each time a time-slice operation is + actually performed (another thread is setup for running) this variable is + incremented. */ + +ULONG _tx_thread_performance_time_slice_count; + + +/* Define the total number of thread relinquish operations. Each time a thread + relinquish operation is actually performed (another thread is setup for running) + this variable is incremented. */ + +ULONG _tx_thread_performance_relinquish_count; + + +/* Define the total number of thread timeouts. Each time a thread has a + timeout this variable is incremented. */ + +ULONG _tx_thread_performance_timeout_count; + + +/* Define the total number of thread wait aborts. Each time a thread's suspension + is lifted by the tx_thread_wait_abort call this variable is incremented. */ + +ULONG _tx_thread_performance_wait_abort_count; + + +/* Define the total number of idle system thread returns. Each time a thread returns to + an idle system (no other thread is ready to run) this variable is incremented. */ + +ULONG _tx_thread_performance_idle_return_count; + + +/* Define the total number of non-idle system thread returns. Each time a thread returns to + a non-idle system (another thread is ready to run) this variable is incremented. */ + +ULONG _tx_thread_performance_non_idle_return_count; + + +/* 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + | (((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 00000000..ba22b346 --- /dev/null +++ b/common/src/tx_thread_performance_info_get.c @@ -0,0 +1,297 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_performance_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..0d85cc10 --- /dev/null +++ b/common/src/tx_thread_performance_system_info_get.c @@ -0,0 +1,287 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#ifdef TX_THREAD_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3c6dd51e --- /dev/null +++ b/common/src/tx_thread_preemption_change.c @@ -0,0 +1,280 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_preemption_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..8a18fb4b --- /dev/null +++ b/common/src/tx_thread_priority_change.c @@ -0,0 +1,280 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_priority_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 suspended. */ + thread_ptr -> tx_thread_state = TX_SUSPENDED; + + /* 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 00000000..4dcfb76c --- /dev/null +++ b/common/src/tx_thread_relinquish.c @@ -0,0 +1,169 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5eca80d3 --- /dev/null +++ b/common/src/tx_thread_reset.c @@ -0,0 +1,163 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_reset PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..43e789f7 --- /dev/null +++ b/common/src/tx_thread_resume.c @@ -0,0 +1,581 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..67d61a40 --- /dev/null +++ b/common/src/tx_thread_shell_entry.c @@ -0,0 +1,201 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_shell_entry PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..2f24c438 --- /dev/null +++ b/common/src/tx_thread_sleep.c @@ -0,0 +1,198 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_timer.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_sleep PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..c690724d --- /dev/null +++ b/common/src/tx_thread_stack_analyze.c @@ -0,0 +1,181 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_analyze PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..46235137 --- /dev/null +++ b/common/src/tx_thread_stack_error_handler.c @@ -0,0 +1,105 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_error_handler PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +VOID _tx_thread_stack_error_handler(TX_THREAD *thread_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +#ifdef TX_ENABLE_STACK_CHECKING + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the application has registered an error handler. */ + if (_tx_thread_application_stack_error_handler != TX_NULL) + { + + /* Yes, an error handler is present, simply call the application error handler. */ + (_tx_thread_application_stack_error_handler)(thread_ptr); + } + + /* Restore interrupts. */ + TX_RESTORE + +#else + + /* Access input argument just for the sake of lint, MISRA, etc. */ + if (thread_ptr != TX_NULL) + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Restore interrupts. */ + TX_RESTORE + } +#endif +} + 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 00000000..abd456d2 --- /dev/null +++ b/common/src/tx_thread_stack_error_notify.c @@ -0,0 +1,125 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#ifdef TX_ENABLE_STACK_CHECKING +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_error_notify PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +UINT _tx_thread_stack_error_notify(VOID (*stack_error_handler)(TX_THREAD *thread_ptr)) +{ + +#ifndef TX_ENABLE_STACK_CHECKING + +UINT status; + + + /* Access input argument just for the sake of lint, MISRA, etc. */ + if (stack_error_handler != TX_NULL) + { + + /* Stack checking is not enabled, just return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + else + { + + /* Stack checking is not enabled, just return an error. */ + status = TX_FEATURE_NOT_ENABLED; + } + + /* Return completion status. */ + return(status); +#else + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Make entry in event log. */ + TX_TRACE_IN_LINE_INSERT(TX_TRACE_THREAD_STACK_ERROR_NOTIFY, 0, 0, 0, 0, TX_TRACE_THREAD_EVENTS) + + /* Make entry in event log. */ + TX_EL_THREAD_STACK_ERROR_NOTIFY_INSERT + + /* Setup global thread stack error handler. */ + _tx_thread_application_stack_error_handler = stack_error_handler; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success to caller. */ + return(TX_SUCCESS); +#endif +} + diff --git a/common/src/tx_thread_suspend.c b/common/src/tx_thread_suspend.c new file mode 100644 index 00000000..20c83415 --- /dev/null +++ b/common/src/tx_thread_suspend.c @@ -0,0 +1,843 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ +#define TX_SOURCE_CODE + +/* Include necessary system files. */ +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#ifdef TX_INLINE_THREAD_RESUME_SUSPEND +#ifndef TX_NO_TIMER +#include "tx_timer.h" +#endif +#endif +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_suspend PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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() == 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() == 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 00000000..0b92bb8b --- /dev/null +++ b/common/src/tx_thread_system_preempt_check.c @@ -0,0 +1,127 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_preempt_check PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..b81b5d70 --- /dev/null +++ b/common/src/tx_thread_system_resume.c @@ -0,0 +1,1002 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + +/* Include necessary system files. */ +#include "tx_api.h" +#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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..f3880e24 --- /dev/null +++ b/common/src/tx_thread_system_suspend.c @@ -0,0 +1,1218 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_timer.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_suspend PORTABLE C */ +/* 6.0 */ +/* */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..012d128e --- /dev/null +++ b/common/src/tx_thread_terminate.c @@ -0,0 +1,310 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_terminate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..d629ab9a --- /dev/null +++ b/common/src/tx_thread_time_slice.c @@ -0,0 +1,184 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_trace.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_time_slice PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + 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 00000000..19ca83fc --- /dev/null +++ b/common/src/tx_thread_time_slice_change.c @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_time_slice_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..0ac5c022 --- /dev/null +++ b/common/src/tx_thread_timeout.c @@ -0,0 +1,164 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_timeout PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..c590e17a --- /dev/null +++ b/common/src/tx_thread_wait_abort.c @@ -0,0 +1,235 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_wait_abort PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 + { + + /* 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 any cleanup routines. */ + if (suspend_cleanup != TX_NULL) + { + + /* Yes, there is a function to call. */ + (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 00000000..2bc69bc0 --- /dev/null +++ b/common/src/tx_time_get.c @@ -0,0 +1,100 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..83522f7d --- /dev/null +++ b/common/src/tx_time_set.c @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_time_set PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..69580545 --- /dev/null +++ b/common/src/tx_timer_activate.c @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_activate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ca796a3f --- /dev/null +++ b/common/src/tx_timer_change.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..a394fcf2 --- /dev/null +++ b/common/src/tx_timer_create.c @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..b93c2785 --- /dev/null +++ b/common/src/tx_timer_deactivate.c @@ -0,0 +1,250 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_deactivate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..c5f444b0 --- /dev/null +++ b/common/src/tx_timer_delete.c @@ -0,0 +1,142 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ffe9ba81 --- /dev/null +++ b/common/src/tx_timer_expiration_process.c @@ -0,0 +1,477 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_expiration_process PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 +} + diff --git a/common/src/tx_timer_info_get.c b/common/src/tx_timer_info_get.c new file mode 100644 index 00000000..d422910b --- /dev/null +++ b/common/src/tx_timer_info_get.c @@ -0,0 +1,248 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_trace.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..f86498f4 --- /dev/null +++ b/common/src/tx_timer_initialize.c @@ -0,0 +1,304 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/* Check for the TX_NO_TIMER option. When defined, do not define all of the + timer component global variables. */ + +#ifndef TX_NO_TIMER + + +/* Define the system clock value that is continually incremented by the + periodic timer interrupt processing. */ + +volatile ULONG _tx_timer_system_clock; + + +/* Define the time-slice expiration flag. This is used to indicate that a time-slice + has happened. */ + +UINT _tx_timer_expired_time_slice; + + +/* Define the thread and application timer entry list. This list provides a direct access + method for insertion of times less than TX_TIMER_ENTRIES. */ + +TX_TIMER_INTERNAL *_tx_timer_list[TX_TIMER_ENTRIES]; + + +/* Define the boundary pointers to the list. These are setup to easily manage + wrapping the list. */ + +TX_TIMER_INTERNAL **_tx_timer_list_start; +TX_TIMER_INTERNAL **_tx_timer_list_end; + + +/* Define the current timer pointer in the list. This pointer is moved sequentially + through the timer list by the timer interrupt handler. */ + +TX_TIMER_INTERNAL **_tx_timer_current_ptr; + + +/* Define the timer expiration flag. This is used to indicate that a timer + has expired. */ + +UINT _tx_timer_expired; + + +/* Define the created timer list head pointer. */ + +TX_TIMER *_tx_timer_created_ptr; + + +/* Define the created timer count. */ + +ULONG _tx_timer_created_count; + + +/* Define the pointer to the timer that has expired and is being processed. */ + +TX_TIMER_INTERNAL *_tx_timer_expired_timer_ptr; + + +#ifndef TX_TIMER_PROCESS_IN_ISR + +/* Define the timer thread's control block. */ + +TX_THREAD _tx_timer_thread; + + +/* Define the variable that holds the timer thread's starting stack address. */ + +VOID *_tx_timer_stack_start; + + +/* Define the variable that holds the timer thread's stack size. */ + +ULONG _tx_timer_stack_size; + + +/* Define the variable that holds the timer thread's priority. */ + +UINT _tx_timer_priority; + +/* Define the system timer thread's stack. The default size is defined + in tx_port.h. */ + +ULONG _tx_timer_thread_stack_area[(((UINT) TX_TIMER_THREAD_STACK_SIZE)+((sizeof(ULONG))- ((UINT) 1)))/(sizeof(ULONG))]; + +#else + + +/* Define the busy flag that will prevent nested timer ISR processing. */ + +UINT _tx_timer_processing_active; + +#endif + +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO + +/* Define the total number of timer activations. */ + +ULONG _tx_timer_performance_activate_count; + + +/* Define the total number of timer reactivations. */ + +ULONG _tx_timer_performance_reactivate_count; + + +/* Define the total number of timer deactivations. */ + +ULONG _tx_timer_performance_deactivate_count; + + +/* Define the total number of timer expirations. */ + +ULONG _tx_timer_performance_expiration_count; + + +/* Define the total number of timer expiration adjustments. These are required + if the expiration time is greater than the size of the timer list. In such + cases, the timer is placed at the end of the list and then reactivated + as many times as necessary to finally achieve the resulting timeout. */ + +ULONG _tx_timer_performance__expiration_adjust_count; + +#endif +#endif + + +/* Define the current time slice value. If non-zero, a time-slice is active. + Otherwise, the time_slice is not active. */ + +ULONG _tx_timer_time_slice; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_initialize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..e765abc9 --- /dev/null +++ b/common/src/tx_timer_performance_info_get.c @@ -0,0 +1,214 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5439864d --- /dev/null +++ b/common/src/tx_timer_performance_system_info_get.c @@ -0,0 +1,187 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#ifdef TX_TIMER_ENABLE_PERFORMANCE_INFO +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_performance_system_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..a4b844d3 --- /dev/null +++ b/common/src/tx_timer_system_activate.c @@ -0,0 +1,164 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_system_activate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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; + } + } + } +} + diff --git a/common/src/tx_timer_system_deactivate.c b/common/src/tx_timer_system_deactivate.c new file mode 100644 index 00000000..b951791f --- /dev/null +++ b/common/src/tx_timer_system_deactivate.c @@ -0,0 +1,132 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_system_deactivate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..cc8b036c --- /dev/null +++ b/common/src/tx_timer_thread_entry.c @@ -0,0 +1,480 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_thread_entry PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +#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 00000000..e8723870 --- /dev/null +++ b/common/src/tx_trace_buffer_full_notify.c @@ -0,0 +1,109 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..61881ce2 --- /dev/null +++ b/common/src/tx_trace_disable.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..079500fd --- /dev/null +++ b/common/src/tx_trace_enable.c @@ -0,0 +1,442 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..82c23789 --- /dev/null +++ b/common/src/tx_trace_event_filter.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6c2e8011 --- /dev/null +++ b/common/src/tx_trace_event_unfilter.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..1be5408c --- /dev/null +++ b/common/src/tx_trace_initialize.c @@ -0,0 +1,152 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3f8addc4 --- /dev/null +++ b/common/src/tx_trace_interrupt_control.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..9ab427c2 --- /dev/null +++ b/common/src/tx_trace_isr_enter_insert.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ef484c3b --- /dev/null +++ b/common/src/tx_trace_isr_exit_insert.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..f4cee525 --- /dev/null +++ b/common/src/tx_trace_object_register.c @@ -0,0 +1,291 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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); + + /* 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 00000000..abdc4bc1 --- /dev/null +++ b/common/src/tx_trace_object_unregister.c @@ -0,0 +1,131 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5e21ff64 --- /dev/null +++ b/common/src/tx_trace_user_event_insert.c @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..e100758f --- /dev/null +++ b/common/src/txe_block_allocate.c @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_block_allocate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..7aba85ac --- /dev/null +++ b/common/src/txe_block_pool_create.c @@ -0,0 +1,227 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..dc18a69a --- /dev/null +++ b/common/src/txe_block_pool_delete.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..631a5529 --- /dev/null +++ b/common/src/txe_block_pool_info_get.c @@ -0,0 +1,114 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_block_pool_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..da32a9e8 --- /dev/null +++ b/common/src/txe_block_pool_prioritize.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_block_pool_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..54914be0 --- /dev/null +++ b/common/src/txe_block_release.c @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Block Pool */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_block_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_block_release PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5f374024 --- /dev/null +++ b/common/src/txe_byte_allocate.c @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..9a45d76b --- /dev/null +++ b/common/src/txe_byte_pool_create.c @@ -0,0 +1,222 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..b3d8a505 --- /dev/null +++ b/common/src/txe_byte_pool_delete.c @@ -0,0 +1,144 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..cd735df8 --- /dev/null +++ b/common/src/txe_byte_pool_info_get.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_pool_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..18e7e4b4 --- /dev/null +++ b/common/src/txe_byte_pool_prioritize.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_byte_pool_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..c7a11714 --- /dev/null +++ b/common/src/txe_byte_release.c @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Byte Memory */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_byte_pool.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_byte_release PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ed2038ee --- /dev/null +++ b/common/src/txe_event_flags_create.c @@ -0,0 +1,203 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..ebe73938 --- /dev/null +++ b/common/src/txe_event_flags_delete.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..3ded965f --- /dev/null +++ b/common/src/txe_event_flags_get.c @@ -0,0 +1,177 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6abfeb79 --- /dev/null +++ b/common/src/txe_event_flags_info_get.c @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..a0e97bb8 --- /dev/null +++ b/common/src/txe_event_flags_set.c @@ -0,0 +1,126 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Event Flags */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_event_flags.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_event_flags_set PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..621848be --- /dev/null +++ b/common/src/txe_event_flags_set_notify.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..76f9a215 --- /dev/null +++ b/common/src/txe_mutex_create.c @@ -0,0 +1,221 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..de5ff718 --- /dev/null +++ b/common/src/txe_mutex_delete.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..c1a81601 --- /dev/null +++ b/common/src/txe_mutex_get.c @@ -0,0 +1,168 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..853c7470 --- /dev/null +++ b/common/src/txe_mutex_info_get.c @@ -0,0 +1,114 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..9df7065a --- /dev/null +++ b/common/src/txe_mutex_prioritize.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_mutex_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..16de56e1 --- /dev/null +++ b/common/src/txe_mutex_put.c @@ -0,0 +1,124 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Mutex */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_mutex.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_mutex_put PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..006386f3 --- /dev/null +++ b/common/src/txe_queue_create.c @@ -0,0 +1,237 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..75a63778 --- /dev/null +++ b/common/src/txe_queue_delete.c @@ -0,0 +1,142 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..09a658f4 --- /dev/null +++ b/common/src/txe_queue_flush.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..91c1eee0 --- /dev/null +++ b/common/src/txe_queue_front_send.c @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_front_send PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..0e05cf5a --- /dev/null +++ b/common/src/txe_queue_info_get.c @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..2a40fe36 --- /dev/null +++ b/common/src/txe_queue_prioritize.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..93af544d --- /dev/null +++ b/common/src/txe_queue_receive.c @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_receive PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..2a568742 --- /dev/null +++ b/common/src/txe_queue_send.c @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Queue */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" +#include "tx_queue.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_queue_send PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..a6c0d746 --- /dev/null +++ b/common/src/txe_queue_send_notify.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..e404d4c7 --- /dev/null +++ b/common/src/txe_semaphore_ceiling_put.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_ceiling_put PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..9cb9ac61 --- /dev/null +++ b/common/src/txe_semaphore_create.c @@ -0,0 +1,208 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..9036373d --- /dev/null +++ b/common/src/txe_semaphore_delete.c @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..10f37e59 --- /dev/null +++ b/common/src/txe_semaphore_get.c @@ -0,0 +1,148 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..35e88f79 --- /dev/null +++ b/common/src/txe_semaphore_info_get.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..eb980d21 --- /dev/null +++ b/common/src/txe_semaphore_prioritize.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_semaphore_prioritize PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..dd35addd --- /dev/null +++ b/common/src/txe_semaphore_put.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Semaphore */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_semaphore.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_semaphore_put PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..d9794f5a --- /dev/null +++ b/common/src/txe_semaphore_put_notify.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..12b67017 --- /dev/null +++ b/common/src/txe_thread_create.c @@ -0,0 +1,311 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the thread create function call. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Thread control block pointer */ +/* name 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 */ +/* */ +/**************************************************************************/ +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 00000000..f85209be --- /dev/null +++ b/common/src/txe_thread_delete.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_delete PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..1f71e3ff --- /dev/null +++ b/common/src/txe_thread_entry_exit_notify.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..24365329 --- /dev/null +++ b/common/src/txe_thread_info_get.c @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..d3cc4fd3 --- /dev/null +++ b/common/src/txe_thread_preemption_change.c @@ -0,0 +1,130 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..f4160d13 --- /dev/null +++ b/common/src/txe_thread_priority_change.c @@ -0,0 +1,131 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_priority_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6f7733c4 --- /dev/null +++ b/common/src/txe_thread_relinquish.c @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_relinquish PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..bef5fa8c --- /dev/null +++ b/common/src/txe_thread_reset.c @@ -0,0 +1,136 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_reset PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..04255304 --- /dev/null +++ b/common/src/txe_thread_resume.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_resume PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..eb8e24c3 --- /dev/null +++ b/common/src/txe_thread_suspend.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_suspend PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5531a378 --- /dev/null +++ b/common/src/txe_thread_terminate.c @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_terminate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..e024dd13 --- /dev/null +++ b/common/src/txe_thread_time_slice_change.c @@ -0,0 +1,122 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_time_slice_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..831b3f84 --- /dev/null +++ b/common/src/txe_thread_wait_abort.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_thread_wait_abort PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5938a428 --- /dev/null +++ b/common/src/txe_timer_activate.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_activate PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..7be337f9 --- /dev/null +++ b/common/src/txe_timer_change.c @@ -0,0 +1,124 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_initialize.h" +#include "tx_thread.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_change PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..6397a801 --- /dev/null +++ b/common/src/txe_timer_create.c @@ -0,0 +1,237 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..5c1e620b --- /dev/null +++ b/common/src/txe_timer_deactivate.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..21debdf1 --- /dev/null +++ b/common/src/txe_timer_delete.c @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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 00000000..66d311c1 --- /dev/null +++ b/common/src/txe_timer_info_get.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _txe_timer_info_get PORTABLE C */ +/* 6.0 */ +/* 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 */ +/* */ +/**************************************************************************/ +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/docs/ThreadX_User_Guide.pdf b/docs/ThreadX_User_Guide.pdf new file mode 100755 index 0000000000000000000000000000000000000000..901607709825455211d9f2b8913a4d7419c53788 GIT binary patch literal 2836943 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ℜEAgRJOD)ZoE67AQxpk9{;Xi){)(Ix~F7DMF5 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

J=V2ctH_nd8OF@s#scH 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≪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%0AX-GP?fY0D<*_$b#!N=mOp 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�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

  • bW|#l6uR(NHCAI2J} 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�_S01kP2FYCcA{o6U7KY<_4Ft<;u?qjjerMXJp1Cl%S zyNkg&@sJcQF(cK8YA^DmbuBwp9?bCXb`Yn45kB?>Kemq+Q;8UbDU0S%n9kZfQrmE* z4FKML3E?A0cT^ptclsgbL3y57$x(ELM+f&7)RvucC_*f$HVU1wm_l$ zU{2vDA9*v6oU^7kLc4Nb5cc*5Gl5M?)=diSZkUkanH@To0FE5#(bGC5&&eLL5$$RC~$-d)^ zCv#a1fkuM|f1KDDd%!)oc1O(yc1Z4U!k8ZfI@Ar%`K)Kcvfxxl`A9iK0HYRtsQr#rNV7)2fJ9YpNib^fR{`>#|Q4mK`5 zMmbXxOT+)`Sw%y~UpvBxnAzAl|8GXh{l^O^Gyc2Vy8bfcKWC&YoGgF;`@g8IWv?ra z;d^ZWAha#=(t9J(dKW?wCt_9(jfJ2lI&fb9Y=T;gnw~4Tqg8I_vOyN!lCX5j)0FK~ zai-h(V_9C1-==%hmcg}yZOziHt4vldsgDq`J}WUI3UT4e&bTC(Z7PQO;OrN{zm?&<|XGP{rz%bj*4hmhd$iL>WR*iep7tH;bvPtJ^M znfZbTkCz|+B~#k8Z))3{Q=A{7#N@!RAjugCHN%C1%G|V(*ngR&ttl$q6QE z33>7u!?4^_*wh0>3OSkHEj0rNeAKLnUgn8ruNhTuT5&SzF28htAyq-AFV|-741n5v zVd9RP?&X4%8GqVt8z0BI$Ns{Z)wZ4-LPXCy!%BaT4HUZc=W*1jhN4tH-LL}k#T3>Z z494doxku+=Nuw^2Hp6;fX>rXScfix*&DGZK*4@)voLiWI;3v!-zPm9w0|CG0Hm;m| zzL#>RL3d%ya@0;I$w}RJ)>OY8-5+lbUJtuRaRUucE!WrfR|tex_KyqvQu=&eR0|)5 z+PxDf_yQR6ceNwb-bo+88|@}4TAy1tK4OorIT#pzQPTN6np8~CZgeSGY1egov_=R9 z3rcR_3>NR%MqoPkMkYeSOa;Yh$@`;W@b}C7pBgp=DQ_TspJXL`BW`Xs;5(ydp`eHYw1B?F1X7TLeB1Y0*EH7T zR9CRJ#4-n}kLyD@TSQd5$%h&c0j}L4vJp`~NhKn5Asud}3gy5!fS18b^!8sxR*g~7 z+$w{Miqm?+dM~Lo7K&HxF7N37G^-56d(&HOxBNKyzaeSmnVIc5pQVo5FGvEExWJG& ze>C_xWQUFza+$lokAeFQ;(`-F-w5{vBiD*I1V|R2)RrtB%rTyb%0tpaGW~lLdzsTY zCS;8jZMQoA-yEr(>zrIb;!@F9!(tR1BjE6abz)O-1nPmQ3mB2!lML%r_|HVmT2|g| zvuq?l897Z$%bIbHGOBb?S^c6IuDpGj=LeJoQvFP%N?u z2-&l>LEW0V^(b(At31^85pr-9vAP=AI#JT>yeMx$5k6QpaKQISgB5_Ke`KVD`SDhN zFj7120K1=M`0qRQ`!oCuu+51>ARa&&V|B{hQYyM5gY447M7sRtSJ;T55tZr22XYa3 zZh#25gHg>WNi&p0zD>e8zXJ^n@H&BMi3T%A6>W;lH7FkEgs4Q3?YA;~sEgnmx_u8w zQ}M~+B0ggqu0D4f-Oewl+(BgW#WHmV-z1rmAp)Ao>Zvj$n%l@O+-aU2Xi;*Eob9w# z{n`3(!IQ~(4m7>Rp?YS&A92Am6{0+4xDa}Ss&9jLUos`?d?%4LA>0$8dNZLV5{C+w5`o(B*-F!(OK50=qNp$Vw&II|5J!_NIg&p=1MOx+vMyQ%q;R43Vy zZS%{b3Y<=ooOr@8z5fBMxrI(;rx`VuB9ADjg)s(aa#P}#XQX$hvB@2=5*W0^*zKZD zG8S7$p7VM5x$_JU)^X7WeFLLAR~35xE*YXyol2sVL7fx49(s#om502Lbd~2ghX)j? zq!Ce)35=M$X{j07x5a@>Vq8rQh_}8kqgG{EA*HGFXj40}Sp*rda%K`gU&Y8jJ1IR{ zNC!IR#AaR7hJS|%dEM+ZF%yu)EHL3{k0)!{V1PUwyiEXuBzBX|d;&dI)v*a8gAhiE zT}Z@R%e9#zPG@E3R~3zyrCA}zzv9J*uvZw3bkvTri;ob7XP?RDI0@i!a=gtR!NAm{ zdLf2^z0*~JlrpL}jhN3;71Pz3D3z}h4FvN|@}PF44=A-Q7IsJ|$InQrG&3?NN`EX1 zvd+sqB^NLN{V?52y`Q1}wDZZ{w|BB*YG}e9UoZ0KwYZOeX;w9f+^A3QTtg}<;6#tfF5*stc z&?Ltw8>9uKR$$cG8T}ea&l)@Lqt8X&@}!Dw0xo@&dd^Y2`0b;AsG|I;>_yqg`L+V| zfJ!OP1+52}AdYyA`ixw;Sc*{1d9d}FD}eZLyEFyrqE9vBvXqFkY@)p$j-ctBRzLo#qC!tVmc+1UYNjETU`ZGph# z@rLw<88&?{c~QJ=OKnSM^6l7q7eNep-KHWv9wkHl0jVSk7J<>j*$s>@Y0iw?HNS~U z$%2W-xDSE2YxRZIR~Da;Dfr!$da&;OhqS&Q*_65gkEqwF>Xnvs>JEXMTLG!8cThT| zSRUG!`b+gkX*8k`8mZg=1xi65)$mur8qI5ZURUgRR-7cJJ=#A>c)0jDJ?{1h<`foX zzkl4`+}`XzT#kh0Zm`;tswy&f5^%kJ*gS2;)#&%QzZ<>ofdND~KH=Y96Jj$OzF!W! zQ%{Gl7cusPa=(A**6|m!G@c*$$(bst9euY-ix=}T?9t8{DU#SweOkP05-$x#)6j72 zZcCiG2s8wwMaumE8_F>=IwMeVR*Bxo=&8UXY95qZ&yR0e437!xf56bXQw|xEWLT3A z@jcTP0L3-K1^Z&B_1=iw>M7=Q_%21DIy}+$v%rX=Ic{~$p4AC%iRK7cZW|@>=26x8 zXo52*(#pKXu!oR6F%F#1s1sIF;E)Bz{Z9V%l89r!3b`GA)YzHLrV!4v_6!U-weU;A zG(7E2N<3yjmcgA@tWpWJc~Lb>>o^{!*V<__`!wSII#d(#xWg5&nJd8hXvJZoKCU#hMvdoo>*Lvs zizw8zD>AGoEDma!@*%sQy%&PO4BX_0zd&|YBvn$buDg;EXqn)iaOYPt&x;np!I4B+ zFyOkkDa+6!s{>T0Jo6Kj+N>t<@x#ZJ@Rt%=IAl2XD$U-?R1)rqa49&I@ZO*6)ng}? zguuVlQh()e)LZXjF@~%;2^Ey-00p(?@+(K4jgcD^AXX|F|MeLDx?hA=5316yQH}FN;4B#;1?`FlX_rTi2)DRrv*ZB zhZ3h}Pt=F)3JhMjhuL5+Dj4v%DbQDh*5Z!*ZZ>nW980 zVQX^vHIv(5U^SyPKjZwA3@&z|la9swW__e9e8%)r{71PtHHl>@F`aob7|2|4V+3&H z^w6-^`7(UhWXJ>MQ#HU&a0`j74ZUgJztt1#lFfG%NdHdlA|{-$ooLy0B&l&^rMuJ3 zPMkMYGT93#BjHOS7M|nE+0B5-)5i~wq+zb~#mD>IeXD_0n^NSHa}FFi%S#B+C8;+S zr?rV0)W=7crWX3CAfcgiTWCzCec?IsceF3EBR-d;=Z|9c+m58>KK95vC}e~UBR2hC zBBPIWKpg!@fqghA+b1Yd;(6tS;uw6k#GFtgR!ef1)N0vWPYNhp1mY6+R>v#r>V2Q+ ztEFItAr2ACu%?1slp>KWquw>{(ItH@A$_x5T>`$l!iVNKfNaaWQ zPH|-Om9Dr=abat`*L(En6^iLFmmg#IAI@6Q9b8&-GiUTlbpb&tVG^QRSM)=^@K`xs zoM`*L9=No!)-j&#K!iwPzIGP+_Fiez?8MS;e9uOrcEh^foz~V~OmXPh&&R#{>a0~t z?;7Q?4>jeYn7ao}dr~$%M~7EDMfIgLw7Kk}ekA#X=(3Cy`V2Zw(w>H!XFr8s|2SJO zh$NTzPjAwGTf^Vh@IPk_S$_Jnb?4+iS~FJx4qER z+4h%PxBp`eL1Et*0MM{+$+ZM6h!Wn6wTN-gz?4A&tjcXP`@gVZAOiFQH@t%lzWDTk zm04ZFuvJ64I!+4?N=4}k*Vi+f*~T?hiX(LjvNW(p%d> zeu@=gkcXT4epy361>lI%!+!*^0!=ZK)S|N!&m((D?-C_Sf9pB)|5!tboLp}aQJiHF zw6z_@K(=z5-68ONJItQu1~5_;OS01jisQM1SsZ?-+k*T>k!+JPR_Z~l`xd1Tq^z$G zCS2PT!eNxKWid!J3L#9`R|+*_;3J6xhv~l}WF6Sa7%rK%^MPa4b1rcY+FrMg&hpyD zU)QSlw#aYK7u_<#%GQCkOvkCdlm&JgH5T$DK8SdiR7NY4#+Taofax8bizS**bX$yA;tE_O?^K)$UVvxsaKZkO|Ok zdj8ChokPhmJHGaBbjKlL&yJA}Xp>I&iw9h^sAenymY;^1no{Z1dYRzO%lsv?=uneb zO#{Vordm(2cBsU04mZ(QMtO&%kfRbpj#=Maf39j&3O&OASQ~-sdbiS(45ZR3Xw19k zG1m1zLfFAlFyz|UULWdbD0zFWZR)@X#Y828AuLHc03KLD+E0mR5LjUF{RS-Xr4OME zJEcK2P@)F7dMq$B%)~!GW3;v$*c1DJJ{xl)nMlAgLAXmU^jHUc!N)OUl7Zs+zMqN_ z?#Q{mbrCB%kVHap5ITTc3FT}WYWI$9sin2-CPsoD(B<4knD&!PkwCG`7$FS<&)Vr1 zH5BzEWupAt=S*Yi;CXoba`ZW%6I{sqo+&XxEsyV^=d3#q7 zjMYf(mgt+U{5BZt6ENI2o7MaR$E(u&PM{lFA;FVe&vyVu>m%iPNmw|6O&hUEG8w_p zDkGnyZm9ou+O|R+q`_;^l|OBXn4Of#bn%F|&rDiA^k+hZrILU|7VjJbJq3z}ii%w6 zggkPZeHS5*<*BD}9_EY3ZlCXmuaWvVD&)zyw0LAVO8XShUsZ58BR;bBOkfVbs_b`T z07MKr*XQw6wV9~^8=eOhziNhD>?|4Gs zV#Cjiuw0B>O2s3fB!rA9@zUth_;hn(Yh#1oJ-j8=m!yT&%9JL!I!c$t_Ev#?!vWsiUcDlgUD*A^-aIj;=I|wE=C-^+YzCwC+PDGrxZEA1Y|eog9?Y!~g>pi)w=%+bIJ9cu4``m@d*?Qo4^2{h&4+Fy z`0WT=hAYUO?xY3dJcO`kkB&(f=4Je+$J|Rs0+q5U@c^d&=+Gu5Z3yRsfs2O&o#3;J zF+}s70fd3s7uwCpXmiKuW~r-#QDN$dI$cRWF47gVRYWIi!e7ai^HmCQe>PEA|B)R2 zNLJt2jK+Yvc8L|AO!9uKfeh z!L?zx@cCD6j}gvSHmqmKpo>tGy_133E}it)8w89kX3GDFA?z}Cn$1XT(79S2g)P|T_ zz9i)GSM&Yw^8<*(_7HY&EPT5?&f5BjnD%Ybi-sP3H%$1>l|uYF7i$;tUqTH8oOpt#1qrIogz5B)E=ict)?(LD?&mZm$xCFbS4VVh1tNifB-v_Ypf6!q~ zEg-n|86*q#y5clsgc~xoY~l0w=(KVT!xhF$aQ59>_}c-`YbN5m!U9(Tqc(zG1Ld%+ z=FI_HIB?YE*lQE!>CQ~+(4s%vLw@&@rLkJXWXd}U`z*wkkK98*AC7_rg65CV%4rv9 zc!P>KS8WvW$`{lydX@N~|1^dgutj1Yq6XLL?!FF6n}=6p1zO0vtQ@T?;G8Kw1l?P595 zZ+IHSX&jUwl(kvR2SO~6ZnehK`T<-00V$f`TPF)e9ld?ZL*cN#jL)WCZMAfVkGI3)=N=zFj$okYw+4M!pN-t!Jp7kl--k%Dy=Y)u%dHH zDYk*&q&NWZe!7YgO#bDRmZx}Q32t@a*!eKJW9BJL#Ff+~@oJ@w4R)rXs?)rmNZ*p@ zfPNZ7WQVDPGN7YWLDF;U!lxp_im|(juxn*W3K7RPCXtk_4$hh!l#fd3I47SWk6o)?h<-KxEW`oq zrD9WGk9Oi8ODAznXUX11R}JGIM-)GncvKmu<^;F(q0j%iQ#2B{#0X0#9s}M8q?$yU zpO{p#IxNNRC_$9&iMEDHfJL!r6q|rS&bB#6t{N|D8bd&WN+>%K)} zs+3)%L;*Xsa43VaGRmlz;7O>E1XQXiUsZ1@l!7rzrlAd0ulpz6#%vJofYIsT45P`u zr_WR{eQS85B$7D#M<_}A%)3Ea#CIo!)+q%*RM6U^L<+kUk{7TdwXo9mvHd{EjaE7qpk7DbMHC8A{P#mxTj}K4%;&g? zTp++549!>%+7k6Peg)w%C%zIXg1Jh>-fI3Lh-B?TXQ{}Cr#LR3vy3vp3=(#IO z8Y84Y?Lv3`8PS15rCaA1;oQEVlZ|8mavYFmu!1l#>G_M9c=wd7T;xGw2(2|(K3x8H z+BG6$0dz@Y7A!p&CEGn!%MoVJh$U!;?}HPTVx~QXs^RXI`PrO>ArY($FnvfKkpPfQ z7NPG#OD~JS?p5SK=a3rIL-{Sbbf}+6Ld0aT(XZb~$!nxd;)c@jLNR;Fg76?G-4(FDHNO-eN#qNJIx{aT{)(~$ILWtqOm+BGNdr@wj{Jg% zwQ}P15k$6RL!V9%q8d2e4BcOd&|0RUkzlUQP**G2=Otdh2be9B6M=nm&VS-QldSVT zq9i|Ch+j*Oym6bK{UySxennYo2dHPdUxeL2au#VJBGp&;o3^_&`_MXb*FBd>bjO;GJjjMngdR;bCP6H zbF~Ug5O}zf0~^6<13+c0U?mYKgWqf8 z&&Hn)@6QfDf9zWN`4v~0@*_|oYBG*D`_Z-R__@DbE%C1ZuzD`9PE+y6V7;~Kd*8p? zx0)6So;(dnJX{f@_3gHk)^{$JQLDtIm+x38=gk+5SvOWHBU@+ zix>?-DzSN-$j9iV_@1!`gv6r}ZM##-xJ~&Zj~!CPZy+_3Ar$!HatdL;E)K$i$c@IX z$y8W4iUuJFM+sb0;Zv|2zkUwF$AC7txRF%BYfA3_|JZx0*vPuY+}6y@%xz|7W@ct) zW@c{NZKgK6&CD({Geeu1nc02&-{lPW|Nrmp0Sm3xxT00Y^X|ds!1mAZ_=AYF)m`#=^qfNX12PKza$$eBnNT2fGf*^G4w^u3nSs1E>Vi3VzA4 z+vB1hZ2Zz|CDe4F2E)cxDpG!RNYx%4J-_;P*Wc)vjufYYU4q|)B9A>U+waP(ioWSu zq+t|8iv+)(jtn2u9`?{?=#2tb+Ik=T73o`R#XQy0q-O=j(OH>jhms79CB4=}pzLz) zcm|JK=cUo08h-t1HRp)Ed9oy>sB=V(jwDXL6p*5e!}(Pt?sb2Rb^a1*cTEl z0*N?gAmn=1tzgxq6nWXHB?>LYX1YM?di$ym#+B1*x#z)B14^(6jG(?i!G;mrFcj8QEKgvP9$%gn<>uARJhx=TV+e+Yl|Bel zmFei`xvX4?Tb6tCS$yhQmG3K>DuIvSqY@S6Z4fqfmqrVw2S?|+UZ9Q-$H6+{ zoWcwiSE|7rd>h;?jyXTPBmVeF!<|<=NAH8y?DyUz>z9lbr&h^<&uHn!FiD{Mer&R) zVO63GKDi$^MJo2D-CFvVG@z0)@<=1SR>t77FuB;U2TqPsUBX^u3{zQHJuMS19(`U%d5y=)-7n*k(ZtV zdl2}}^)YZBx2_deK<~q6&pl{N@{N?H5&|9D)o9YU?VupS{Q!ylrgwSvb8=AI@UUsK9q?Z9+^Ww;>w|o{=pwQoWY*H-BXMP8v}n^ks$SfD zOV!CyJ4lINB?AbOPSOc^+@8R`=a9(@be`X@lAh0IETM+rlp2n1+Lyg&)$X_I&o|%6-?GLmxcppvNises7byKeUcX;7!cOS*S?d*I$ z3Ou{zmt2tq9PSLl^qt;59$IfN%?R54cyPU4gow51@vKkMp~yZSI{ z5HGc|*sswWt+cfcrHD782Wc80ysui+*Q1(L@IxdjrP@KhQJsEBHP)Wr*<99DdOWtt zukO-%e6Fcmd8>$A2C)8oN_-0L{J9Qg3vet>ojK;%b4GoeDKL_8-+zHYO4`f-43{BS zwfw4PVW=QOu_2);j!`PH{?r5frr5V8Xf0A`Hk@OOvecDM&@6PD`d`pdAA3~s88Jsp>bEIAir(avrX+vi- z0t`Q35_xRa_c;L<9UqJ5gqlz<2Fq%Ns2p_EY?jt$?9rNUnQS)M%v$#<<O)gs6lX)F@>qsGdwy8}%w-x}x2KUWS zhKbrd0FSR2rVgkAKtNmZ)e4jY?CasKh_exhSJs_&1wO|cbE)E1KDr&jBNwF+DvWFH zzQ(>*W_LN4^|{%MLrqfHL41{sfxn3*to2w%bv<}7ii5w5$ z5L>ZtcszICljM*$^w5knj5}B9KY!n*5!%!<{D;dke_-Q3ut7 zVBi@ox|F**)*!WKZe-ikUz@G&EB=Fy#z`q|hX88jf|8K&2{-dxl$G;65 z>p1i=!iD{kCfEU9ZM4dghl+B-MX`kXInXGpmPb&FuFPh%cQkz>W;`at|MHW6m>^zc z7bSie`DXXFAKIkuV<1$F{^TJ$e@wM*>VSaOQl1jlD$uUNe+zqS!qu**uIVH*m5s+a zY(E8UaV)AG3(bzbc*I2pIZ*}#=O!Er)M+(29lSdn$;?ReN(;lf8{+Pg zRsz)mlw)sV>J})TusKo0NIq|N*!b8)CSx6;4omF?cYhJRylm}g1M}Q2a3uqIjH(9a zql-@(c&@Y{4EHFsUC-Cf0{AbxDau>Zbkb-Zn=jI?m`HvY=eRIoF%s#_miU3NZI1e0 zuVoh4cg75v-+EK6-+I&C_xn`cy5G0<6{yIT@gzic=i)HkEd#5H&EFuje)zX!aF^QW z_&3Y=c*tuWyiVN_sqqkv7cxr|s>$omu1e{RC$ZOOOazP#(#(1>~BNC8O zv3!2mY;y6P5OT3ocx@s&IIX32pM)lpD;&G&nkz?ow5BdHM93gJDLjOTtqETi)3^Z6 z$c1$HC$ErU)Msv;qXys^H_t$>h#x<@LhBHSiVLy?5$*nJ;9o`LpUq3cB47--TYgG?d9NS zEvLgGnmgN%-WxGNKr0hoA>(g9=ES|e-$w|NQZv-_e#j@XNl|S*|0@W!JY4^J|sf#u}>;0 zAHr@dvBzC>Fdw$SE!kY3+MJf(>I&Zii}jfsW&^@sEsGD4t4)ZI2g-u*r^l>@x!#>1 zQHLOqZAjOk=MyDhropnlmdRA@2&9b&CMR{(6N9udrX+iw54Nh}u1fl01xP=W?oaBL zb-3O$Y>lWP23M}HFxSFtu+1YpGAxx7`3~1Ml50I6>Y! zfY+-20O{CzZMu$YMhi2Ko%UVVzDT`}%?(z>q%J73rA<;sT{tT^i^}eT{yA9uG`=uM zF9;NFEQY5`OdCanSR6c1O+Ha{agkL+c;wE2!}Y!Mv!HbH&7SjnD~W&X(eur!@z0+< zQ!sFq4l4pi0wAK2hLa7fI~N^A!{zBPoZc+leRAefjtd8Z*j=U7Z_$!Y^zahKA?%NO7~dG z8{)Fakcd1Kn|dhK>^cTNFkjUoGG=@qZMwD6)j6yKXZ~VXfM!BpR7a^rJDYeh#&0JY zarT90W!hyYPdPf6tlRD2($T^oD^($!Ys})w`qge&Ynej?z zv!o|QFpH%-W%i|uFhr6Pkbr&~^LJYkXt8Zgub^ zfx^Z{brUUFgcAuTHRYtl|KZ3RBq}&BsJG^P_{DvJ>xq%pn0Wx2CtTI&B6OZHkT!p3 zxOKiyR2Q`shdjfPIsZa9AioY{l$S#>W#<8(&8Wk;nHiGi!kR%nH?&*lr{GNpJ~(^Y zM=)qh#%m}_Q>>~6FQ$T5;m>KAg1e(=#8 z#^MarU;?A|eMHrE(wCkTl}zQaZ%5XEh;KjO<2{i9Nfwd!&>lK3NaqAz2dhl#u7cWF zrK7fV2aerH7)&`2}iW2(g! zWt>d)IwX|HSnoQt+t@;mq?(rXElbY52N{*x>oH;}NuNgYgUPIfwM-?x7z3>pB^x_L z-#S?loMqL8ljj%I(Lm?Qr=&UW6!Y(&_HM>Uq_TxOsS6o?MrRxdP~!;-*zqd;qSN;< zx&>kfVgM7$1`)6A=K|SMXbYhfCckAVO5SYa3`nSyW%`&%zI@4j$UzO}l|Z&Xr&?Aw z!zDp@#124YM$6>chcGcdzoASg@ze3qzN{Hw|5Qu2ue(5Iab_uXIh?!sk)UcHe$fmd z;BVg&BRCc*u^q$Y8m?J*adau>9_+LBs6faXBRv1aS~&fDG%vB&IK^eEeGL~6AaF-~ z;(%e$B!BehRg|vc$l9^qxCmDWAS`>^X$K5TY2?m5z?H7?-}CXRTfYo@SA3p3x^~hm z-ZU$2TpVq@K8gn&_q(?$SLi60yk5?i*fBd7E^(Y~w7)fe8bB6sdbU5R{~C0_j9)ad$70;F_%SrTLL=@&jXzJ<_jqE$;JSdOkQ z7LilMDZSwMGy^Owll^=)_!6;PqcA-UjCEc0?9=&$5%3*H?=#k**G#nrm}U}0lf9s>H|Ecm3XfYW9_eo3V! z$T@_sHjk&BezWlxT~>58tbB1}Wef)TBj{kMeZD}8d!64{2F#@<&+fEH>L|6z8SN+#ES;oGxacqC+V0 zfxb|<{hBxZ6!iRDNe%S5FGecT#W!kdbW0<=7<lZK!+S{lICBTB&-=^L%$WZ-OS84KTfaG_|NABTA$#}J<^->n zGXkFJD7a*`VVfy~$Liuf^n6DJIFwzeR7RnTEv|j?{*RY5Gkreu-C86CcarZTV~|uc z>auw(rI6`pEb|A{;VNJ6d&`gLY_8>P10D=oKPTklzj5Qu9rcT6IRDl(cXl^#d5#r7 zYQXow@Zd~+u|l0yiELQpYJ^(+qKHMGAHfkTf@yyZp!6g@IuG2R&f!fi#~XLM4`I2r z3;JO6xcqCMhDHem$A5I9u>R}P#Q(ET1M7cjX@ZOK|GeD4>1qDkkpJ|b3@a1Yzwk7l z>uAN}a-jGx*BncX{=D4r0|Et(vg3qKq{SQm2_(;$K5K~w?()-R|M^J=bH!GQ#U12a zBruGQBSxZ5^Fgg{#GbIzyAbf?(ZHb5P`F6#+ODHFaho7gvWCOU34`Xd5qGNv+iui%tm=IC#Y8g0{2b2|_OdiwHibCzB zKeh&#yeN1Q$@Hkf=)~Q92M%+;yLkB#`RMcmV8;=I1McWmTQ=@=t%oRU`1p(WtlB7i zdoIuRNT`EgYykw`ut=+sbI2QwFT`1|Mm0bu z{r31p?{vvy1Id=d6I1{`uT7_)(zD<*Xvr&*dOjG~{*0!)I}=;r8R`orL{h$&B2f#H zk))8vSw@03Fqqpgsi7P)W2rPSEvMCSNysaH>W67pmt;`DQr@p+(*mVeFreFJ7Z}w& z@trrJ5Nac#9+02CrzxX~uIw(zP6tU056IbK-X-al^zvuYps+EUzC?*Bq-0w@T4;` zFsTz{=77*5w9ut`PsNuQH3^I36Dh>;!BGpwB-|_*Q7uPXz9Y$S+50_Wo_%quK=y=ErC0)j^F2>avtCAZVUR}DH(HsPP zGzCS;GXY9>f}V_aMkg_I38F}(&T8?RvDz{enw8J0qVXGn7g|L+Hbxlc%?cSUluq;) zQ&fzVmF78N@*`wxv^OM6!w(U#96%{>nsd-=NDAB|#J&h5)7L3W@+wlR{w&GrSURPA zyAH&r*v*j6$hierGUY0&KjgLouBlctho`$fI+X301j;$(swF_%$@XrS6m-U{DAKs*?M;Z0{WL&8P| zRFs|gGJbo|ao7hs2)}wq?Ng^nE+iorS@POR3v1Z`n0t_+fVIYy5o4nj&q7Av%*23) zc8A0^s1i`4#z$LK;AU4+UCR_1IUt#*zl8%bdUiF}uYuKDJ@03`ER~=Zz}!p|vm6uh z4`4-l!fYMF`+%Uw{0XI=rZ9|?zn_dti#WojF7HB%G|txX2Qp$wjNM>SHJh*s?j zHR0J6I;{;D4CFCS#O6a6V5#JLYgvNr_0AZtC-`3C0YQb@JOwCV{BBG*N<5H>Es?3@ zmngyX-1JeNAF?!Axgz}J)+4SpF~xG$i8jXz!>Yj>^+lq@;~^dPoS;keK+!WiOGUYu zXFC<-f;g#`@;wwWqPxKh-$Sx@XZ{k(U{DO9_k~58&M8g`p^8~L?SV+*Ry2Y<>NpZ@ z%#cF_vc*toQ4~~ehzL*jMw`vNp;q;)5zHCGn!L|pFd2*Rr?(*mk&Dqi96nFJspp;oY{w>aZ+`F6$g5XLV+C16~Q0;`$2 zjN-E1j)*~;iB<-QyX{jV`v+5vmDz~}G?4?0xaVHh96}!H8KeUywko>Ye^n+JzfEwd zf@s7x%jUQw!4YVzlAOzTDNleoqLz)$>x0P9(S?CTnvRaZNw6K*kiIs;r{LkMxz%hx z!OwKNCntVxwp{`)H>MR`_<6h^hPLyc3A-0~G*3T~&m^bbCvSPP?}4e<1?Of(X%>|t zL!p_>Sdj4-Oc~4u{Crx99(?MmW)pmo8OFNDK9B8^%9BEQ!O@6LVsJ`% zCueH3lYB$MD4J6gi4&I(3g6V>zHt14Az$wo0QN~u7sG#?jz^by2fL)$*Q zFGJoRVqi}h5(J_wF$6!(S=>rdfmtFQbyqrI2G>bc^y54sx>N;WRM4}pxu18E2W_)& zQ)aMfLQpg#PE)_xrH-)c{gUfLfBXd-!HZv*_LMgVm7CL!->uE)m_Wpy$y<^pyN;6+ z0&o59SV2#@M|SpFiXW`w2g!!#4106|b9?{!@fpo>XDf2la26^O+WI0yPo=u^*ZccW zYiAijxSkW;GZ$CF!Pkr_wBwv`!$Ru*ZmNDxmN>kc9{q8(yi^(9M-k8MK*lyu)#goL z0-6KT_bD{If;f88B zl?_poRr^<6y}Bh=tw8jkSlR+!C5W}_g}&rgA{}ZX6L6}^V{mTZwU@P;ZUZ-1>=MuH z!M)-mx2~+MUrzOba^{~mMt8MbEBXfO*&SQ!X@E6mOrp_*3nSU-z21qt+`|e&1^sTn zmq)WFTZ>enUgi0lWig^|=fvxF>4RA2;6bTjnng zPF4=Wf99-jY^~>XZJje;vYjuGhpDf7lx{3)2z0#ff`1ijN;WDtG(_|Buj}jt2(a&p;i-0HS{E?20>;lA0 z-4fZh`R)`T9R4!{9i)Mv4xICsRh{Sh&h~!LO(kbGW(1289(xZw#eps@ za#OPqH=UO9t$3n_XlzCopx-8-7(+&s|@IN42upfLeBG^9!* zc`wu4Dg=x@&d@id6(=xZWftKt@_D-yicw-TWpOH+B-yWK@JL}ti6CMuOSEV5gKXf4 zBrj+Plk`QIwE_?k^<~+Y=h68anU=7!!zlf-UyW>c+k#fDJ;n3mOi*Vty$~M zl+^HK6`}ZJuMmo?oEx8*iZVi^Sq!Wl96KR>WJKm-XIvCoDcL6_@sdowtnSAwe_gER zGLTi;s@LT(L0->XT5%jrc#I>UySE>G%(Bncbf|c^> z{!S`LWyJ{cYY}RpRRLzR1tUAjI8~(OI$Ghiy zcN27caS@(#1RFVUXLK`wpE1-(OiWUPlY9-i3vjR*+eja9g^kMFWl2ktOdC3b=AVG< z>;2@*Y&NP5FB#N2TO&>%9$TZtWh65)r|%|nGxDAWcsQt|ih^S!70jw@2#7=nz<>%e zcATsvMrI{4MtmP1r$xRr=0M$+`>Oxrj7b7tPuHF>j)J3W&#z{O&W0B#-FYob8spbb zndd^ZawA9-OBq2ImaoWXK#2L)1Y=wx;HC z*WyF_EF1k)a%AqBNy@(I{Mmp6eS8UIE6gm+x#udMJOypvQ(1yUDzI%lT>6{~Uk#gU((Ykw_-Ch#;hLV4 z3Z@9zhC)RByfA$VbdYA}7M3+pxYI_N?FiOZwDkVA?=M9;2aYG(7QMAE38}=9U$>PpBKWWDou0k_rDl0y@>>0eizk074Sy;P|G7#7>z_)) zpGw1@O2eN@!=FmSpGw1@1pXxOCxJf+{7K+X0{>$Y`1e;Dey>R~68-br_RK7Q&mW(s zcG|BoA`N>8fcI9TE2vr%laPT2g%HKWSc*2*%{Pfs!3=-7gYMWFZ3+By3K;$yg)?c03+ab?Y(Zf9~Egne^&@fmQdfOF_*fy=YPnbSquTM|qn``-lJ z{6{Md{{eq`aaAi8%29WQrTG9I{h4t2dK9j<@Y&(8!Qc7QPu{>@BJV$dz7cpJMqBo* zhY*i(;=px$8&ku^bVfvQjbuDXU#W9L^Gd477!=1TnKah5TDMA-6zd$~QnN6T%aSuA z@i(jACk^-6`C3|>z=}qMvx}<;DFnK{%IUyfBi$6=+u>7jv#{2)=y{jK+p`y;0z)~8 z+}PQH2j2OkLT49g`KyEE>E^@I#oZEG( z>|z$RJPq87(y8N!6`Xwocz2Ed5j{*8JH&TrMj&6y+}wY-iuJF{41YcU7yfkC|Kc*k zzr&mQw;})OT*Ab{$n^Jkx zO-^}W6!+2MU!OxJK1|R>YGCK9EYrMqv3%~{x%OBY8neT^rw46BvHJ~_g&E{b?>nI5 z$^|B3VPr4N(WATtPPDy_C~lJ~(zm|~083^oOI796+dle<6?E^Z&uUG-rn<3Q?Pj?O zsm8&2j*fsLrf9*(;ou{@MBVy`W92DB)q{r;6`}eqCq{q7ntzioTd)_m6w5#$-;xxw zw3;AelngNidm4?LxW(oduw6|w@982jSVPKh%3&bSA(F(98f5B_rrZ-{3aM!-p24Lb zK5*5RpI%P7sMlRA^6(-@5#rCu6^q~QBHA=?HhM=jdk0`_*C1#CbI_^az!vnB!%lO8 zqQ)y>>Z0Zds_WIx^Q?$Qz`nJoY`rJcLtsta}wuzhumiqIj9akOMD9U+8( z`>BjWBb87p9VjlUHK!J1o`nc;5qu*dJ%D0c?#;6x!O#M_M7=Ew=ATvUxri{ zbr1$(UH=R=RA#7zsP%r0gN0=U;sE|34BsAo+U11Tni8PslEXFW;T@8MBm`4tRxl9M z7}ju*n*Wk#IwqC+Sq~?BK88fW&(D%R^@QY*F-Uy%!#Diw=jbly)t#eZYZ*KqKcnU+ z1lm%!{8K7e2{pz~9qpH=*~N=%cga)%iTE{Voh}DZ@=Aa4Hs#d?j7RHit+R${!fGiC zHChpt3}zehUDdpmi)DdsKav9&;F22T??N}Kw3jhAeq80J4?og%W;#%N!{gho-*2av z`w@?dSafX5y;bchBAnSaLimRA>hR^3*3>>SM~I2JD{k8m8iDwOKw2=joRt^FI;(iI z^P-uMUDx#^bkiQpmH1Ok>oTi2#tZZtQOmW@(5Z&b?Bq@Zq;G4faxu>A+C4IUA@+S8+C0AD|jKo+JClOy;!AeM190+xxDz zqku^6w@VY}U!A=DSx|}b;Pwc#EfYn)b}RA5m+6MRUt?4P-qc^OH=%1M_0mdrNt0N3 z^fWtpv9fY~c!&nOyx{t^frgWhNZic2rBt87IQmI-o#97vIyL^*r!K|h=5m+Cv0itd z`td6J(Iga6Fy`PWIqhZf4l`5a?-rNK!es_6}Su&J%)TjE&Axn@j0$; zL1jCH(8ml7_>`H>96X~*Lh9AEZQvur*}K05w*i|F_h}_bE|Kk;+p>EuJA%rwOD@A_ zHgP$1OCf=W2J-syW>v>$z=I7nM43zhXN4@@lseBeRd=Tm*y9E?SkA%O8+qQ{Rv(fN zT&R%VGT9k~J_f0^qIYPL%e&i($h4O6w#ccHdxz74G+33Fw`A;v5SQ**=g;4&S$IbzlV{Yq#=2?l_e%Y4- zGu~)B^EsGc^O&wRW$>2T)VU78~A z-gKHmJ)Ayswk|LbKCfyVpl%=^{1m=!D4eNvm$WgYHL!yKuFRR5^wfKsRx6e)%(U$m zt8+J|jP3oB2{1)$c1uwkXPU%ZkAX}T1IO*APMW zGam0Ae+8Sa&UZ1-n}jEHFxurHaO(8?JuTH=T1)jU;yp(RpTOQ|BH-1 zVNYRndU(_PbaH>x>u%$(3^>i*aJck1vkUlHrC|-JlEb%V@%xjob1y=`3V_Nt81(+d zMFX?zWw}a#gaE3V@BMii^5LPi`J0>3}_EI z-LK>{58)XpxN8u+HnX?>Mk)_pm>!CxQ4Ry9cya(1%}Qzx$TUI1ExAiV#07)_co z;!0=#q7k?_5uBC|vbr=_9UBaeK_ezAiUeLy6qI&CH-v9K)+9bWR%JuysdnO|M*%9x z!H?9xZXK-$HfmC<%#2f+>_k+VlW3N*_S7_B?E}ip zX;gcajOUG3n*fXHgMG6_F%P91#H)vfy|UFgAx^r3;;Z!=vl9Gd2c9&k3HowCx)YK@ zYaDU}8k|1lYDsQ_VnzD%x82$&QG6{F$p%*g(HPkj3Y+zC#E!W-ZeVO)c4Au^GBeKz z_LanGR@x9rW+^I2wlaj!)wE)4M4MHujHw1_oYT&Fdk47X2;aPI`eknn% zP_AAT*bx|Q4!b_vDPKD-fAXrS@QsY8tLBUulv;bD5Hc@=mMR6q3Qh#KO?(szOarmN zrvP*^QeBo9Nm+E*&Q26mi&g!Mi1{XYL09fDU{?bI#rTO8hYe-ajs9CHF{$J{gtRmW z*O4mr_9%33LnA3%Z1gp|=nnR3CP-}mfY>qG2(+jZ_XL{Vtv%eUE>U_GsMfY*za={} z4+1KGD>_WPO(T^y8W5XMB%CuQLOod*5?FV_y*U*eQenp>>d7Vm1g?Xnql^)(j-H!}q3cjm{@^Qn zguIs{k)eI|FHkKs6V_IqatfPz@(dUaoD?8DhD!0q8KvJYbKtUhOdw=b0P)j-X@t`8 zUJ6MDB1qWL;0P0eO$=U#D5m7bTmi3MAwr`Hnybh;3qFiZ#!)R^1mntRGE$fD0gh|R zMNiWJ7X(-17^TX-P;?^-Unbd(@ZV(en602Or%J4hrf|0*bmP{wnczzB;Z(le*ra?+ zm}nW$r^~1rffHe~g<#OJUUT$a3`9j5ils7xGB~>~=fYSML-Yf^b}9#g-!*YidWB~6 z3I_ZXm=;Y{i1dG>(VX(o&Xxg+Nv0#ouxB|2t

    4esmR*KoFO*)tmU*Thqta7uvy9 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

    c2jmf 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

    }LmmDe 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≪@oK)Kdx^ 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%0ADg&btiNa#fo5e`C(17qDW-O{K8G!v*>d>rOh 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

    cpT=?2oaVZGyoyJr`Rxpc=D>rOa=71S^tI- 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�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≪O)?GM&J0q5| z7nas=o}ugM$d$^8xzn!Ujq_fIoDQ{~%`i_lDbr_Bv_86zxIdp!OAH!vnbSihY&YB{ zxg!jbKu?1%2d8uz7j!B1W<~ci#AawGcD*Th6}l`p7hbZsJw38?D;Oq@+XUoU$^6ne z&ow0I6$7z7bfQ1hLrn^1r;3e`{9TLqGVd-2S0ECeJx_mD|JeFs|3VifZ*H)-%aKfU z$%ZR6+}EahMZ{=!gA&67S%I1a%OB=R2T91#dha>cR_BAx(^85 z*#B`123#?T{wMwLsmvI+D8-%+j671j!pys8UWnLvSG>K6$J`NoF)ewL@TD~N@x@H@ zP|9({PX;IUF69z1ELx?2EstU1U5MN1weGS)ufK@?lUm|&pQ0vtx`fg=XwA|bwH&*) zOuA6I&S){`>^UFA+CWufNraoc%$~10J%dYjQ0t}J*!bK=dHZR_$Do3`P^_~}ymRPPauajioJ z>nIH_)@6ShM*rd2K5eRIcW+U%7@tW*2RK{)a{I*~2M zlDfz~#Th$2Kj@#slL5UCUC4CXNFk7CN{owZx&gP0!>DIJ_&`gjTjn~wbBKYzvOIcn zc$~8Cigu6qvB5IpW>!=iJDUGf1ESe(d%L{s;}5J&`FiVextK=lS0NLl2u<1@%%i7KK(>HRszt<}mw4U9lz_ww z+FvGXXEuMX^AGQ6j%?en1H36jR%;APS@14HHgn`8l?$3K1!FDti~Q3T-(&~7cg@#PGTSORzsLBpUx}%_}}W54#JoA?Gis& z^(iLR)qlEle4P7!P}OPUg^Ksc;RFdOGb09n4QU__Qu+?@6^@nOJdioWh$brej}n|_ z95W(u(i7f41LDMSsV<{zJ#ZIPb-(^F-Ce z_w0*mdz@>8nXDHn)PKD^)mq1y3-~i@1kU{@qgrgyt48dh@J$_H0k6kH1^WCoi!jVy zQhkF0dFO7SZ-FbLK2p0kPhUGGqTrqFM&d4B4mUTj*Vptn7uGA)1#G2_4JhrE8X112 zmnh6M%w%|0I#C$pycL$4*s5cBwI0M#zl!eNr0t3{#h5xI>6XZL$f7P-=C*jllg+xSo?^uY7p5~&-$Wi>`bCp0p5xj0oACZ$L2i6QMJw@P!JDu`IPlk>D(4LT1fz4OFb3KRs8EKn?zDN3ABt<9s0)`?gbqJj49>Jp={@wltdpJYTo5N&v}Smy3VkF|bBzs6 z9ZYo)D~g&T+K@N#_yk*g>8Bx3klgfrIvUw+iuAmHJ%0u_6Up@jZLaLPl+SJP1lZ1I z_uU)~bG3*NO3&&kQf+@{S9U$xyKD=EL$e>9`uU^~oh{3~dj&+}6`;bGOLMcs9DKcN zaiATd>%YbB!rNz>o#0}=8-iL#m8v|bmEBsmI&WfN5id;bHq2-y80RebUTIif_{Tr@ z-v3tkB;S&0!%PlaMnKjcOY4}Q(Q6GlzHBi0pWR)tjsjpUC}Z>oWHeBc(q}yR<+PKc5N8(*K&>muppqkIFX&0F<=OlLKg+ zisG6h-f^YM$v?d(tY1vjKiaaZp6aGJ*9qlf;h)EG%+9g2d?DdqhK?1(7O|_F?;Cbo z1G8%ENN=m0Tnp_C&SjZq$Ikq68tgcq;UaULATeW);V`8=2o7v3;f1#|UGYpjR_PFy;VKUN_O4^n>HIN~3Ka)K>`!4xTjE9wk+$Ncl zW@_dyZw4gEN*0ap`Dk@F@kaTvoJ|@Kb@McaH~&q^$?o`d6eu|+I19-~n2I&tBZPea zJHoQ}0rW6|;^}F=bMS{oiSzO8Ej8b+rhnAvopRb=(J=a*X8O?%?2Qpq;;&K!JKZKB zH6uuxWz09R^Wc5e&g;X0u2^QZdc$6>6j8Ny5~gRB#9cZ+StRD%#cLyQ?-u*QzO_1y zi#bR1I4*y_XVec~yzC(62;)~q@yFpKBhFycH5{cJZ*%WM^=2Sxs~jt zQl6ZTR^50|Wh;+D4G@TEQ1!tMd}PL((_HB-Mos)|fN&Wemhb*#T zMTFl~_61Yx&tR9uNQ5z-|IgJAfVbzR;73Qp z9QL|mh-JN2sm^~pnS^tY;-MGk+{rXHlBaXwURqOmJ0m+3W5t|2^kU}bu%9-tMoyL0 zU@CKA(jkz0pI5f$Wj$tL1vy`8?6j1-|KnvtX}u$-ql?jLIqR9%r|2VE{#g{G>fvrm zFO}1KiY!&)rGiXU(fqVxhoAxS?dgo)i{jtZ6^`gq*fYdN>#r<*y?@@=)^}R_M|kD) zFpuXd8Fxr=3mm;%mD~@`U!I;RJJyFmPJ}{aH6Zg&5`qYFDr5xCa)+TId{$U*>;!)c>%ytTH)(Unl5gi^p=HK8%LGUv zBe>&niz~c+hq;d4iC+IzXvN_5Q5Qg(E}hE-gj2D;ZYwX91S z2c^X*JO~yCWp(T&_`|#KouZDHp}TsxLLW+Z3&A6c0|Dg+PI*8s4`RpnerC#jV+|Xu zh7e;-$(Pg@zB2Ju$&7{GUFei;h>yyvB2A=t)V4?lebv#;kFj%@U52QuKXx|fEDh;# zl8iBz^mmL8yeKT)P-Yc5>-OT6!|d*B&b=JH%`2nq>`NG^_J8{LZu&epE*at44XP#D zLVx6z9B%XXJ68r$wKqhHi+9XH`UtQ^ywZnyx{2BjF!w8AO-bmvK&)=mt`qpR7Scow z9vb<$lj`RPGXD8Dct<-mLD8V`-M`d?n{|R}5fOGB-tup2+EZlOyca&@pO~~?ALi{= zCiz_Bm!s!TZWBb0T%7^~j{8XI=hX|3kz+>ak?rmc_&dSNhRp7ihjOZk+O&{!&=^pC zYM8dM-~Z9lsxUy2L85ktYhJLA9CyrG&L5Cudiza#N|_xDYGa9d>C8i4Jc$G;j| z-m9RpH!-}0Dw}w5satTR_aMYa^{oQ7 zcNKlR{h98}#OeFP5iv~10YL@O=fuiX$x~>%LR1K41Lc=Al=0HcdCCybX9cSF<{o=G zw0a=W&u8bopFM3u3u7qT#W%@+#uafRyu<(2FYY4_QQ&-8YIt)YeR#u=^BexR-Bhng zpYwN!i7v%KtjG`9v(T!vt*dYIcJTB21|euFUQw@^b@AEpq_X4lKzwaA*7bdGo0Xz+n(r*-UM z#tYC|r|9AqO4H{>J#E!3+V@usNxCZYnm=@k?7C&_N!`CD)sdY+^#}58lJ0@r#Me>_ zN0ufBtRVIv&5cX&YX}LWOq`FQSz%Wp)s$C=GnQkcBq$^`q&X0VMt&M@stm3KvTSPS zddD4}Yfa;XLCyVOyEDviEO72*-=uWFrVcXTCx^I&5bfOESx(PODZDrR`LB22ghsB3 zN@v^lG{SSv4(D9rmtE6{YB=K>^9nj#&2^zkAD)@HZP}ntrfn4a`fqg_ zgM8KCYl`Xs0mJW)0A}RXZ)_s5<^ie!i0~ErayHG^xX)&Zbgx!UurgGdN~Zbv6DZRwlH3vnajZjx>0mvkAJ(EO2w*&vw6GbjGF~@27Ov$ zpG--dK^9I=BTM`f^>F{*bQ3uz36WUawv_^rF+Bcs-o+C-yC&pNN=L06a}RI2 z{z`Bl-2;eDYl|c^o{booUSM_dYtufEx6^f#xC(m_$p(@q;7$m`vZ$9+@j|(;G3G}R zZmEh4pIR50l2+K{e4}O~BMs)DXJY>NCEDW0By4*q?&QXnOSoQ!n?pz!Livg}7;~y=VI6RzO0iCW8 zZDXGlQ_r#jzk$;)EWj-&s$0g0q)9wTC)G&}bWsOPmL!^AzSg_Cvqs2K8LaF*=jrXI z(P=YB2(7mNy8eCN!>~%K{mgbR-EFGh7b}IlIpWBah3NhGH~jwP$t9DS*~qwF`Aw%5 z^tRk<{zsC17-s4&fV=O$3nSD!6ZUT1Fj^tUHRg(O#r8b|5tn+Rst#ClcE{b)ZKT7D z5Q49amuduy@GqD7a>P8<)%X(Wytv1h#AqrA%1XWVu1m*;(8sc(qc?A#r=j#6tBk#M z@!AOI`L`|IO`<0lz^!flcZ$^jn3fGpv(+}QPY$z8t4e;#O4iCX)1PEzUshQw_P!JM zD$y@LY0+^%3Rk!-Y<_LK^9}mBq|%szPRd=t823QSC*B?73p$27A`$Qo11q7uIkr+{ z3<94R+?=_LPJDUeXA*xXUTMEvmyuuP2fR(ZFB34V^I2lg^_QH<#`exPZD_2IE7!1x z>5cOelr;Df4rz%1=i=N;;WK1h$(gnZ^@IDGB6xmIPuau2 z(0%PkjlDBQtZbq}jRnJT^+zxBI{F3T4i%RVtX15|CU&h=U|%f#HwtLlL)aw5x&KH ziAo*b^rD0!Jh#P)WlIG?Nk3PUGmsBtNy*VDPcTW%-o%D{ATOMIEI9aQP(H`c@Prlf z=*Q`9tu0WxNoc9BEFDMewmc)!z!slwFE{C_Lmp$i2OgeXq(3FnA$usrqM_y5$dal=fpW6dbe(0P8&0!xkizHyrMX;RL z7BRE3;{EV!*-k6{I3s?8?Zzg(z6D$aX zk#b>3+u!7iw+0d91m4Foam?nU_!7c3K>yTedNsj+5<}g2pbxUnFF*5 zC;kLMucfn}OPu)@;oC{SX3#0Dst~kBH$?yJz8y+@B)!eB{Y5 zFHy3QN(WV@dFu`M+a+WC)iY@>cHJ=wp`0;KJ7@6DbVV}!6z=uiub`2p#aOw_r_r^c zd>M*$%E*@#95BnmIsdAY^MPviBa~gs!gz?=z4Eq@h)c1UIe)QhT>4}BrBsPJt7xpg z*fLF|L0cM1xK=0zaQgc(tQRK+XHrl&BkP@zTHxWTU|xTqwddKBY~X6o<+zo1hn3Ye zPdbSlGaRlCNd3YkymPURjO`DoeN4e9G@uGAk_*}!#)!elPLUov&v?5)V)?jN%-EU| zKsn^#{;BP+LXBY^AZ_L)y={nPJ`O(s5|1K`tEd9`x8V3O57P@A8DutQFPw1QjBYmD z&4@nK(*6^1)J}aIi_8Kv8h^`f_FWwnlb~HkAc0D^5HC4p<6Of!*cz?{<0%mYv1C6) z;oMgU>G!)~6|pK^`PHS#`oErkf7@q ze3ZXJy6j>BJ05cNKiDdKcG=b=${(`)VRI{Sq*_g+YJTJJqZt#bJXOcMtX|YC>_85Q z)(>X%eazE1d93hNE_`~ zV}V>XdsH@oVosz{EiT~DynReZ44_xKTe27f*lQir7AID(hIz+l)VM+4fyN-9f#XY* z)>V!ISbU#W1lC)~TwTnR)uhe8iLJ0}c?h=%9#B@q7a3zq>6&sYru|a)r5g^y_d3KK z$iYm;j@j1paQ*}MRkVN$mkGLMoh*Cv%@NX5NFN4=hpR1Nx4)U>?<~S_6H5@tU56bi z9s8&*_lheNV1f7wml_SWb^%SCE~}P?s@sEsPDR_lm?`{!yig|;D&%re0K5~wm*h|k zjVAIYIV7>b3=M6;+x+f?5s;}AQF1hXL}}k)_Mv)a`<9iVN3ri|QnNjcLF?QFRRozg z>@7HlX5q!ILaTs8AZG=k*?@}tnoY@%2dFho5BFzVj)CpLf-~z1l{jiX-`> z=rV=vA=tH~2g0Is<7SLnRb^|<@0en9|83!yJr~DUd9SV{c1#O#%dFH{K;Kgs*@DG` zcoC1}vhyJL_`wG|0C7ul=R!c?hg}~I7Y`VtHPR24}RbyzJU9WaA2?hGEy7I+d={ic(k@wGo^WProy z&N~Z+vJb}G<_7>^N)v{A_mdW*vS4HLp-$NYJVZ(;n1AgeIj(Cw_^O2+1dG(8{FVgQ zM~C{BMd+#09YNsb*8gsod>5HVYkmLF6{(Fm8YR1>P*8YrW_etxMy-#et!^4m#eWU# zI{`{!03}8=mYg}Ofp%KX*!;iQ7qoBF3U1>YbHj7695BKcrV1bV`&{DHm0NT8A2SEa zOH4f>t8rP=of7EDHAb!0Z1TRJ1EMA{!+&0zYpPTW^gctjrz+!}m+Yjj?fw;)$>F7y zf6l{0W)CfLxwGPJex+DPzQWPi(*cg6unx{N|QomxtV8kvu|q z^M}stbE|eoyW+Q@uxw~?Ivy%fKZ=>DsH572xD{k=MHfW!WR*G!MI4_R0jTy#kQDU zxh@)FZCjdRk#U@uzFi_u>bHd|N zdWjXel5yxg3D)n)+!WF2RlMV>#@$N3(N|`uTz)K%R;3d_G|BUMEo3JwJZfN9em0oYHh%P>$})o zvQTNs5h=;Z=mqbiqdLC1{xGQi(>$sGy5C&b_gUv+>p*Y>JDQlDcicunq7Hw?g6x*b z1;KOtW;k|^j#efb zMn`S!$(NVi=yNUWouou*`Krr#s&wXVyLynObJz1OeMc8$zL_{3;HbQCM-pR^>0#~5h#|DErNtEq)6G?y4XrPPLNk`vRcADA=_O_5 zxDqXciWAGQ!`K9)iV{Y!M&Tw`wQO_+I+qe*hGz!!p|*UL#;ZuOmD;=;y?rEWJ)Abd z97c#1zrg=e6-<86btWaMNSVop-8So6qICK#rVl9Zz~9cVTP@dH6o5egDAmi(SWl%W zt3U1-fBCzpfRC9|ES2;jn>~OABRnOLAgZt|MWft6QP^0{5}btW5^$PUS@Wu#Q6k3W zZU-`6=p;rHFb?@4oT(7KXLhUMX&a|TegCCevU=Xe7Ix@qlh%MDN5LXF_VT165oxC+ z;|J1VFd=X<#-p>1GRb#ZDXdYW#~EZSnOMxuo!Nk;pp!bUX&&snQu#85`-P(1*5Og? z+7V2Kw+Uj_v!Xy=`_5y68BW;622ofJ>-N_n7_o`<*s*iVsqnI`*z-8xn*NhP1VwZ} z0xBX43lq>2!eIu9R1>8__*VNnu95auH`8p58W!|wFVLK34Ad`m<<2-e5G!rOEK2Uktr-D?i6{`*rH(%R1F!7Z-i3BFJ$uK@lSL2I?^peSuCgF7A`Uunnj}8Won(#L-x4K)2s%7z#ynT?k(V7x=|-9$ zivyNEoO8(SsvAQ%xZtnr4;_-<4(1(Ox^}eaS2tnvAiYF09|IIrN?dIwZzaYGHeUWFAheou4*g$RP zdM|}|FoA$9_^&k8ZZqagva5_pHJ6J-1e0)~SFO%Sn?yUjUfD`2hFg^`VHd>)W^T^_} z&i7Py&w)VPUvbYYnBg}h_s~faIfgUoJf#c~N9i*|G`X^J^2u3}gYUW)Er2xE;;{Lr z-C+s*Et`*?yax#1!Z(k5YGD^Or_jgj%w6b*UrfA2k8q`yg-rdD6RzSc#_+s@e^+_) z5^89b(29!(1~2u?c@ep|;_?buH%_exl!FJ%(=+IAa){_*I;;z}iIlnv-dsm`d%nfd zPdguImDK&te=#`7$@h%=0BJu7ln}P)QfnBbKX`eq40^f60u zsEx`kK_}Rx6<_N_!NRHTd;4If|4kvmW@2@2)Zn|bcr@2h=qoJiC1yJkvs%T?h3V*= ze02e>iQmUwc9edY_)!{Gor~+p{Dq*C7%B7|1xr{7`-ot{Y4&uBo0=c4S1YYk^)h|6 z0E9MoQk&j=*ygE_y#J9b=k`~HFQZ|7jffILu4#_n1B+1!CMpJhM_b&DxQ zPr!%Jj3G}Kd*GqZHf9()$oJbuBiL1-HD4%=s5)PmyYMc>-z9NN@c?L$O4Svfg&-wf z4je21y{m=NDTaNof{pe+AMAK>TDrN$^YE-mhWd6d3GwTuK)lj%4d`lc3ub@`i8iJ> zR6u2RvWPOH4cs|rk?S|)Z| zGUGN}V98?)Ib1;*O`WY<;!wNlK~VOPM*7}JJ$}X)q-SSaA`is4%%T-Hxl=N#^(c(T z`;l3T;F=6kXLct~f#~nGm>mB!mi!v*d1Yzh_YndeK=N|ChSu;HiCbn6Zv5F)w_aaM zjwA&=s!oQ&6oMZAg*cU-K=Hx_)jVS(N?3W0rsxR(}8$f^+|}v0+CB*iW|c8((fsT&AmPejv0?PHXsSV0P--T3RS~ z&?yHa(qND!mGRQtPfQKGe>{HMdpAf=g4EiyX_oyF!dBvPUL)4{mj?0F@FDLyN9kb0 zKKb2<9dEc!LUMLLKQ46VD+9Q$Ss+L4+kK1eT-OXUU87(D1bK#M5~|Yl=zQq}UgE#p zF?jzKFFhm?a2DR57nQ_ncKpIxl1I2PC>P$t%Ma~AS&zI^)oC6;nmH75f8=8wb5@||+` z4fK02ABJS6($%D=$N0I@aqiwc^Dy|kb-zrxhdZr9;4a;0k6Mw|p5h5OLewtwfcDwY zA!tX~>w}GNg~PFZJf&;pcKePy#hx}l=^Ms_X@c7!&ZF;6dAQ*$At z;ERF0GWZ}o#=XT?2Q9qXCOj^Npu5qC4w>@rsb!Z z*W-&&P$`zmWApTB?|hQa8ij+j@eX?<9K{%WA+AU_9i2SFTQ3U_Ril+o>t(A9`29t& zq>4#v%!}6^>ipr)bnd-g@iUOPdnnAToRxMEz zZ*No*pXg?SIuyX~NLpcqKY-@%J;mWdv!WgyUN5_^zg@pRgLEVx5GNdSTM=d^kCXd6PFLD{$uKM&eV@2}D6Q|4y_xFkObr{XM8n*md z3hUjVN^gV0X7Zd>I~nx!Dq%nWw0|nC^)nSz^3LgaWEA5|myfSk%BSxU0&$g=JXV6$ z++rT6~MNlMlgob!&`bv%WD$xp0+EfCXUgHmM;)2F1i>1}ruBIuq> zUV^zp2?Jdg8CnZH6$M(0%E~7;+CYz&bDW!#{K^3B>k|!nNcq7y4I(o_&dfay#2{0p z>L(bW{SMo3KYUII+e&10X+15)hf$CGTp=n?i0-WpR#5CIWy%_p8kP`B>bW zHe^sNhWQh|8tVyFxG9+7MyGgHW;q%DWMmKzQO`^m!JHn_)}p zx!Dx-VU*hbve(jE&5^s+z3_Mcoh z&x)9g^o$aQqV~v+4xD^T`guz<8O4|~>y&n_s7JlKNA!3aeI>pSG(-<-Nf|TB0EIk) zi3%f|IGoPCRl50to!Ha$-H%|Pz(Ew^F?9sh8onl6Bi#)2l-{s}xcvAd8IE-yvhkp9`FLpL^I_u2(s z0q`WON;l#)Zw6n7-<@(b@AlCFkz&N`+76E@7N8rQ@hMylVR7r8$OkUOR7@}ZH$+g* zGVZm~fK4Cw;Tg& zHb~h0?#`L{0-AlPrf(DL1B;)>^C?~L=pSKrFpu+RFWdG}A5_6kJ!GoPx#~FRx~+yC zz?=jh4dw!g*Olx!Ub-r}6QR zcycZ_Dn521bY_{nQ;eC6ySes%h4U6)k2c#<4jD9tuL!=eN_VasGp#}87I5>UsZUbq zBc`RDS%BB1g&k*+hti+ zD`R4#rggc{e8g(a5wDkjv0dGqi*_?g zaWOteCj0n&Csf5e?^U^Llh5!hQ_f8Y$*AqvlEZC}h#zq2^_bi|4yB_QOCvMVr90&< zWoG2nn4s{rhUVio9ZQvp)CgLG6W%Z=x~F!{rF>}|E`y-~ zj%!A9Wg>D=UQ^W9AGxeh6-y7Z=$QxZp`6f;UF9wpghs8kAz|2*(23`$h)|?kJ1+UC8tp(L`UMDN-Xnb_#PtkUt>i&^4HudJ{T@E_O^W&dnJCo2rgLjRUw zfQVYT=7DKEI`Q{NP9wp*U0I4!*}20QR*wT>+{2sTjCKBL-)Y~EVhp!X`T?gMgktEZ z+fpL27{kUNQZKmD*>y~U5k88jTPv%Opojo?NVuhXLi|PH=ML52mf*|K5hOb#pf{dG zyfe2J(>jp&l|$OZfGM}^(|6;Mw?gW3nYa71E>aX*^`ulQScV3hOXPLLJCJNV%ujfy zkTmiMSPtYWm~1>m^ERr8GVc~w%hf}2c08A&nIuRYOIOnsGt2?x*nWQ_G^R6@!TS3g z{S-SnOB}fM+0$||!(*>Y4^&jRw5!Y|f|B4=IK>SEvhh_f(?$EmWUg?yoAg;+v8!Qq zZ}_9-P9${fZNfv+L~C0N8E^!*JQiNp=JZrwa$R#u^ICAk6gRyiOfkRNJ8z?r+p+Q; z!G}4>xdz~|%BqNUofgGVa-(V8B_a$tp_O&s#-tvvNI&_OF%*48^hb%vI#iBI<`m^ZxfoHh*rEbN-YuFmxHy9IuR*-;eI zguX^BvzwX4uJzI*PS+!R#+tLF3>~XoCjQ3lTB5nk&v7bZ5f=oON0*A>%t5J{9ru+6 zTncV{URQ@!M>|yW^VlQ-KfCmzq%?vQ@Gt?phs##gv3}T;fWXn{ zTC_v3r((fAew0cA0hJW#r~Af)0Vir>MQo~zZg!CAHNN&B;`#WVrIt2@_iZM zE~Z|R#y4DR>a9^t3?^&*8ot0w+91HP8}E|+LIaL0O$Fs_mx9gD!aD<_hI98f9LU%(zx2Q6ye%H>@Ekz&=#S-m?UZ^a!KRwl5t&YWgia5A1Y_-lW9sDm z6*w2sJ}@g5c`gmx_qRknnp|Y+gW1a(Kh)Kp_%v8y49%wgq?Pv?TF?RG1PnvSLGZ$< z`&)Kqh!kemBy6Lw(+w5ORj_+@9xr9ZO z%j_jX>4?9G3>Rn;v>H^+KbzS*Fp}O!C76p_T$2eo2xmWTw+7UnF`!nxedRut?irEH zz!w-b2!7EMEGmkf#i^SL>xJhSNxwUho>`%`Jp%_y_HPC+Z-b*Oou{iTZHf&$xrY^d zS3ad^SYq6&VYb}(s#E9K%JfonMLMKB7!wAU*NLm7(pV57QEGAy+Kt6v;@M;Y&Nrg( zM+vU}4oB=lvLL+dE#!00H`9d^Km>hQ!)N*G3gS*$D-$iXJ;_To{d3G*A4xCad*#YF zTtt}LJqFhL{{CLRFDsN&K!cQQT-00qUw~YQ*F(si_ZoFSnuT;z2lV`8L02c$TqSZL5{qtT6jFX~=jB!zFoefUsV|P#)M}#G;A6-6AZCtXmp=-vClHY) zc8x=*6uC0r+@-;M51&=JEPtjyK?2o`1PCTHbSvpz0yE0%1=Z3TN3mz1j;2J5L_T3X zGIDbTq%rmb5_eUTEXR6Kv(n5IXaE2lOAN``rf&LovhW(qE?z2Yzc&<>4%esi&4MQZ zE1BQHoVC)780%O0{8ku*N@Nm`9iN+>1n0Y&lL#l;+Q7Q&F%5YFA-RA3XJmi^9X_w)gSr-cRR%dh%EkWN;&J zDAy8*Z!cX)(M5Fa{0dp@O&aQ{@DM;EECIDeHex4gu!OhAuH6po>{6Q_!iH&%=OhsE6?SBUz9!_&Dzou_4#7N8Svjh;e zvS!0BF>v9{w{Em~Yv(Gx!U^zwB1LpM$&Km71WdrO8VG6ZgdZco;I{x%w8dpx+?if_ z8h-7OV5j1CG4)SWS?#wtVY(6*Q;vLRGezdFNAWPhu*pvdnh%S#?WorVVI*oPp5x_W zfB#D-RYbxkzE3Pggr_fE`2A+qKys0pt?Y_^;IT9&Y(a`rK!jT)JC)d$OlyIe1dNr+}$Yo>rrd zj-clT}`GsqX~|T-MxXy%OB2xr?wi;`Eeb@e|%bo;IrfS1+d8_CfdwS*P7w zWGv=&Byp%iK|8a~{`d0E%n@ZGSNexRH>^O*oZoEt)2>sN>4~>_=+*rl0<^rQt^4*!vM^9V`+ihD6 zq$+iAyp!$kCXZHZ+C7*regMn+O->)s$y~hA}$fW}I{RnxRKSa*>3S z0WJzugryeXx&Ja#pT7YZjv!FHNMnk2CEX6B`PlOlw+oiUJgGBvw+}I=J@nye%$!`I zQX6Xcj3;!sV6DzX+4GzjQ~OsPfRJPzOBgUTtcUE^;ZE1dZSzQ}({w50aRM(hCS2di zkSIOpURQH)aknshpY8AY_I~f zQONNn+M6TXFDRYKsr zJy=bes+C%J-{$Kg>0`)PUv-MbTYjKEWXC^(D?L&w^}gq^DOyS*^CIR-k@PDbQ%KcH zCI7QeKLw$1_rsT)dWN}q=ItprS-&L+;x|}-{P-a{{`Ez*v*^KSzj;JW7K;aMx|*AQ z&l?T*Z(kDkJib16hu3Bc zgv>DoswG3X%kAx9ChbEM$5VvC+X{HZ<>5;&&)1R+Yz2QtF}Fj!fYffLh_@F67qLIK z2K}yl*nDQvtjx7@cw0(ALxF|TXDl=!SoGU3_QqGG+^6(rc8*i-4fSzl9UCE;qRcdr zG-LV1K51M1q^=N4=Xw+`7uRPk7fUH%8e0)t?_&k<`SprXrNw&*TC59!3MF7ZvxsoR z2x(lm^2y-|$%B8GXG*4$MH)R?jD^67!-OL=a)J)M+C~fX_GZI2hp5O+i73A zOXwZ{SGK^QrTVW>h`CXX>V~**F?PNJf0q$+rN+E+0nwrJT*wZ7DsSMmLVi)r^Yeg- zX5kioO3S+YRtfLxo|ZtZ?v=>FNi`ND=WJdBxN*G)ks{cNMJZmjh~zHD^H+ah;pOqh zMtyJjXy1KOYFL$ZyGPzWfgE8GGFDta;L8g=fa^=vrGZzdF(aXofMu=H?L1o{u5Y!# zE+SY;U>#fHSNX>KyMCq^4>dh$wzNRWMhq;VRGfk|=v~Y(RIpBy*7k0Twe7e!5va;{Bs*Wyrg;XAUnl!`7UdPL!3CPf+rrbCRQ=PlD_ zY{s=di8ZVYU;z?;N6S-XQD6WBgmy$yOGQ^cQgPH89#whE4M=F6?9u++LB(o|w|O1- zt*p%nm@1Y<=#CcbMS~iLs9$<|8a^;s$R=(oE1m=nhiBbCd=QFR%e%}iF7BGxT!s&k z;X9(XJ-QYzWVy$mEP9pWwx$|JzX{v6rt&QiYu-4A=gw zsj$Ed?rS99UJVU!XGC75PheV|e-PL|f&uEI0DL4rTqwS-g+Q)4q`iN`G_3x6IRM>U z4;s1g?Cl4aFY(wS1Y+ENLP^2W=K%P(Lr;)#C@aj36_{LP^qJ}UfnrDUom>i5_bn;B zB{A(|TWEQ8s3}=~e0QE0iaE7@=%YleMAKrF8;wx#r1|Sk)(6R4Z^`J6YQU`WK3k0j zbwj>fZEr3F@9&Kl+>E{*KWa$k6cqijn{eFu-Xh!q=6u0otx)cm{`S=_;#UsNzZ=wU zJCl-%AUEBo>|!=wD?6g^N@3M%p0q`E+%iEsb!TxMt`iU8tk1Mm0M);T;i9NVy8QpV zUE1H}-Y3j48h30~3q9OFOU=fpiJKFo|3oy0krCc%$pCoC>ihrxnFybFT^dzXOX<5b zbe>ilSCeD8R-V>?e`6fYeL&tX>^}%!8@dgXP92cYLP~69N+iQD876q9HnKut9RZBd z3l>L~a0yfew}sh~9=?sMdq>J7l`{v$8WgUd)?* zy0QGKfCg=2W_Z=ADj}{{GU*H2l6w{i0=jXvb>U!->xQ(5n4YHuwhsy^v6Pt4g!S8m zSg3k5ZjRbDKI=mhE$z^q2cMV21lrcy5DFx(aL4M4)USHUe@}gVi9GNBMRa&jZWLix z&8X>sD-9=GF`2JYB%&;pzOx~r@1^?4!OOh#0P@PvTADg|*m1ZMw_jA?HfHX^%5L$u zG`@r%XAW61`Y_^90jlO|eikVH9O*Cbm;x2;po*of6Ah1A#0M>^UXdgg`72Nh{;t6- z!FA+`jS#hmz6Y3zfs92d3Ewn`*~gHPSQR1CP%mlF_%v0~0e(+M6J>pJRU39h@Nb6u zlJ0lE+~sqXF#a;$Byhf66Ye)iked*Mvn{emC?(aM^lgaxf^XID6+E-FZWmo;EtXj7LK+yHj{r|gX z`oBJCdm}4Y9-jYKGxY!I-)3fJWnlQfv3zWttnB~4T)q}>Xq{!%kJrbXT^M#jI;tWH z=3xju0C0Lw!IXV6G%ARSJy!(<66dq7hip{5V zxz8>igSQb*Xo$QDOyx~I2m0R0{UmVpfW3mw3W!bd>`0%rb9TQTJX2rmZ`4I` zC{CA*10Vm0YJiuaXV84oYiM-t9d7W)2>F96mQyUk$QsdOQciR%Z~$y~c`MiEm_rKXTVg5nF z^pkItIBda05ijZXeJeL7-T0$KKF3Pri1VH8bN6GWi2N#|8Ag6aI$}By{6xS%psRB2 zwGromxh)@$tjtk6BxS23MXzkXoL@qcB_L1q6`_RE8~j4{4P?52NTvAgU3epzvU`GB z)Xk7sKqd@?Yq))fDsJgtGTIZ>zf>0dlU%TeXn)48j96P{9-Q=?no%iCPA3S__(>lk~zm)r72vr(> zCTcg176^&)d4^nx4O#&y(aH@n_?6L!RRpV`}(}Qbn?PQWDyddT2W1m=kY;-7#(g zQF#=rQLv}9mc53dW@NIasGp%R@UtQJu`|Q{&X6x=TdS(}Zg1Xktd}y|$&y8O)N5_O zh=Y8;kKn z+2Jav6Mhe-=9Z69i)IzfDs;odwo|S6Tanu;!(#m$^X$F8Piwd4c7=ag{(Lt;k7QIC z>e#qkx+3LfaFSPSF8CtbC8y7n+Wg+9FCPE&^c{6)()(TbC4!+*7`vo)?Z?C*c)MZn zE{=ThF{pgdS#EA+`l(uD7v=-EHn62vfL`d}B_J#N(Ss%aQ1S|36#R{FXUhJ5ZHS;O z;&%b5mAl1sgLeb$I*D+wVa8#mW1V@Wd1tAj{KDO6%=(F*an0dEDEJ(0#szB|YEnZW z`rK~Dlk??^Z^ow;D&7FJKHxO}oPIr>xj`tMBV)LO*Zou_gpdcQn(A1zCoTVk_Dh~` zIvv!QO!D7EYihGY9`@+=QN;U7wW8jd>yfxwW9LZ>9AK%^1T!AFvi+ zSML}bv-yHeSOoRyB6yCn9TpjvOIYuLJ_7rX#m{h74-j%K*zn5;d%~P8>ds`@07r7@w z?3E_Wnui9qMY$7nyUsT^&PS0K_O{L^%gl74(-zs_iO-~SW)Qs-N_?_doCs&k!EFq# zvA}!8F6*nl>68flVMn-8mQaEBlJrl}JH?zob5uw!9MIM>}FI)&%<;P z!WRcOXe4Tpw?N4~2sdOGTM);QojY@W4ony$>xFsj$v>I*FfL<+TkX)9DP;$?2Ihm5 zfImYY7&9G%GEQXN&9KF>xiY`9ZNccq7>*?ja}JA#4Tq`6Zo{|aa)5q5Wm;I59Oehi|{q-))=Lmc}VHg_t&Cd4!;b3hQo_LO**BW zlbd7CgUu7?Rm}s%8*go|_w#w4Sm~ng+vrdKQy7tQ=k%o6F=*78v~LHr?tn`(K24xqE$HBqVRm zJz6tmop<|sovsm=xckLAAr%u*kFSPBcfwx506?)Ivdm=XY9d@S^};?AiI#Y*RHCUh zC)Jd;3WtuFO03QHxT#x(-N`EN^%-ZitbBKSd2c7Vc*YVXFX`VLYu4^8rA)NFMDHtGdN#(k=E;dpFoq_@?2n+Sr;IFf~^t5FY>rF6AD zG7k|lK)X2Vr>4JAoq8bm6<3Sk+HGT2E1it(S*DF$AA-%*ZaS9JYSA&%Qv$%oqC*nm z&k_xK)b5O9VUZK()1@Bhs+O~dzjLAyWXiOqvslpXrCkQUX^)ZZ7s)5EGE2ufw6>$>D&rUtl83=}~ z>iR@D-Ot(e+G{DFRzOHZ1(W*IxP!?<^ad8Mr@H?x#^+n217dbaz&MUr<)bY1Z~(So zqKjZC7Ia-aqy$4P-E25Vi{@Dc&%SO6231$(Sh~}cX*RN&yq%_Uf&}-sX>NDXvd51VkX=gJ{N>~>RORJC?6eR~ z+Ac?hAV0l$<X_IlwT`G^lm$7+x<8PNIEj9&zGn{FGntP~+7dw~_;m*bAnGDP)Jn(2$QRurQq65w!HlS>(T%|DMb) zpyd~>63pjob?;Fkq3_2e+Q6MIsH8i1EiJctb!OTfLt4Lr0#c`u*rVT~iodWgQhAiTml~}D7G~Hf;wSDzPuth>yya+u75=sbIh9f^ z*ean^b2f&`E&_ktr5UjO+UPqbDV3NjkB(Uz1`qA4pB=DeP|wS%o?h>FFYrQAp|+kV zbx^#_riIVs@@!qD4W-eQ^OVvF^Ug0Xhil6oiEJL}CzV6zsf3m<%P=yJ8WQgc_b)xT zpxs}hZ@|2R@*-~EXdguTvfeMg9rn$D_a_40*w)eQ;$KnaC9}1g%9w%m7;xD{z*J9NczUw54s&8(+~B# zJaGlI9Ujf))T#+k_!qrzWGn&XCufi7Kcmraj?cY^RAS_cxam-1*&d;O7+cpUsqVo3pU zJVO_CpV1l9e+l|YC-wH0VjtV%>}AR(Retax-3-gUZACtmFeb}*?5I{`OJ_TjB~z&I z*WsgIi*Q>E`?ZieGhH8LFXO$t|LK=T%A`#I`YT)LwtiZrmI3b>7wYo#cuQVlQL`cc zo9FfF?D?qoQQ&``{0e)K6Gs_&H7(n;1OFG!_5=P+KFIG|{a5Sv-%f$s5fNADbK{-o zE3GWNs3}Ps3o2S(&}NL+n^%74rGwP^Aa)hDM*4FHtTh440)}URj~9|!fBc>Bs4~Nu zJ)7|frxDD!p3LLa5Vi#}5a@ZSQHfi=ZFGxE0ZULi1{4P zP`oq16qC%G+_#oiufE@ zM`qZg8#kW$6T+zZVa}rPHy!86Q%Msf-49b~7Zv40L4NsE0ccf?Ov)dPi?YNZ7anr4 zZPC{!!ODW_N+0pTvc&ip4NqqDjsk!DO57O+w?OW0RKL94f_59y-Vx6218zNOpCu=M zY^TgnhY|I%{;a-Wx3*8ASV($m?L1D6<#mABrYsy!dEo_3HNr+O`qU2IFIT_37T_K+ z4;W{EWq^xsEL-EF^H;#8sD5Cd;cKq@4R?bK>_Oi!+UOkUJ6TxU=TLL}RMjK-)e$#7 z90j3bdyM^1q?f;#{yRiZ;T$W=^}Fo8G`R8PI^)(YTu#-v@Ra_BEcfLmmy&fc_y%VY&iYX@{)whTF!3fE6BaG;X!r53XHHns6D;zmbZM zZxkhavRkg!Z*qRntLz#h#O#4-LrFTvseK9~?Vn>jp$*|bV*ZDoJn-yCyN<;n`+eF% z$!~TNd#owFhCH*U2p?g6gOohr(@vq#+E;D<=p`jHeRS$N0Su@g`zNmsdhvx)8_Mgl zb^DeBVj)--0h)Q}orVn+QV)NoU}3V1L-cvFa>U`|zMT zm=lir`TeQ2wsHGGeslNxas8+_ws2|_TzD%u-_C!9^fkie&nO6N4H;-`5J@D6KnLYT z`}PhD%a4821381y^hYvZ_w=?R=BLq1&?F_Fq>Z&{KWfimTdvny8Ze7}&i5`|XR*A9 zx6a&&VeP6L`_rUiUxwFpq-$GxY^z!utJtM{SNFpz=d`}8E_UTLQ0dI;>jP5C@4il) zdl50LA2gMB-_t+sf}BjB5go8u7f?PhPMd+e-uQ0P;!uXlMF?t^fO#U=3rtaH#Qi;s z?dyL?Sh241sQT?FokuC!?@;>->Y<5eB&_ zhc;6iZcOhaA>6L1LAhJYHUH66?FYDN%26l<1EUj;nKk zkG&1j?a1JFWE?Mgw_rDj<(2zVO2eCi@BnLNLK;zk^34dIPkLuBVJuezX(~H$7QWz~ z`Z-C>`(ZUEeD4;YeoU~(s@J@=H-$G_yE$}qjMaYQ7i8eYp>#4 zpxF)Wg&MUVNVlL3$;=$kcPv6)Sb8FxCL$ltMbVlFRrYD$&^Gkr|u^+f^(K?*E`{+@OzN!>CTbMf^LW@P7h7cid`A?GA+U=cUvbA$IoB zM(&wH*;p#^wQCB?dqtGASVumf^4#5N$>%|~OZM{WEoViLaFet*R z9I$`?wtwUmtYkNLz_*{GtgcIx8{&H}xM%e0m@@T3$5V>$#(!rEAgWaS@xpp(1R9L` zT$jTaaEB9$FE=O`ulVIkgzL?hhEBK{iRe7L9_qmLcpTj)%?m~M=EjObcgN=hJwq6T z?kxC?xJ&$D9NPwjAEDNz_0LtX3vUpQP4in22kwg;TRqX%vC3Zt^n5f7IdJAb zmj1DV^NUTulj61r#ZOvkbuJ_tf!FFx{}~SR33YUcdHvG3nKScjmeFNOu!`Qm}U6 zKi_@9m?xcg+fZB^BzR%tZ7dxF?U<^^>{p9}Cj+%Bkt?iSXRdBm{ z`_Oafsl9-^#C68)D!azxA8cxa`UKlGtbF>n^e)LfGOIU-^dv~zHM)pL?EN@SU-z)S z=9vAyPwu;c|IT#1V0!VTrQkc$51_9%TFGI~USJyaLsD<|i5_ID@@{6kVc>G%U^f^S zf+_WO9eTYV*ac*@);s#0bkp>zMAQ~rZ z(}V{4ZL<8F=VDX%6nULMP=CNl+rijZ62GvNUC2B{ui;p2{mw$;38esDPraAHj%7!3 zm(Uj^%@C)D;Juw2vZJz3nKjr%78>7^@H*%eef01g$$XGrXZ&A!+CzWVcYkO@es6)G zB}dE4GG-dJDA?KKqsRT5e`Qm7OF;+mhmkxSHFiqycESg{nl}nL!dUB6pEoIR9=Khe zT!ZP7C}r;--8T@qeOA5*&mK6)xBgcmy|>JIKjPm{vHA~eU){U+L)-6%{L-Iv4{Up3 zfBZHN;G?hxd1u4qA`4D8%8cQaUFRO*?&o?#$i6Vrcya2=`lI}zvOHz|iPGEr5cRCM zmUNaveV0QI$RJeuJDVPMJ~byKS#?70-utjd>T}E} zCG#$r%nV50^P%>F-G4u1mDEV~;(zS5&Sx`~j*gz+*jk&Ok=qC4RL-w9Eu2EABYv5_ z8>Q=?cI~mA_gWvLFW)3E5wBVfVl^*szUv*Ae%OBc^t?DYKZ@8Fu%FA;rFBJX_Wu2n z_0Ih26K}83mf6u#f|_2I<&WGA9QW#8{BemIt!t~?rEVU)O|p=#u08z=%!OO3e;_oW z0&n4hS2H8VH%I^YZYE!MeGAs}Zr76?Zg3pxu?ucE_gd^k;S-u>f2W}#|4R?*O(kz0 zd|RJ!aAvB3qEtUJJSC0+MeCJ!TY9_fJ<$F8{6&H<$OYczE^@3keVhNFjTWGd&drNr zNLqh9_fGWUg#jNdJ};6@fk4~q1B?9}ascF;MAW#qdSY*8n-SKp6|0yqYCtmPR z>8`y0VDv4D-HdWdK$goENF>Mbu|)SiiTz@{u=mj=x5h7=yEOwsfV1AwHuu)U&-ZT8 zm1{OVJ&)2;de=a>MPDBr$`L(+7Myl~H+a3zNQif4O8#~G8J}c$%E->$SOV4we|MYt z_3wcfdObPvck-#>>#@4rU*(Bkpz_NO-}XiR-d|C*?-E%wROi#Vm*e8wrxS62`%LK5 zS$Q^ddR-3ozd7v<4=*N(d2k)s(w70U0<;cz3`x3=S9WWC{glk| zj|LUtXaLy&z+rmyxyr1UKBZa$#SX!VMJJN@|ovYTM`3sC_vBwR0E(nfDP~wwi~Q9 zZ{i4jWnP>CSbMN3uY|lum)meICh^v1j%SWOSCK!lRLE$ROzCdr zrLX)ce-*n!T30GKa2jDJ0H6X~2j~a@Z0J_O!>b(8FT>0J&61byf-v_A&X6%R7eCw0cg5MFaX((&Nvcv=#p@%0NkPr8Wz3!70m&&5;)lW5VVY%ZhtnG{xFYA z<>acW@Q)5}W&cj5_uWb7+mlxRTzv0yiKEZmlaBU1htTKRN-z6d{ON1Sr^19|}rZ<)IcE}qGByY`cq`zBcu8VFFt zX0##}vmL33eHaqL0n7+g`R~p;5Vss!aKaJ0ig5$Ia}xa;^BzD9z?1;F4Xjs{SlUOP zI~dDspfR@g4VeUEEDOV2{EHgS_{6-Xu)tMqi3?g)jNyw~5NG_TD01yBu}r>bg;EZF zS^Kcb?CIQ8GK8ADDmM-GVI!f$hMrRM$_$m=2!DeiAW+n_m<39td72nXYM!V#wv=qR zCZp9Is3XQLBduhSl~y}f(B~47uIh*MIcQZ;kPNjclgcg_LtxAfXdPkkt||=}mOID=quzpiw3^k5bA3 z5{wgS+$>zLQn<3GXd^>8#fiFx1l?4S5TPI;LUBTY;)EJC3loYHa&M21YGRLYzx0M# zf2vxSKOOP=^e}9@BRk|QUN_+|N62n*&RQq=19>ktfE_r5l7Ps-JAm0hH(&uZ1CfJw z2BU*+F@u1q6-Y4;bHd@=(^-zG9?D2WH-vn{A^XjL3u)D zXXXf`BUkVWxi|vZD7zvSacGg~MR54P_5+xsj*W_MTO@oXAP1nufv_Vt$}~yb3Oo$E zsUGt92#6|Q#2wxcV2C^7i?Q%9DqMwXZ**tBG*@%DJpaSp}aLjrxu!eRm2Sq*k zh}!_*#1FUy?j2ZwHd?RkgeisA5+ZXg(zIn}1#r3Qft>+m155`vRErc1&oxtp+k99CiD#O39y_hGk6DT2W$r}tK40M3Qx}7J_tOy2M6kZ7#xPglNXCmDN^l3{Al9fDkt+bG0yV3Ax%L320x_%1m>57a zpk$O;kpq|Clqp^dny3`q2S-j|5{cKJow+0f93xr8i<1K zDHpt%1ju7~KpdF?p$d>PNVm#@*8~qP=4T0gZ_x}LPW3y+d{2ze-GybOri-%8%XLsii9FEPi74;wX z_QBxW5B`DOqhoNm_CLV>XHfrNEh$_B?)C-m28y;5$o3sls~NLP5gPX|h;C)TADIxd zBSGP&Ldx^`43#rcs3&4fuSMjKB!Jq8a5s$tQZozboDA5kW`X9UIuk9%%Y25<*$iXa zlP*Z-x`8cnqcG15OE$BdxXf}RKgtYqrjt$NN4bHk14e0RGi$Wb7dl7zF9ky{2n~oW zz$f4jAlR)HKV&^I^#CmbcnNT&z&rsU1o(_Vj)0=#{UuRRu)oaQ(fdHR08oc(Dm`+e z@l_s?QR3Ac@}rh7e?krGQNvWx!#JUb%h1D8QNvO7>)x%)5FwKN_X7ru8xcKT1$W^{FV$P$Y{1xsoQRS5#yP{^P z;troa7@+L-q@UCFHC{)(qydxcFKC$)Z0g%#Sgw!JCxPM@Mzk+zmlQsQdP^ZDue_#Z zCCpZ|KL{tQ+D(Wjw~QrOzfCL|8hE#!DoqQ|8;;SEr}8wU&3wZ5;09S?w=D1xG#+0Eu*3~ytqf$93}o{MvPK57 z@B&%O2C{Afaf6G3h=Ml2L%~8pKtVx4FoQsFe&b+2Fuj|ern$jHCP)SdjDx4dAuyrq zH|aPe=4p>SRAI)M4Lx!(t}Y6WqrVPl{zwg|$ws~#U^-#fcfDvkPbn%0S=+8PM;_0!vn^UbE$3-QgRi~lmM z?Uj6m3G_~|l2GoV>Tq_vJyF+P2}iD;Pi2vf6$+JsXfr?Si!Si!>}BKWr2ZY)dV*2^<$*6asyjC0b4sD z>`Z0c)R8|#OY3^M)6Aq#j#r{)m#45r!7%c$mn+63NNQRdr)wo9YLi@cFB>J!ei!6m zo`G-A+&veA{EbK2c#1|RHtEk}x_^mQ|31)uuAXi_I$74F`Qh`dlGnTBYpwlUuHtL$ z|^za2U(JZwUNpLjaZiiWF)Ln+?0_(SLE1 zXnJ*Y98X@^e^FOeck^@c>9?y`N==-2s=&@y`0cFWbeyX0o0z7q!yF|)QkVHH<8I?- z@|vXm$JYM@ZKH>T&6~Z;^pEJY+pbVuX0JJN+XYW> zZBg*bSuj5&_OeA!Fi3*QDvlzev1)9z;r*^TtJ(KN9RuY2%A^Uv+uySG=7*e96XAJ^vcUrH%j`-HXOe4oc<0S8dv z;%BYVuxBP9Jmk-*<*BDBzwN1csYK0wKh9boz#=NF=lM4%VceYnfj5@bf!GcBn4&xa zE}SA(1~xV5k0^#^452RiL4xV~4_J2L`0PZjywmc9g0z$&Kwx$`yE5-k%r1GA{wV?X zs7wWRNK9FL1`Nz6{Ii4=i#LICV~}XcUqG=Q&!60!o&;V^T?S3v2|p#>0Xa3rS}x5} zaXM{>=$nu;H1+d^%7~kJN+W^%qKF@a3~;i4AAmmj!!V!<`HZ@S<7Mso$1iw~v3Pwg zLflt$if5KaViiD45e2Civ`j>N-il7|97}i{9R^E$kn&WgP45Zl+|szGkA-&Du2?ZM z&FaH{vg;VpWJ%BIk*|{IuP$GN7mm&o&XHXmEz82)gZa%|dORG?9wsrko z$Nzj(cPkTCPL1BI_x@m7jqp|B8|kU+G>PE&wND_wxc;D> z{HQV@5WWazm0zGfrO)haF4bu)S@PJ62^H(}!rR_WR`#WwL*{mBTpVV1bDxR3_U#R} zcC}Imt<#~bAtlLk%f$?8JwHae*ZS1DKrI`Cnqjq4(Y(&zRm{X{A+O6-7ioE}ElB;i zeszB}cfc1S=p;z!ym7`5eUX{=`NxS6S>qWqlTrGcA26Rk&5Z*mYcV~(FxU>^RBq5@1YnsH zrpS7(3?Ii_+ey%L8ba}^y3puugMzLWYv=CIlEPq}2@!attDZZ4-GuA)?h)Vvjb(X@ z$DezJLNUc_Xd}a|e{J@Q;rYYW31lnJWGbvg`-|BG^Lc(T(K(P!$quABkn>EW7c(Hp zvutx>vT$l*fWh>{2y-cn`&X!q+o2;2pr-bUffZ@CFgZHF*}XB};L22}y!NDd%8aNm zqqAaWXZ8B)6K-kJpC)(W4olf|7-$lQ**$+nG zciuVmn!A2hk>zc39y_0Z-~QBfTLAuhl>&+?4FCduA90f8@QG;X)x3vVhiZfBHYXrp z7(P9Ld;9nxs^qQvuG=(jT)~w`yT&udGwz!83F8!cP8hLa!g}EXC=|DGvdsCmqkBvG zPf8a>7Nwg!h~854IpQ;E%((qV&-j4sP>e9!4P;VBj`n73&)k@}UOmnLSP8-(vL_JX zMl}Rys9Pfs#0*B!oHj||VS%(&0^uUBaME?iZn(HJ^?#tI&P|F_e6KWH>Q@oXGMVsw z+m#mg3c+uaYI@syYmWirbUN%P4)dOUMF@NyN};WogufiW#HV#@8bVv zKAUD+_PJ7O#nwgYXRe3vNoMdUvW<=X9Z5V(Tu*#U4Eamdcr{~c@$~e&EiI3OLhfxX zs)eMkZW-<|;W$!=-DX6*8hdb$ShKXR_%+@;rh)S=j=8DV#&6Ov-);7Sp8DX7PIa6Y zEtRHdHs}}gA#2uc{O{jeMDEvmR-@vChd8F{2+_Cs7>TO-h?dP%r=3s*q3RVQ$ZU2& zn*s9iJ2aopusIcr!0M|>NKiz1ISRLZcLmk#3|LP3zFBm~tSL}>_;<_ZZbVDl+h7^Z{rJ9%WIvd87pn3lfF z9c=ro^e1j-09xyxwXyV{t>1y?aN*v^dLQ6^r`wu~uV)f2=_qyWYH#)5{mRl^oIWtK zYruIOpyt)!JaRT@4bGFfH-3*WKbFkwNmPAd`}>&6=;pWXy2ENG2ew+!g3;~0%NlBZyqNVd|c21p6hq%e(qaVyLhm42Y>qHHq{X@OF(g-c_%;{Gb z_s?+vXqP(-=uMsFbF0xJSg$MdUQv_bwwVH*i4JH?&!U7(iixIfpc8YZe9RINFqc0t zvI-$-;Nd1L93j3b_)&;CO&p;-$Jn6`t#!@mnFqyY#VTwUcwJYE+Pl6l^6j%1X+irg zRbJZ@e+EOZ*-^Nvao4i6&`($Ecbn#KZO}?C&~N;YM_FUOj}> zPWKi!W)b5h)e{$0Yvk!IF0~yQ?VD7WoIliXyj>R5Da96lo1X(*sMWo{#&wg13!D%DZs!nwIy}cvv=$%2=UQj0G*1> zzNuslxt|dE_$gaLs>#wjK~vcM_daj#LbY|* zu_^=QuE4EHE8TK?q(r9_tnWb}yk-|->a22pPgQli7ZB0~adKL)&TJuq5hABPECrJw z?T-MhM30-7s}G2W^z`>+5&(@F7l-zGmOz1E#72&&>1vH#EBj_mO1Ez6`OmqN!jqtv z(DsRj0mccBfWZ(jh#5Bn95XIPSUGsu{v;rfG3$-;myLBo%SaS$iU4Xr*aas%?1Afg zEs)pa-wr(_>5j=*SNPZGRR|p5XUM3_XmbDHUxsGCyq`Lg%{&jJkbrRSP^I7PS#0 z!qj+BHw zY(Pey0p-R(W@QFp!_c58ZI#Tp@m1KqyY$JA^4snH2Jt9bOLFyiUXR-<*4+q)b2~F$ z)1JOtlODa_7n+nzN+0c4=O`iu{)hjQjcY>i;vJ})wRnuaXWw3IPSJ%oj0nH)^>*U-!DN)jgQ8x>pC3|hj!|j=U&z1iu2>XZfiZp z3SS-U)a7VeULF3hUZSs^?zUZhO!vLDa$B_Aot<|DwaA_!8VR4w9c=Z@12k>e6wmZ0 zIl#kZ9Z*1EoyVf2jgf>FVnwe->bD1n=deC#!D6{2rsYYp5 z35sxlaCM?17mBp*Ya+PIjOJQV55Rc3`@gC5wAW@mm?AoVtQiQ)o$CwOQq0;AvrmkmR*@ddd8U4m zdM1BG*~CnGq<^kFVV}ABr1)<8#_*GUWk2EfJR|v`I_G|B`SJG2c9DJud`^G)KBzBl zmeyK^4_@!lCK2)uZ%-m`jn6neHKKRWo27N)B7q-vp9}W@=m$6i5@CZLl!cT>@dC?z z`CuozNc#v$w2+n}aR>Vcw5pW~WhEA=9Fum!mYZf0&UWlS$$9q9g`FglSQ7GaWsD2b zjL6}TF=9oNCsnSpEss}y100{`@`>PDr-T%P!r|k%UC409tWx%O8n$dP)J1b(63DneVLfcPF+uA-c5#8yXoy$Fn#@$OO9!ZKP zLL1AxCj~mCWP+?wQbnnG!2dLOr)bL2czFiT1ck8$7)v0aYl2dy6H}6#~HJ%MaPt;)=|eH#Mt1=h;=H~ z>eveHBC+PBTG@Up3|T%>TTx<6S(vPpdF-nIh&E+zZ%(08+~xagqw^?gBcY}S)7hhB zU{)skgWOH@^m<+8Ukv@u#sn`L=kMX+Dh`~Vj~eX<-Q7N?{Td+&DoUaI)4aC4hf{f6 zd61~ycEDQ*jV17B`$D-VY@(gj$YGQ`wc^XWmCEYPy4xP)-HjeXSM5{hub%>1WZr;t zJkJpCh+<0BMNR!hMq0|hK@~#XF_`AFofDlyonxNuOJ_U-G~!|=MmM;U5U3H8>BTs2 zj45V>C61m^`!s*z4tC>bI?g3YvC>)7O$H|~MhenyDr94tl{w=ry3SC!n65F$)^jLG zLRrWO?HA|?`Id+X_4_1;wA_N7JQ0itYQ#d9lmeGq7O%pRwm6cRSSWE*SR``HT-;b& zp$o*WZF%h3S=)Je?n1}yIK3RUi{gw(ZtO2pz0`IdbH8`Hjwi(%Jf|P*FY!@Ab^`I? zm%o0pj_m2_cf8ls+rDV7C`GfpNGZA7TY37UTsQGIBD34u6!FO*usne+OaNFOaEW-x z`;7caE4wv%NS+IX*}>nxa8%`7+RXBdTOxT`=u=*#Es+n|$0_@DDZrQqyEKMGts;0w zn6BuTloG0gvF%N(jp|L(VN+said+slwC zL5`g{vUm2{;l6n%QW)E`j*#Nm#YuAP+ax({t?D}lPf2C!MzAN#Mkw0pzbB=wo$&mzJo2D{@rkVcDZBPsRfYr$&@pMv6wFM&d>yMAdxdE z!KqDlJbIjJ8eGm3_5JC{lL)Y*XnD_O%FE3=LpCP}-#ih_>vM{vYOo3`8%XmB8Qb~B zG#i#4?h8lYM~)ByK0O?;Q}wI@1e=*E4+j?u4@Zf_CVBlzu+>8^NK>aJ)I1~wX~;zT z3cxZ=g|ie6f*5K}0EfjC8X&+gq9qk!fs5Ui3o_keo#{rqRA;);D$|`>*uSbuJ3wFV zz8>@hHwuu^3ZYt`N>oC?d6th_e9!XA2U}79@;22uzN+ z!7U>hk@QHrN&^ny9IchK&6^r!(*b8!f5O-et+f$Gl$mrhsEvUg`l-CV%qM~}UFhus zmJ#CRQcta8S>KT8M0z#kU-@emdtlX5Q$nXoUi1^~*}4;meKC&q>D(H~|L4Kn>1Qrj zP8XJ|72KsN;1zIeWY`fbH@m4+kE{ZD>5gvX%tbe0sX+R#PhkLDUa16K6*P@=-J@XO zZOpKj9%#|UQkK-nVdI#rlZAkcbDl@nUSugWYYRlJfOW!7=#YzbP^R&E%cv3CvU`vHa@)~{N0bOkuWan|xV)nCbrekJi>uNGw1i&7Sxjf^TdMp@kD zCQVBBYNRa(<3p>tj#cKm=a~EzXQ@^2xml}UTE#_@^I3iBhXr=ogdg(M)XDgN>CP@Q z0GuClAJ)q6_OcOva-kNk-xX9Mz^tla9|OA{kYBM>eJLRHt~#6dRfj7h^vUA0;<@6- z?c6kE<&=pmKV`zZEM6b4A`zs~rsF!}Os~Z!x+mXp-;&9rfBx=TtdbUbj-1etS+Fln@D4t)`QHec*M`45rqR^^fSOSRVAbd6Ki7UBRCCr&Jj?j!zDfm3Fem$(dkjA* ze2FF#a3qs+A8BDFh*(vXWR_q$st#HV-3T_z+L78~5B_Y7OlRn*LbPP^B}SQ?j609Op{ju z*`f9&@*_9%eRiCm>Gb|>FJ>&67kD3&!eghJXVCTg$k_$0JdduIMq(r;?mg3l0QcU+ zQUI~>&F|5gxQ$J|T5eum~r@{5e*! zGw9hzk);XZGQt9=LsSoNzChTgmN0b7^fFu)satx(&IxqVNaHRlRIK9hBE^u8igR?Q zeIGLYY5J-93G9av+uGw$O+-Zy{b06Dp71S>%P~8@lcdu-NZ7rwGEu#Ul<)%4OM&rm z<_E4bQAg{1iR&f~FEW5l;5FrjHhQV-Vl8JEE$3mnppv;H+IkwmQjm z{nk_~R%ee7rUs`!TLl{9ukyIRF_a}VWjQ6D8N~yVMZaL32Yo}m+po_)%w4398gA12 zl{@N1^{YF7d~zD47wWzQ{5*f!&aOR)r!>5zGeH+T{~|B2Gn27lRoGtj@_+7n;ZO4J ze0!{H(bSRAN7qLl9*h?)BsH&^MZQLgkFZ;bCE6|JB;QbZ6_vDBYs9KC$BVa{_ocF$ z6wQf`SAl!!O=A>|?AO))F_71hdGbT|)&7#)F{t10zUu9&IC7ZL5o^kX!BQ>{U;mbA zkK!^An2VB`g8=eIb6CnL0gof&*rFo2aYO>gMc69m1vK*4171|)^1IVn#|z9^x@rSAA6B9IK@1-}$qvP-XbEw+K@SPi(Opde!utm``4n0L%H{U}u zSzrN1xae=FXjtE@Ku5H=4S!TreQxvydt`02Os!NGHS$-5I?{Rc_yG1``#|{M@L=iS z|Ksc&nuXDsHM(uvwr$(CZQHhO+qP}n#=C9np6@T*QM!^@2C3?Ft@ZFn+DG~$@T1<) zHHy|m_9ML%VcbMYFz~0iC@&#b&IU>o?4~>?bpDJ|k^ZmvKp!Gau#>XlUG2#;Dc=1A zvI7>ew*?isyDi(J#Tv~=07pWP9zHTtv`1p>d1CfHOGg>GDH^@c%TkJ=QQ?E=!(G7J z+XElDRdqI&^^ryKbbiC|%lTy|Y!nhDltQr>LQ47v*_B;(603PLmmV)=5eDdY4jt;e6twHzchIGFrmXqNyMiyYy_1uKKI z#m*>8aL_Kk|A^oE^4^1YcLY>_45DI}dq7ZVo?XJpnN``XCPC(U++|L`Ypay>s)!&+78C3m7_XWM1AFGhJ zji03jDhBMoypc}|gNg{bAl9a!{W8zDG3L(Pd71>49p`*;!e2yq zG~pj;UTa=pyxF{IG_%YjZ`YJIgD=yj-oO-V+YEGIk1I4kuRZ`~89E;_kUrBX{_J~I zGo#P3(=JF&v%>hSbM7zL1M8Cq)_ZQ>`9>OXhAFKHFNh-6@7~-~opjV8<=&EQ4^~bp z%$+5F(Lanma|i8@vwvuN^zPZ8lK2O&cr~pY5J)wfvpLNbus-)n9vK|!w?HEPYMMpG@t$mFb+kOo3@Rh;+itnQ@U z(X-3pp3Lmg$?1;hmap{4^p0g7?<7)Lzn5}V%RZ>ANj`+9E_d07Zl&7- z%6F^Ej1B8OI8eqZSk(jqp%j6YT$#0uec=OL;><$K(mqBJK>M=#??iEk^0j0aUR3~r z)JnA)y-Mps4}l;j?4OkKf?W1>3#3F|v*!VfL>f|QxbUX%QPD1zb=o-yws7zjird6F zNg$RY_?WWc*k+jk`miMG?w@bL+P3&`jC%vVw;#7cwxUwoj1Nn_S~mM1ytm8d%ZzF=egMA@R>ZI901jmTOU{wOD|MwV0hu2nQ4d`pNnc2phcEQw zqfBPC1al|o5|W)lS6a6m*P@jrDc}B#X$sTw%WvofmkjcI?C8^4+x!NYnzKxH%c!&J ze(d@B8)f(+E3LDLvs6iBP=uha5PXXaZQ(LSh;S0h1(l>q@DI=Vsb}1<5_Ugi%4<*^ z64n_bzn51Egf1x`m7}PC3q_P)nQT(U7!+oyrXqPM$m&6*mB`kXT3ekhuH9;D(ydja zszkoHKga>-Bx;l)DXC;u#}V13^W=${Yk!nXy1#~Ka0`J%Zw6X>vy`7D#P164fr@%r zOK~C2_eFbtt0HWfh~4!jj>uJoRt~X4Yz3PCm{X_m`<7);nFk_rjBe!+Tm{izNwtif zA}P)8s>Xv~YNs5t$&GILj*DyU&2#rB`HMXv_|c+Vk{<}ak;hEa?nA~^W0~#jw#So? zS)5^H1xtRv>Si8l$S|n z?nc~bdve^2b`n^~_*HE2nqACsKHeNhm>ky3UB_!D086&dM{a@QK4>gdQKnmh-`YuXq!_*$c_!Pl3&E@>8e9k2r`VO0uEW37 zaQl_0LeE425wQmsmb5q^x=yQtjix4Aka9sk<&?xh2?A__z|p|ez}CRSfwO_R08{4! zg#bv1n=67%OMw}5|rhbiY_;Nq%EOA2L_}S%^56##r{-fOfj~M%}?K}Oh4ln1o!|imv z1}w9x)?fOl7^#XFd_w73LGcK9M??MV&jLr@=1@a3=Je1sQT6cWZDH-=?d0v!n;Y$B z?Wb*Nei%F$Jcu719yB+aSiQ6!8LiWIqx-atvVusCvyij@Y`agT(YVsWWHlvaT`96- z0KB@R1eO<6UUtZhfe%c?9_+>Wu@$jVzQ0384jtGL^^*aKigSkOP;MnhT?L($klj&~ zU4cD)1bcv#gsEE2DcR5PwllzLkh1f@XUnWR7 z8d$TI-KJR)UD{!E5KElJi#c77GO1MPRN~2#B9ckR9SBpSiez9VynyMaZALg7Y4E~` zQ&G5%IdXu4F3JBvb@NAgVkF}g)+8P-UX$w>wI%D`0qj}1Ia^J^;V@-AO^J%zgavj> z*4Ih5GEAhR#y@=Q(OG4dw9Ts?KL$zh{){BDQ7hugrQ9-;k7M=h3vC;wh`3WEhU9CY5vZ+ znVU{Yc;5Kt>qX2nF=J0S_uq2uJ@u{Aa#s_nOVQtxlUk|wGxWH@UHgEteD{-6e~eX5 z1-(W?{DAEa^fmfPt*C63=%pQNcW`crZgYpmL6=j8a)yS6L}%04*Flk#ot&Mco!C$9 z5^rsHm%79~1RFS;=W;qb3A1NgC7nm`E{Gfz-9q149}ahJcb+)cw|3r~UG{(^S+%4& z$VC(Rz0=J1FJ6Jim7o9C%s4vi^wR8(7KQL08lX7127d12(%k+-mfCl8eAKv0tC;C2 z9@(Y(6Y`Q^lDL{lAf2T*Oe7A7B{(&!LC;TkIQTw#NI6K+v!r6=mD!-T%PaQr-~RfD z_jO2|zj+s`^?aTP9oye)ED-c>r|G8QOkp(vPV^O~{8T^^U)5mOmKVGJjo)ynEKMJK zJr>=3S0+1(ZxF@Cn1PE&uxsp!1_p~PVQ3A)CkDY@SG;Gj2BTzNo=GWa4eK~d7lyL6 zhDA%3ICM~omKl&nOls_S29XJ24Vc0bihjdKN-;0YR7Dzd<*pr|jYRz%%w+tu29JY* zmA{>!(?Ccrd)57%kkj+Fn9P+f_j~?;|67$hWr==0D>MBoueO!kUdQySS_xaD_25jp zmTuRN!_98}udT(`Zs+{>qI+S`BuKv;2`h>+0vm}hsYVYHOp#@lg&5sc{$aj@(<$21 zdlk-Xvm7=aSM9+~D~1_fZ2`MoJVqA`!HG)C`KQhrx_jsV#9p18p58xKFT01{)$i;+ z9bI>>1=sP~j&t)#;#4&a>FLu7>Q4r%kmgldx@2V;>>|N5iIn7*U8Jg=Z<{%5fGrkw12)m(YM3Z7-}ETSDR~?p zS21W-LB_%kCNw(Bk)sSsb297194p-9T19(oC1mXJmv=^-=A6k@09T2vT8x!Am%DR4)v-VV6zvDj%i#ainAAfTWyWtmA zAskyx$yx)pLcr!Z7nu|HBO?(U4&d~Fii|;M<>i9pM_8&(5A=?^QjIxBKgIijYrZuV zd50lS5$n%C{t~ev6VPZpxYQUafkB0Rh|tyz;{4t5pAFY5JyJxn45vkGRJ`b}DDo)$ zauhy5PjpgZmPtx)(mdkR12@N{S&jYQ`e7hN05K*w=V)-7frYbY{ zJD<3`+`3cpqYRv}e4nM==d$uH3eaQ6!|q}9);ob9S$e{Y?#Y%e;0_`}3sI&H&h9%_ zm$N#OI)|Qg&3exrUqPRJj(AO)iL19WAiA~{u$M3G%xNWBwajVc5cJSvRI2B6K~erJ zF~P<~XpBNZ4!gX;AufCo z2JnT71Ed1Mk{nB1h&{bkceXCvCtPB0P|7sQ&33rS5J?k1b*z;a)jw-Jm_$ojw?N)q$SY} zPg~h1R}=mj?cFoJR6dbBLB1tEN7`)dzrelZJ=vb=-r8R9Zu;au2lU|M8o-UgIe~jT zt$y5b*_+y>+9l&V?2Tu9r|5>1KZ8sY6ve*9)zXVHp#Y4!*%L8K-U}~ z_5{h_zj328p-cTdQk_egm9|LXx!oq_3--tNj_}j-Z@-|sFubDut=Gwu>PbMy3W-@D zH3`Y7odoUBv`>h3o+vCy6(=cXrPL%*Q=bZTcJ3(ArAfy%wc1c`Pscg+9;s=J7JH!P zAKkUSZh77G#_f5r*0Ld?NV$p4&70{=ejBY9eY-!so&V=&Xq8^ zoRpA^xNu_B?MXh)W#ptU%z(*2ZBR3zx2j;i!me^wO4AAF7&p>^Eotj6bE{T0hzWUI zN=YvHJ}C$m0LHSweO_G^&3$9 zx^sb&PB)~7b%B%A3nA%@1_a#-glBf(Kuqp!%$Si*qH#YhLs1@GTLZ%~gq$$En+&?C zd|Lm9lE#hMPPHn!A9BM*Rm|4{W4~TsIQ);Jsi1s;;Z$hd=uSRpVpTgWY_U=o=^dCu zsyotXfwJbAk@VGS2I0$NORs1BPxk3gOwQm2I$TWrE0}zUc%}j`J?7{Kr{y68tqWi@ z6h-!dpdvPCb;)uqR6k4W)(KFMSbnNZtEs*~W|ZFQQYGl0YhZfPda&(|xa!rY(kAH4 zEDs|poBL*I(il2vc-wJb8B>%#iCuYtTfp7mAS~uj7}CyAJh+??OVC)R!IsIlS;5>? zi{t>M>6VrAK1oS<0iI=y1+D-yscl_uTfr7q`KAe+jAW_xA^S5#S4DO8&Xb&bXYWty z`qtJoulU37awM8s-t{%b8_%lp>zedeUczPXX&$-vl}|k3-&dQ7 z=3p(-TJu%scE~n~GCX&DHuX$e-9a4+-fqzo8S$J=D^syP|%C{-!3J z{@Nom_l|mp^T+8Az~5qfFo7Shouo+l+}qOEGJWyo?2q*iERkp4^ZqzyB7`_Xwa*Hej#MyD=h!zz2_WAKpSVpT#Q;5OH?G|YKsC7 zDpChJEEXP-jU-+lja3*rqlm6MFH($$a_GHPkn?;lr)&i(c^%3Z$uSF8LZ0Jt+m12g zx;bp&SOAT&U#xA{QWXMm34!f$BZKsf+1%SrB{Vtkz`qXOn)TZ0IWz~c#VaJGA8|?@ zX^16wjDSR6xKM!N`Mc2nz()hbe|V7GR|vbSqJYM!@e zm^XwG zKzDNczeP)~pA2jR!={r6LDl1)fHNc;goTJjkpu2kHV9KY7n0$afMC$~)!&b{5THZ4 z22Xw}#%2?iA)cxeaIPK`BnJ%8ItS6W5G$i#^O(@gCJJt~K!5Rw0nf^%UEPlnTK>P> zz4@=3`cjq7b9P=+S3IoR9<|tsgrMI|I>ccXZp9D#kAZ>B{3Tag}r56>Y zT6XCPBEl&=H%#FyTJJfc6@vuJo9n zRgeBdL@HrfL0zlLN;pbSmGw(|RPAZmQyb28Qs2=J+45GnZt*wGJjPy%??smpm#S4E zMb?M-GCjSz?Hk3cG7^dwzF;O<*s;Kr*tXI1GX;CNQzy)NDpvGf zY7MfvOy;&iBC4_2SFh_ax-CroEP+TXOm0Lw=$$HvW?+4j<#w)Yx?nb32x73rE_SwPS&L$=isD+e?BRy($DC8#>2ft< zd1g4i$r2MShY3l-7s1QmvU%BjXyeIG5{F==lg(p6rPj@86SR@w2rC(p6*288AqAH*AJXTFCk6sqNcDr0v-iPa| zWT|c3N^xR~8ExzlDaCkVu; z^3w#xSxsPCesjUS{z9>-#dkUWe>=ws%xIB17<4;*b{1d4?)yK-T<)bB6e@dOHy=}z zWirf?_d4WC=cA1m^NdI zCK#jcWEJ)%_d>p1$&uzWYlbVuT9(QDc@5cU2+;E(QouWgaks~M#};%no)Jv&B?zfV zN>Ww?rZS;U^*+ks=>o0oO<>e7h_UXBULe}-iGB*5R-;fWa40#A09H$2v8Y%ZrftT^ zilX`gMZYa27B7qc$*qn_;z|SjyGjXjhu0b@&!Erdzg~5<{Xb_GJf}pBl-2)kQkBQ; zHY1bpbv)V+p&EC5o#$H!y19yYUURW;A()@aS!XZ1P9C-QKA4X{8)}vtetXNW_5-N4 zuhGnN=N*P3F}UxJLCYi?ruj4xvVLV;fB{_+XM)r=YIzHM zUy4FMhn_?5b1Q=c>$cnWj@|-ZJ!jBrd|%vf03Xy8Xwh4-UWtVF82>J)&`_4;)J(8FsBT7N zmts+APOB6dWdD0R+{BY{uhho|qbKaLYxIS7u8@5+`j7N{*3S8}{Zti`MyQmxj=-uy zvbUNF8>O$+8dGzh20rdo;)=%jUu?O;|D{({uIv6Op8sA;E|i_gAUE;DwnD6~N;z!i2E$bx9>Yegdbx`#{?N|CH?9JS#_|5r?e7BsyV_wI+&Latj7;miX zwOG{I5pkS&%nIeR8zfKgN1v{2L|SB1hq3R#QR*a&+Z!OX!vI}HDs3VPD7+`oI-)!& z@~Tv)9L8{1#H}NO^I`FVut|RC*tdyccC*XSYs>B0gS*Y(D3|$kR$4f|Lr)$Zb~Ax5 zPg*wych9_hsW6IsgYmG4*Se$f5`x`bw@|}uJ0~V!@bEp$ClK>w$p$?T_#;>m6O#Z} zq$v+O%0mBVyW;g-EJ@!~vcIRX8~G<^U?Ed(2dB__`7Pc<4l?Bf$IdbEaqPB(tPY0_ zM1$j4Yg0ts=P1N>&!4Zxz=&P{`R#c4x7T=9394g8wXX5;6Q-ORT=Bitu4kV~4(*?O z*MB+nh3aCtZwhMfUB|e^fc&A)6`&KX?bYXW`*?*$uhoLVzwCVv`~$f5hsL5Gn@t=j z!No*sYn9C`i*C_Od=SwL>ITL=13#{RpdaC%^jl(JPUI7ekcfTj znsdM(?Vt5a<1NIc*-$=MggLNOz zo?z7b+ko?Qu9MkeQPw9&oQxB{sXMpwLJ^W~+#O3)O|-?P-LCbfso#nPUL&s!uMOLy z+V-jiyXGK`-wiWfF@G9CTvjNd1`RB<%LfQqcy>!&HRkth!LLV(`!gKlh6l*z+4&@) zN!@TId0KS}AADLq*YGXtNw=6X@t~47EX$U6m^d#`!x!cX~ekWa@<7z&C zPPibh{a_hN|wBz!iGtJEo6P`M1TQvQ@WocK%2}GQ9}{R%;r?fVA`xj+ltqQ z=5EPw9=WZcT>Y%|vz4p!rXqzQ7GFi@!W5Q!D`Q-|J-ZSF4*C^(%*7TRT{$gmUpP0xSR3SabA*j#{0f&YRmDJIe1~+ zE7Zo)(X`?$l1DrKNIg@U=wbycZ>w6?xZy zBrbiP+ynKFseTYUO7}aNsvs1Tw~+a0D%it(<}yL9hLo@IIkW)TYa4PThe*thuB99g ztiEi{_uk-iZ1EyF7R!%qn+h7Xe zXH{pyvTabI%j0;ebmXqSZt>s!jF`XVQ2DK+EBJ0+?CAyI_Y9P)eI`_UvvkPl zb}{3;*Mtmg9(Vu0-uob=tD+pxyeKr2szK)|4VH05&VH@D~z;tP)MN+TD&aaB@qu`_^Nw z{qaI$mV(ETE1z46Jt$nlZ4P2a#q7^m!Zxjj_O*h+r^_9rWb{Y))ArN&^Q(&QLLS*m zyhzMaVb7F#>gu2DpYZRn@b7I0_YM1#AM9`KA7ek_0jw2^suT6v_uUlg&(*dhe~J)t zxAB-!zkYYG-ruXL{+`cj;}Gc!LhjaWEot<1zl`LoIOUWmeEbDbg2qxUUcLJ9V^n0w z48!qNZ3>FWjv_JaD7~c_=u{j~lt;buUO7gO3ZWrv^e3sowW8REg(#sZJ{Q*1g1b?^ ziFC@S$ECMx6V3RxQ*K+e`$38;rYiupJFbJJs;83zbz8VH8(3Cyq`V=$Pi2~2{A$AZ zfzkBvq?`_&kNO%{PFwBUSD>QZZuDMx&wsR4*`+%w8z@Yyn@wyc#kTg>f`5^zh$`_t zayXMr0S1_uf$VH18>8X~049(JxKR2tif1bm;UvMaJArIM`wcr;^J~7*o@*720tOf} zOtf4-2;*QLJNcxEKp>D-zDgrPi3ktD#TDbemp`XLTBitILR`BGm=xZsJWoKx2ud>!QO_Q87tV6|4$po>#oc~rskTGc9!@XO}q!bkk2986?1Y&7483l9!u58|3P2M1YyRQ~>(NCgKU??gm)4DpKYGqJ#r#Z(a=O_waz zTPHb<<3kzpgNfPZ7w93W_-rW4;fSEC`LQLYW9RnMVJ{}#_t)bru${YHTK0_B413RX zdc;F2?W^6aWJYk@^UlS+mCi+w)(!+VYCUrhT$>r>O1PB$2X_V)(5SfbK$J!c%=JN7 zm2qRy=Z{V=Adw*Z6S%egN-4Td+$&p!9eP*cdn0Mf@JIj9youPrzlq$QZb)-NLtF0Q z8YZ3?u5R)*PSl;LpRYe!KViSae$0NKeG~pF?5Q=}huDlDHzh{LJe9a65_>M;WqDP| zq#wqqnLAP~lJXcl9HCblNeWZDxbTVE=Up4Ady3MXyO`f_24Oi}-7|$bBwvydK$&;8 zft8hUZE($^rayUF*1J`-qQibp!dec8VzNA#PN4yc)5h+v%L)-@|{ff5z7MW8kXq<_u8t%nnOE zHJtJMe&4cW53v(Oew$RK5V1?(O5sY!mc~pg0aq5TjHNJw=1UHmE4|BYQ&PewnvgFG z;)JVMI)gj8@~k*k96O9Z#C54p4hYDd(WOn{TB&z#6w2i*USni&qQ{@*28*BT1&I4X zJ334HHxjcn*N}%kqbq>TbNWBTt>RV~!|N8B8ENVWy+$bq;4jGh)}d&mp#aK`wQPy- z{tl&>i9fs8yGfE0D&_{kzaIjhID+1je>)W7(>)LC{|oO|V8=e821r(fwVgWf>y|9* zw0))dUN#71o8Mb|Kh>0OQdQCOcP(eM=7z1>v{Yzaf$DfPm{G#Fbzl*x(TRz2M01|N zizv(>#bE}y8fFwJ(tp=0kgHiv)-d(h+7KfRGbj!sE9}~^1htqd!5NjyuJ~_KK5#d% zj);%Ddf8&hJ5MqqQd1}rR+N#Wtk7t?0j$GRK#A42u4gfE>a~BdaKupkQQ5`uhi#qyLzr3>`1y%P5aMA6tn03 zc1rfx@l=-iV~kRoioLVLjTX-RVmiWjHhK&W(|+XY-%#V3{i-y6dARJCEqJbdqyOU# z{4eFR+KIq3?)msLdD-W=(7dRH+lcdsJIk}+$h(?@|1<9=?y}-G_}rVu)8j$azhT#S zjrI-v>c7fqAJpEZmLa!RXVmT;`^PcdGlv}ubAnV;V1r5l+_IPzM*^jv7-mEPM-uTVVkEq24mVgsXd@Ee=VlZrWL~{?3fL zO0pdfWz*-myI94mer~t%w}iv9^mD%tarbNA$F}W!k?y*$Y1yma&lha*KJRhx{jTqz zz?*eC?-Rr*JZ?2jiym|9IjV&AtTs5=WT7b)P~8xPQSbpC)X0(D^XC2+ZKJ zvkxS2U%8eZQ$<7-Liq*-AYuq1!$FSO0U-|7C)kG$6e6X+k?#CQ9w9C})74&-lRcPH zlBB&x)#x_d@j_wgoJFOWknIRoQsi+5{|V5Ha9&P`Kqp71ef2(y1rc_Z zj}7LuU-a-7jMcjH?{!DM&UHCo0HeFx>b~Xb!>P3)nx;J3hT#ud$O%?{+rF1(_h*Uk z&+j#zSoiLp^LId6AM?=I`mdMXz_z*&xD4@Q0eOB&d{kJpHJ4%hNLa`pj1COW_+8v- z9L1s0z)X*WsKsG!!c6EOn#{?X&;c=>&uWYrmirBF=Bf$pNwAfW4ZNAVn}XJD?_ST2 z5u4qX4Ez@>wuRAxGmY~lA9nn~0!(yTpeEev1i%|>v2o~zDn+qFbyrFc;uU~JoAPd8 z?_lZR>OkN@;X%WJ)^ZJ9WKhAP*FQ72en7MeMdpkmy<<_Hx4M>L*fr8Ac+{~>N|#0b zKBN@fPl%r8S#>Zh%NKGg3n`PtF1w=@RZ~7;t@?1MZFA z?@evxbKC=d_5&REXT0`CzuOWrf!TZaG+h-G_WAfxzxTbw5Jefv>2QCSRiN8oiF`6$ zH~7WA(F)Ub=m=Q&B^yCn=O^4@V(f+CMcup_+pA&>3tnMIbndJ*Yt0lt?m?y=em!Gu zkR+tjUc5Kd1u99`wR+*~h-^>Mm1}rJK{-3(xII`Z(Z7vNRTQ%v_ea2b82eXfTnZLHIGvk`;JUwj zJzE3q`Jj&@7!BNSWcAIa7> zXXl_{8jjT9joV0o4@GVBMf=K~!oTrH!yVuDqy9zSBnUx3ipkJ&g3C6Q!AgGYCoWO= z1f=H;iUm$E_B1P+y$6hH;_W?I=6Ygdo$ZG9=HMp25BlGB@)K|Gmgf#POAKA!?P}L> zm9LrPpuU}qa`X1fU4UL|*z)MBT=1|Nc3HimIkjhf(FyDWrJ3LB*5aZ*`zuao5sYtjT85b>`xXMB9l37G;`|c-rZPnhmKQ$@qt3 z3Vt>T2!v~_F?C}^Bkm?4|2AnEtci9PHXJlymjVZ^%_Lsi_X#*S2MH~ycL0rvwh%#i zwn@9?RADx0IBbhcWb<1uCMO%ew%i-e+yy7`mv=w2{hl}T+phP1_qtLRRXkgY9pZyG zH!_1D0pr0ten=n$wp2D4-^?oV-I(@eU?xIWl=+jKk@%PwVGa`!MJaa6qrysdK@}i95 z19BP?@?11>e~vKo%HUtDjc}e{4W7iNR8lRAhD0zZONKmfn|-KbC|-R}C?Kzy*=%WsMd{T!5f)9!AP|<%FBwuHc9IJ!tUSiW zVt>!mNz5c&1~Og-a|Lu6nfO%}Dl5AYd&b#1EQ`I~zx+x#yqk%$t~(yrA74pAidCYU zkjwXtxK;mV9+ddM;XAdu>zMQy9pH((oDIN547OVTZmYqUu)q6| z_%ihp$ZaqsmxSM4eCH~$uHUiPLsFKZr_dBfovU8!c( zO8ZylpO~L=0@dW5OO~*${cWH;qU zTTNHvSAwYeBKui=vU+HHs5Mv!!*w3)GriaxL+NEz$%08&I%7CdrMid-UFlGw$eU}B zKY~XB>ZfceTR&>0Xgs97U|K7igPmz>ySa3okI z)I;Dz(STNFTWx#->dVYUC`m8rG9g-aQoI2W;(g~L<9Wy1)vK36I)hfzP8 zd%|OvUXl%X+7b&mLsv+6gI<7>E#r8QW&B-_<9|iAIvQnr^OQ+I*(H)n6?-9)i7=($ zL%`y2aP?)Yhm~i_G&dUe!x&ZiEPFkYEx@)JJlQ2%!c21g6Ua5F96xxL47=zMa`OFa zD{7(3B(wV*1Q~zpVeK2Q_C%nQTT83`&cHeRab}VH?;71DlDUxh082~d@25Z1znzB4 z_RHCJNOw<9YH|#kLUwZYPoQ?m_v?FxduekW`cS>%z12TspL8U?@iu2~((o1VAa3Ba zONN&W&n-E~aGm?$%}bc)rX2)72Q0%EIdx$LI_Y9QRba|S4OfuWmGU}b3jF51(Op?3 zykvC6-sTKF(VBa-r_1|7A+0RfsbVkVsh)!=BIoG-C2-}y1K+f}lA%M9c5D`o?hGxg z<527Fr}S6%2W{souML&Gfqts7K};?M9|Wdw3JJt7D|=cuyhKH%qEl`IRSvo zDQf^~qHu1S(M)A@QkHuD=+VobwGylwcN{tMisOcayEUOo5DLOJB5?HK1W6os(9b?iset+t^4;sg9wSoiZhjD`9f`P(8~cpC1!2H1|-ffi@aoYsZbj z`!I<}s#8fjnPSNB5ov2gcEaXA#hQC%&eLWx?dCoX(1W&@_b`45@-l+VN zlkl3cAgO9cr(J!dsFd`YsY~D8dTGiV@00SnHo0VTF7w*Td-suqO|8OVlw}XC&zU<6 zBAR}2^4nZg*%d;rWAgt>CeK2ed@gipD(dn5cm*!Tm7ccB#Fjh09@i(?9=kh$%S4)y zZV;oz_Rpii-j_!ErzWZj`BaLw&nJEYCTm(Dn6_Ntc>UO| zk_)3C-yjmkd)rM%Rxjb)dsSv7oAQqGj~?m2 zP-e;Q-s!&S-;$q%-T}LFym+^^f$?;zac#{D<^KWDop{Mcu^kqHp*7NcsnFQC~#!;_;94k^Ip;XtZu3 zK8pe+WLo%^acyF0Vs|I*5$+;=$h3O1^@!@?Ya;6p?2%VQ?4p&-?X@ZN$f**ZEVJ|| zw2MWg4;D8?9U3g)i&*HZq>k5x7OyjLE3}bc#3Ah2!9zAqo@|-C+Rda|NbKc7hhc8a zh_mvU@Y%96D-tOz%EZ=|p23?u>=@4sVjGD2r=A;6CFcp}u=0WAYnYYsoE5x4t8kab zx!9DQ;y9kA;dnU8uzySS{<}FQx4kRn?acDuG=jLElD?WWM+R@}SCKvT^;W3ZRh5%* zto`F5`)^{oLafu^KG1*Z*tW!wvSlGlW0WKSC5@GlH;3ZpJog4QmsQX9OOs_}O5DHu z4`U{u3}$_eu*mdEK?L^k{uPMAHARbU#^R2P_$+CJ_O?O(SqXb{CM4(wn<76_f!b}(Tf z{m6aXF^OZ|`_7xc7Zv;yvd+Y!`+ERSeP=h-wf& zL&^8@LtpoO2Dx-2p*Ib>9op}t8X%uU?3>4{MjP8R^eAPkg<0%=-Sk5GlpfXdEq!%{n z+o?rv;@vB^*G?{yx=!g!r!+ViU*R0h8i(q;~n~CHGK6!J}KxRSx-QU0HZEN`rx95Cl{g{*$xrnvJUX?9bd{t z>Nx#?YyjZg_=phmkw;zTj=f`-XSPP|JFCdTG*yEF`r8~GtDPW*-`V4j7Tb6ue&13B}y zSS;L7UMXA;f@L>!vdTy{Zlh+++kPju*sCv?+FZ0?HszsBne2M z-4^!k@I=hr(|%)m5jQ^w;D{22$d70%bG5i?%a$rfJEhz1r?_KtMS3oc$(m*C`TXM` zt`K|QX0z9_)|3B{F?Y>cEB42|2t zpX>^g^*!sDQ5N0;fE zciZhV`O2>kJ1e1iG%F8A=Q-u?#r*>VH%NsvBohG4z9t`(7Ca zUZern4m#`x7!QjLXxD1T`CfV<6M7*Q;zNPO0mJkFFa|w0Qh+-^zdBm64(c8H#PWeR z0)6|3AI*bQ!C){L3+Gd< zeYf8%tp3&aQTT00{jGTzEryrCNa2=1Xl4L$pqK_s^`Y0lAX|retR5fCdd0$|)m0&A zn!u}uI_>K2@9O!FuLBve{0DxvR{ihe!|{(Rj`8_T6-ocpx;D@$Y+jn9`B%;orhme6JUE6W@C zLqr?FPs-uW%+Tj@p{fhum@(;t1TX|*2GlT(Noq5v46?&^H1kc=Rt;sKpAYh(s2Xi} zcld#ZY10NdgVpwf4e7d?LH@QG+R>$$8!@CeH7|fZcE6m`jW4wuuVgmjqi*1hvoy~J zUEs^Y8tK^{aa@aES{36e9z^RA_BpSG*xDFF)~Y^s?0n&Ei@?~=*2@`J!%AA+kY5}; zjAUH!nrv~u^w;xTZ0J-=QfT5U^HSZLGBUWuYjXvBN~yf2$ZM|+4@)~-Hr~v8*~X;V z_f>jq&QxjV`{PE}$ho;R-Sz>qH#%EDvDy zF~Mu`2J}rH=L~Z~)qC?bd+DdjW6S@?);Gq85_Ma)yKmdJZ`-zQ+qP}nwr$(CZQI7X z-+MEe`SFs<$*!b+ob0R|>{@%RX%ErfV4WAMjZYY>tjnLI+kXTdRnAIz?d4SYR2W$3 z7%QBKvg*M0{C=%hF&Dc$5$p3?RaK+a*J$WUN`}GoE$Z|g%;usZ>PD8-^{N&)V=$F@ z&lDG1oGqq;7r2_)mon}^K~2Xe++-GA&Ds$2CAI3Bvm3k%#mx?I4=_&_J#&vbTR!W} zB~Gc_rV3ilsux)s(``MO>{RW|-0Slj)n~E;=D;^OXE!^=8nVFoj`->A_NWf?Jk~@- z(K9yGT7^^-PX^$@^!5uo(n1p(oy_y=>8FZsjq;65jGJ-e&@+H_Mh`}!?e(AijHd(= zYwJkD>NO{pM9rM_t$GFy+qz!Y^$Ol%5n6>*%kCQ$QHSmB^vq62tfhWuU9Lmj`w2Zm zI+ak~)MbL`E~h^+#W1M+M~argEecM35-&BYhSI#3zp0&M5soZju1^PTD&EGgUd5F- z#}{8Ziw-DyS4t(=S< zXhp2_os5Ny4Q-8#X~m4qP0gI}=^5E*rHpM%oy_o=7};qRoeiAa?Tl%~t@TZfX_fvH zs>vEy7#lj#s+t@9`-q;N{@;f7KXZaK+quewiVvcL2h9x<3kwqC8;}SC!N%7o!3X>! z#wS251TI%PEGe{gAEldkYAVF5m_XY@MsO-%!sOR0W45nt5v-u zyA`}D+N;P6T%Jj%x}+>?|IBx>A}Au)>hypsw(V}b>~i%-GxNe+j3uVxcbF zRe4}X)j@b4|#syae?y_`jH0ttnE7-F10PZsP zZGO!js$BMxkP_Kueg`;8w+xx1sPiHqQAOgp{I-*@`gUu8PEBHDnT!dabFR06w}BVJ za`!Hp7}@N_QbR|xcbW|~S*fC)bI$VgHn8*KG4a2MU8S^uvLm%Co##?FIqeaN!03x9 zbXR#JYL{`n)ePz38_1ydcCA(w?ID|s>0KteBJFypmhd$FstGk)xG>ShDfTYU9OKIG zC*gbd8>c;6$hG#&Bz-G0u^fQuk&l$a3TXs6K}!#lEMI?|gF)Q*GOz}R1FB@NFA6VR z&&ioLXCl#XyY1<3T6MFQ1NxM3V7V>bqD}u0&(|-+zl_VdsqcWG0|fe0&HnGWV*h`* z`d{Gke=x$xz{LE20Yi_^!t(F^|A#}BhP$4U@IvjyD`_HU;wPaIDN;h5ID{(OK%A7= z07^UnARO5Gf!twt$wMa?o z@$IMctP})4@Asi+^2N=nsk5`P^YSD-k~}$cg2*yb=@E3)RL(twMGuI|Ds`2*6BnZi z$h@y7!o9WgWU59kWOb~-J0#&_NPFZ7b=JF>Gs#?~FmmsDb!W%Rm8KfulZ8;27YK`0D&#CIcH%dVfC{#^lCH<}|Q|uYU z$*iZN{&a+JJR=b9$lKtVt+rZklgOrV#XoL4)p=)&iT?LTtS^_ylOWdFyZyYgWQqZv zo6j1_C#{B7ubHjpmDE#jF8Lk0`G@$95a|Oew-IKLHnF=yb;wBsM51_FGXQ~VHJn?<+eQEopvx!Z-psG1gsGM`R0#q2j++sUNQl81b5r&6b~c} zJokG=c8L~O7xWM}U72&?Sw&bkzT#u9{=~(9&4j26CL0kQ{9mFTh{!?tKiUgvZ2?(M zc-wrp^Gb(UOB-kM9~lj1Y|QA{$TF7YiK>f*RAPEdbRMA>=81L|u-{My6GuNAHa)=& z^pfn>`Dz}(j3$`=Zo6a&K}dxY=gihEzA5v&Zz-Eks?i!ALD>gMKhWJW*I5OMr`01K zhMo1m4~{aD7i=cbbf^YPN);u>PDtctMWN@!suA%AW%g)h6#y`n=k6ZSI2`B8$oz@( zpDY_9;Aars{JsT^Q`jRITVuC(oun6RJMLTPrc0Qs@_)3&jhDh!h;Igi4MJE1Hw(LW z?^|bLqj%Cevr-lzHH5Luk*-T#&u5TL+01FW8g$Ds=;?Q+P@bJui9P3-}Dsj&$q z4Y}J28y(~5N7O94jJjl9Bt&=Pm7=(1^Um`=L^_gT=ke%Xh`-}`3Vj15F~J=`-1Ln( zWl#QgK`UMD*R~4|?R|xWgBA#PRkAlFemH%n$9!kcXH#eEx?+yl3|eC|>ZqP_f?Oi+ zgP6<{Y81#^saHKBX6O6PxmWFvj^{a3r5f~Z(*25h0UjLDu7s5a=SMHGnAcw1f3(a{ za-zA|TyB{{vyk$&Fqx@w!GIm{XOt+Aob-Thc_rlxj9&#lWfj!2#dtdU;*Ku11yr{C z*B%Ocan~MX_AQgS^Wq&Sei8VRIPH@a^pk~_A+?5m4*A$?Wg(g}EtHs{Y&>sJT=Q7> zzLdPUZWoxIe?R~6X!a@WSr8(frXBfxhN?$Hby;%x$GfO%)HSs~{hE2srgh1=_*#Ns zh`}@+kNpT7k;nkYR5ko;dbme6`wHSIrL{ZR4M4*Lw*w-VQ8`rs=^*oaIM*6? z1cdQ|dD|W9Y!8NW#OfWZeX#su$vvqB4gB!&LzoLFH=udBi(8}KI+*o)Jm}TPNGXO{ z0yBTtV0Li~bs>9cROYPCUJk~shMOxrvwTjK&M=QLk2LQ*Z#zd>>y?1NBAVs5OFPL4<lU9?7GV!8S3`RwJByJ8@XNbtpt zqCjwZc(s#%X)mz8q4OQS+jU0pq&e9E+A{f4M?=iHWr zo4>WsBxK&_QMqCP~Yi=30lbnYi-N~^U{Q=;y|Mh6$1|t1qQw=x zvwXX-x_~TEERG$X9D0zHKyMRx536!18D94jm|q;{c?flwbT2fDm3C`C=To~&{xMJ+ z#$ZP1TT50quB=4gyrmq+yTDFp`&O6V9taMDJ;z(B>ykp$Xe;8Ok*nkxF`co+S*~gz z;H70H<)maJ)J8(ZM9fA`*SC9Ry1?9@q-=nvZS7pD-1*G(xmLgau&omqkzs?fY(rTg zqPsC_U9GZRmHOh8f4YUst(}uoQ|d|2ibX|cX=Vi}%8p^52Dtvy(I z9e4CiJeXkC>Z`G;n?^#~P((00P5&$E*j?J~6w&Rp5Cv%|uGpN~T6~<^<-QT>-0UuS zGgbgeE$=2tD6d!zKasATeJm+lr+FL5%S*EKk0bFDC!svJGH)aKtR}00Vb=IP!CyVn zdqkeBjeSD0n0?yzAj2gu0nxfj& z*Z#KxS9v`vq9p=Yg)sFWPe(;%0_9Lt_l|w7Ew4wW-ak+j;5T^8%B*o3X3=d)^?P8hrn?uQ)zBM^q!a;34AX zAumY^1G=eg{YJ-FSKo33|JC3#x?=9AWuPT5wX;UmSTPYrZ}iJ~k%H^*+U*HNdIc}D z{v&+D>%dm>!dNGkB|ZP*R0)O)mX#Qy$-UD0k)>I!1T*lAz9ua>Fmbl=(E2?-S7~C% zdRqQ(+0ifJsx0qcZ?JX2k}pv3fka;5t0UPVs+kg5b0p3^+bp3kJ5=hwlh%nOt^|JJHUUIyKcT%?;OI-22cm#KvhV98fXS3 z8Xb6Sfm=s>$WNRfAoent1~gEF`Ll0OSC2GqjG=WtIA-OlOw0g8W{d^b-giA5ZEz>+ zuoIVk?u^rD$6s3FqXIg zraOf$`%D~XCR0BEE0ZJV!4D2Y`p!E@sizH?juShU^|IlXQH=*|D_cc(`dzMi&mzIm zY3rfieXQXydm5l4;z^HIL*ZgsKr|8{D3GfLp$r~ADM$#Fz2cQojbYqK^}79)-sFmJ zea}z$)&ZeZhT+8V|C+NuaD|A)D_T8#YQ7$0(@rVNXt8j;z)rKlW;KCHf|nw+A+K!7 zLj7+5vLGw$bwcMz-z<7Ea{R5taNpTZ4--NaD?9CYj9huXb{h9KguMWXUIZIr0#tc? zSUld(56eSyDLdWH2YKRL-AisOpNa78jhi4e{$6^Axs0VI-he#!pP>nb58yr6hkcJ5 zYxVg+M&JHjbVH+$TUzp{ddpc@kgyZHIP=akggrW8Gbbg?Y7u}x@=6rNogQ*74YGzM6kn<@0Rq=2Ia^C?18-N7*J&n-|gqI z{=>^y92fkXRWBFGjAKOtg2kpElf<;%=HN_OWBSQ)c?F=~V`tBUe-l z-kG`l5Y}FC@x$a7!+|Y1O72N@-{Kef9fZ6=cv58D6^%smc>Bytz z7fz@hN9dsu?ZxgN|1}Y_F9_a{GB*NQk!{$TV~a5zyk(NGFC|&1v$$DOJDo=_^y3z|{}^K1(_|1;-cOxK2-~A28Q`B!Cfa zSu95Z7H5!mhk|1w5X5`(b_S^G<3WyWfNpT5_LLgO6r5(@zlpPt?q{!FJ}I;JyKK@+ z{+2dp(gel#qh;?{zQeQzBdPttq4g`DcUV7SWbc?dkdU$q`g3PNRJ)*mpi673e!gxEzu4!n*#NF2@Q5;$g0Z^WBy!(Fp-N$c57jgz{0z$yuvG7h; z+hAPoNW^XcUHBLe-Y95RR2C^MzGQs-eJ4lX-2DXkLx2jQVgiA;cWDR6pTJzUb9+%c zcX4=wP4$zHviCc2e5hZ#*gFifA2_+l&EqV;rqE~h$vNPHsDr#?0&ukR?RfG~4@pw^ z8$JhGCO&QcDXD73g~DhJ8@`k4RRv%rp^A$?i5tREe>A_(T5Qsq?aLmh?7i4vemJfv zI{NYl(k`y)P85rL&Vk7Jw69utG=DX0nM(T-+%~}SCVo~8(;jPo1u6TlzGqVqf%hyp z*YJkw&neV0Kj-{9+)CGByS4(kAL3_}^;Iv7bmk38;@kRvC5HtRn;(*VanOQZtyg#@o4xTP#I=gw z@i^r@6&TKCRLi}r!ThSNFfBCBEe)%+Al!>FHJ#f|baH}FqDO0-ue0ZC)1$Y_y1R_- zb8bUTQhXbeHCYk=Q>K4sh2#lhb--qDr8OohdC$5)kbeUP;*aHhT84%g(wNhlIe!55 z<|)-$HwE?)#KNb{sc)c$M;5bfEWN&8OAAbO%R}^b={w!N1#|P-*gSU>uD3-kzsE>j z!!y^!gda4ffV;v>GU9SA?%2mVgYC2Ev+;oTF0HU#q3uge!hIkRO5WeoYD)EVKeH#X zNuO>K>bJ2wV_NV8u*IKAxJ&tpfRfO($7LX;8q(w>Y=mh7M{LpkzAXdvIl!?12S3wr zbBV4XnS*N9E+#{e76CwYU@--1IKOR!!RSFKV7Y# zco_MS#2+^8@b3NHPBWGfVf|8vCyl9gJS~?9cmx6HvA(WF^O}V%9wv0m4)JZR`nykK zAzTRV4A}1!ge{S^Z9TuPVW~Q0#95bZSC=8A$8LPjA$f)_yIfT9>qHK}OxftTOKf1g zqYp%HOnXMI8Y;73xML|GN9te`wK}5m#p$3ft9B9FZ-q=Bgci!n_lxCj%O#s3GyPOGwS&lBD)@+O1y6aSm&hBz-9rA zb;06`4ix%3Po9ay+RBuU`6;`>H(Yogu?{n>wQ_w(`5^IeeL~~{G7ZYa02tkg|Ae9y z1>=mG>d8LB6O8HD6E1PaCM_U@@qX|j9;<@<$vks6Ih)6-Q+Rku=+#|=F>iFNIQThq zqTI930E;-VgBr)G#3|e|+YD)aHTx(C8&JE5wIkjFa%X~v z;`AH=RFjN~oO6rL*Ve!vJ-5Z$7l^XqktIktsjIi1oJyjP#Y<`+#6%bd$q}t~r--7Q z6-4C)!13E#5O!1Fv08hD;rm;qdi%KKdDP?9WvbaF_6 z+_sdG9hZl!f0hgQJX1t4uBJac#Mzr))v<`@DpKo*kkaG!L5R7YQZnz8!5`fYEG?>rIXS&P|leP%CA4~ z303j8Ox1EMrhD}%B}eTZ*xCY$pU6!hR;Bzl#pIb{l4zf&7ywzrJJP?U6%8^Ad6@Rm zaVtXJ(H+j_I#BH$`YRLbuiu9v`a#w&{s=o<=s(`F&~Rx>h$rXcl-&unG?^j1BSHUZGt$--hlO&EzivF zO~jGMMc-`I^d`P{WBzTY8H1GwiKOkVdj_yJq~9@wFm6Pm8@j1w2pMuv%KL@W(Q2Wo zx!=J<=^eMTTD;v_Jj4)4rhY%_g8Lirt-JLK!B%Z)yzR03#U$!|;lpR?SHPby_&431 zDm~!e>{17tgHK?x^CmXRd?{;v-!neMoC`?*rpy~E)_&4>~AA%mO0c}&;{8*)hp z@~+(5qPi8o;Y@RZUxX*WFsG0DV|M~;&!6QG_RB)WwX1`iwMC#=LFn%?Rcy&WK(TI6 zBR`vOK|Xww}0rkwPU4!K?`RcuBqW%48}cjh0dE}vAo>3Be7Iw`UlwB=phL+;dP^*?6 zUh-7#kfaptkS}gj=8!M8RKC7z$$(Cvw@zh>+j*FuJQLn7$2{;yiFM^^wr?V@Sf(8e&a0V;OHkf z@{R|~8t8KT!(dJhIwPW=SiKRU4eBlapXRp{^}igJcr>U$lLH}J1f%Z{VAC|Ui7jgR z0rB;u#HPfbaUzyWI#zIV%uj|VXYC~;F>=~-$zaDOPGumKD^C{x@S)W~tHB6))fnq* zp`J|)K&or76nq#>ld|+l5L>F)=1{Fn+Jb7>*7p>3$zR#h3kRWy z(gDg}~_q!dFA1F|kiD?5+7>G{l>@u$FJ8cKYXcsT0+13UllXI8h|hRmY&uuO1jrklpq`etM+ zyWP_<_9O!?9FwoP%mq|I3fjt2sLfX(U-*nEQQ!?c`9}WSAh|;c^HL%W!@n6NdPtpqQWYEz6rYg*q8)fdC|>5)S|e+X@Z=_ zxpi6Iyn6Zj8`+Z*Tqa|mWnHwMvmi-gQgpaIltV&udc^3JPPCjeud1RT{XIvbt9>}T zTIv|3+G?!AIs5@U6FiLFa(g>`r>j9Brrd1h{ic)huZcUq7Qc|s+ui&yZ@iMH;^;8h z%=|ZK5^;NLl1#ZBZ?e)kE;*Elg7IHAGT&WyK4>ICi3qr`e1^&@HuyF2kYuTpXaDHo zWVFwCl;>gaF;d3m*s2CRbW~Q^Z=;j*Rn6y1Z}Hxf_?CnNlg#N=)1nK;hXtNT znrlYc=k(L-Lidlgj%RvbDVF6?lb^Q+o^D^^Tpr%_QY_X>QTCtMP`Eiao@K2jg&($- z4IKrzDwkT_9e6U|EE8@%VXukL&h@5?jSjH%)uq;lzns&iJ zTT+yg6OTaM!nuJ0+9Gga^5;}%Co=?>NOo<0Tcu~xW5 zs~i9QU>;%?t|%zL)jyTWCkr!jzw;mxyy6+1k)8l5xbago2%CKU&9BZE;^WHLt4d|KzlTlqbOF`3S&BsXVcetH+S|AsY} zTWdN!JDZb`Qd4{ki_2i9C*_n>qQJ{(Ay1Mci&VdlP+t%`R=@eVT*@hOVmcwz+iDoX zOwdn(8w(|IzB-HR*6&+HG|A4uxcS%GA@42wrQoOKBUjJav8-Hq>jv_u&krE&s_zvT zHe!@q4BH-5b1*if7vV?#ZFRroE)ZK#0DJv(_Exdd?P~q!XLX;3jS4p?_6?@MvpLrB zItBLXM2pkyw27@>)@tx%dw3XV1@qc8I=1zLU?^p{4Wv@sx08{8nw>qG_wk5rTyO-F zdy6SzWNi1o11woM<#_|6nbF>MX(y;V{Dhu~rFynaV0EtQia_~LE57|O2aC?YZ%@JV z!tK{DtVkzb`A{>uB_&BKx!9wDIGGzQlk=y2EpE+(_nmV~XjN>HhGysZqLXs7gEF~N zqTHgY(!z{?x$Y}Ja1@pX2OB{R1y>Fw2XB93i-Bz*IRR@wVqB1b%GCu#v?+o?^(Dwh zxqV$(@IxtDvKlitlh^33t>5_2{cCS*sG>~TzVkq+wxXd-TE4TOsq9NEZVz%mDP>GL zzLT(dZ14c91IR0j_}$GW<#1B{x{>OdJe%{C!~rf3cQ&=c?Pd#9_Zb6DNkJy2Sn%b{ zZep}RL3y<9JnbJLE^J)Ws8uLDL z=g*&RU(-PHkkQQ;HQ_80!klVPC>(`pD%qdpT zEv7G!UK{4y|AL3s%A3X~hT~!;I97~mrC9dA3A7HSxP_zNn zKj066h3A&{j1&bhNB zL#?C7#7()58XNgDgNC7vWSxb%L{81eZrJad93mpnv*Cu5tn8;Ty9AW6M2*;~r|#cW z8OD;Yk6Ej8Ottl4&uY-TjqKFZIR|JsC|K-9Wu+6dH>NSqIRu~ie@*84@-^BmN4P0- zG@JFj7E&q|BNVay_wV!PgU5sal02Gxc^7#*+y>Q^J^j27j+PZtQq*d)8qc?NY{qOk zPaCdaNibgEhDF4L$3nzFHoQt?Y09f9kNf|l$6qyU~@g3F7DG@@&u=T8l2U-=d z#i)K|GUp32Oaf*8L4tAo%g*A}hIrGDfFQ{2$@&?7Ru-n#Je%~y6i;fxo+|+d8y&`~ z>$$AFnsG=Z5ctWpe_)$hw>SQh*LK&phm>6%``yy`ysT%%OCCJxI?y?F(}lm{QGShu z4}^Fi>=i)s7dGroccvSpC;Gt3*TjY7`eH*;<61&vTSL9oSd#~lQ)4vCAAV5)HtG-n z6cd8jMu9wuMf@F~7+btuV<3L+Ukg&^qP^c7D&#Tweo0bFAKHMtlww9n{_q29W5OXZ zpYQiCj-`tWF?*r=?yGz5X?FZF*&`}tPW5&SS@h}TzL1}vZl@)>3|{W755w-Z+rWtv zTxK;mf#$T6b+th|XtBk~<9I<-iqE;#Z%Z48iZ}U*(!G^0cx>mTjoTKZTMPPmrRJSg zf9IIUH*JnJZVP&cApb(2};1PVveSsd*Cpy>~;vz7@z5HIt4ME$=9y$@7cGTLP z<@qcoK6-$5h@r^f0N7Fd$#evnb~`1@D3CTl^2gg5sS+f~2u)ao~{@qs3TY z4fqVCEB`oy?%7-$@YE^`Yi0_*w?VWI-5Ol5Mh!~BA)pb)Yu-{@@kYWk`D4BdXeSFY zF=s8r&xP*osWSh|j&JWOWyQevvaAySJ~m=AX2>5{mECkhWl$ND6R$nT@QRoH&rz;_E5%GVz$$%@GuMgf&-O#I}4N`a1bE9t`ApGZt?qDzL zR#TeMGG|IeQnwByP!V6a5&ZZKpzC} zYRi^lWrHLqqFMqUEsMb1z# zzcD_bItO)mLM@_uvHmz(0L_@jeThKB2#m-Dbv<2o_T);saAy`-0m1XE83z^H;wvWT z>t=tbho@$2+4>LJCaA=UXFcNNTDQM&<+5ac;#f6Gif3(AZS`+MUK=(0P~VWha6U1&fO(Bx2Z5_* z`vpefy*wC?(||tK2-*N;D`MT7#P~0q^&xD2kBLYD(TCsjduRf`zwh=2npVvBYUUS% z{qi>EWpQv@^E42DGqRP~OIICoXR94xq4{q2XTJeYiYZ>gLRlilaPe?Ik>w0OS&q`3 zSR+4S3_tlSu5$TC;BMD=TS2y~GVKfZ>w*37KAi$jW)fYEMtGPH%q8b=Ttaw#fxmJ2ni`u$KLKnDOfG8V9&nsVmND+kS88)Qbz9W|EtI8iYCSuPqcPC`@QQ6d~oFE)*HZ zdtbZThdsRy9`77LF**(Y%d^l&J3nBw;h2}oYEN2x8I*Bv!tgl$wz?7^s=$^>L_4$2 z^Htj}PNj%P#p`+9Gzqmap9S|S^Tto$giM>ekSLGE5!3DBEvsUF#&(nOd=|@D>DzhO zFn;{czJn3%Hi+wdwB|Oe{psMe^Pe?r$K|~>+HVhK38~(bJ)(7Ieb7Jpj$h*rEo+#R zp4pXO{~wjUIzXa1$`>%R6fBWfV6v`dJ@?YYLp(zaArUG!p&(SKfLQuxTK3H$KU4H> zSP-Wh6+L~7(g?22d50=qud~+>oGeO+JFTkpH_>@Qco5ft-BqqIvqBjkWF#F%=a{H8 zcsSUGeBUe2gSt!wqBGWNE?6V*`)P(8qs=)?bb>bKjy|CVv1cT>$#NHwVz{qQCjlj7 z`G@&v#y<+3=mp`pLzMR%F~w9?pClRC+17XFsc}VyFMNHAD2;4XdRQsWE^^r3HSG)w z|IAses6box=RO+ap@=nN4r!cq(>ogWC!V-rUW-~eS&h|F%~B_4UZAsMOa;_sDVE?z zm%`biKH}L3eU!h3PJNxYrzcHaRmPjI;Rv-)mgwDwlMYAbmg zz9o^@Z@1EJK8_FA&X}p$&Axu3WNweL?l8YjD<{sVbrpTAWUtxuVtA&GSc2AZT4~M2 zoP&-uoRpL_(EYXdGSFx!{nqU3VDd2jlzxIa&fL7E*wynw&jL=O*ZCvdwK>8`|R z%(7&S)LwB@y@YqdaIr;0fp(Gm5g*pK3dYyyS<6p}>>jJg?VRl|3Jhi3-%mrKJ;0@IubFFMMn9#3flB#B)03vaODgQLa-NHbB7 z@x3eV_N~Kdf)i*Lv3Lp$YHTk@$rP@gCy;WJWYjYqh|K)M3(Mn-rBJx0oN`$DqB;q0V?on{po} zV4H>Cz8UR`H+#|&(*KdlH)9Jx^Pv=;Pca)q8Tf|ji&jLOG0=z;3V>$gBK0gMaBA=8 zkNnh76=7hlu@jSUwa>=%sy1DSz?1IG+v{MYK*#Xo=8!J+u%gg_TU8@EAwI0R}WJNbpvMe4! zlFLKS9rw>-^zi9+iI>7x9zB_@UMfp%Ae)bP#_df^0QOT~Eiyoq;5`GMI1|dQwckRU z$r{{40W;v&vaW}wvp2Gpf0M2QsAxW5`YrjC6iM(-R@0q1x9IwihO6ErE$Dz56XUwJ zoi^Tl7$NGIh`C}%|D*oAI|8w(jvs2~0x~kwPnj`q;*FFGE!2)>lNTb`z6jsr24XgP z)XG^#Q?*61RD0QZw9=DR+iPDuq~k~X%jt}WxA@={NahYQ=+>9i~! zIoW1GLs`V?&&|#yE=Pu{Q4$$l5Q5TB<>e?jB6##2;GlY#J0f+x91Akc`Jmw^AiC$O zUF!L`6r4AZBZW7nq4WXhPS`4|Lhs0wWfuuO(@TUt*_r=tww{*YTehTmh6z_w=)8IM zxL9HlQW4KN*E!-j#d*Y#i@D>0^l0XRu2urD2D;`@MWq&DLR1b8JEe#CQ$on_uy8b% z;U;4(`)>2CeMBjJ8svQddOVlDt=NheMQxh_{=Ne#P6rMPsysnxqQpkZw3?SnE2aDZ zy~FE?7n*RrKf#-+Agrr9RXNQ{ahKsW5C#v@IFrfQRN#l>}D3B&bAFY`Sv^418*?#rVH;HZ61NyyZJq6}{4!eGF*Ie)8nbDi>z4?_KiNg<7TFzqac+k|en-6K{ z(28HD{Q~F9S)Rit8Di?5yX#JypR0*VJdg93%9C17&XMwh*_-m8hwrmUO&ia*j7i^@ zXBO;a+F0fCRXZh*{s!F!!aovr!S+dRwpSQ; zf8K_~Kh38zr)MW}qN!k6t3kGKjguXSv?i;Zx8gKXyQzJ7zsxNdH}vsbU`=ydc@vXq z{9Q%m#}h||Oa6-L7QS00n^~Fr=7=!Nht)Cm7;ciwze9p@gr4 z1%|s8FRD~aHXwIa)x5!f0h<_@r>}OFxqfM*xQ9d?5wIDsWe{n9akkT_SaS$OT@fiO zZ6T6x7;;eDD=so)Jr?t+-7QFoMWN%L^|L9}>66Tx^_w$M=?Ou)*(aJtfRXF3(-Y8( z8GIM?0DRZ^!b88rU3Xutfn(K+^x+)^MyqkeRnCVc2MYJQqJqBSpYso6KeAEkfc9=l zj&vDKNshoGK|8{p*fyS|a zbl!ZuByg^3JKb~a&Zba*t_w=0@&wh`^tkRw+xECG_H|Pq$0W{bJr6)t&Rk_b?FVSu za^6m1*_3Ud?l`Xo?{?hsL`5Qw2;;p(5}So|i|mZdVQ8Wv><6b9df6$Fkp>>Sbk#(^7 zuK&hVQ@)aS{PXeTL+iCgMymc^W8MK~wq4W4C`U`+AoZh6rWiVCT0M5@h*$1&5;@@J zvTi13q;~Tn3rIVcOX9~20cU`I zlgZDaGr@dqk#H>NfJ@$5^z`SkrCEWqgLNkRdC{G7#rHBkB?tC9WU<$G*&N45*zQAN zx^{q6_WkAk^!JGDR7z(HTew%d>jSYr zNXiA(WOY)^i>aNKakBW)vx~rHG?2|v24p(Ze82UOyEf0#PZ*!nPeGsBPsW{-LE>Zo z=xFStki1>J`+t68kG%=!1msvWqLH5@G9eF{6m=`6e<>!9J$7ed=?!RL0!;)+3} z@UC3?!0kqQG1m5p)Y^F=(7l4s_y_;Apj6LQMC848PQXVQjFh70D^yP2;;wTu04;e> zgiRcpfGW}sGk^|XrCoZ}<$+%QNag;%Bd!ya(NFxm^BPv{#m(0%S1O_?{rLg<5g5QB zd;b9kc!K@#hyw&|8y;(cWV;3}Iofy_jTrruox(}HMe#fa{N<}*^~E1F<|j?0h=6(1t%We@N0?&1CGznK8SUiYcBVsBB)BTEUEbs4#*Z ze~^+-A(2-UCO{GXm>rzz_ z{Ih_AUT^zwwD}NZ$SJ)-Kjoqa5s@4#ViS?qe?=iS|m+ZO!_0o-N=TIZlQf9G+G zU{Nl9dHaZun=`Dy6IjFN)}rf>NVqiTOwaud8^^c5gb6FVcl>WSZ3Q1+ZEOWRgfqXl zx_HQvlymBZt%-_&jdgI-{XEDZf9F7E>2bZ;9`#;YU&wH3H>oQbD;ruxZKP`^f4I!Q zZ4AsE>|ZwDmtU51Dv>G^r^>(9zZ5NJUA7$w(;E z$JYzn4c$YiE8_K-;-HOyhS^fb8B*_JiE}6vMulQzb&%T`8Y=Ef# z5)ll?1<+R*nxAs&zH5Ou)-SfK5|_|Gbdh_Ixeubk3qPw-V(9o%>^Gi*CEw zI}>&N9^Fc%JB}_dr^=M4dp;Ihf=9GYb01$YhL6iza=GbjMp5#l#&XsUzRe&z#JF5p ze+YdL%)#!k^d!Fa5tjL3_%)2_{39P*&9WZ72Mgy6KM)!x&hDUES!a>TT3$asC(k~5 zH+l)*r4)3x4+#U&Ly(V9e{N(D-ou{)C7p%YPDG5ej4nHor&|}AB^hsXFw$0B{)hu+ zQwB>8EBq^CEXAONqU&?41LyE?NTl>K^i1oP;y!ar>w@bOu(A6i`Ru=a{OJ|T^1?hx z?AHwCh57PsOhUhl!p#3QDkyEe_@A7r8g-;>HfB*^%>w~utnt(6wP(&Id=&Rgb^ z5U;6!-evu5VPJ8PkyuH)6lmb`+2_7^N~`{JZmuY6(C*tTuk z_QbYr+qP}n`QCjB`(O77tiHNdRox-fN0vt%&4$?#_Nq^BJ{pn>Uv%IHdu7RV|C)uU z)x{g< zH8oMn~SEfqZgv7Fi*Mt#0VXbZ@?lobOSx_(tl zU_X|VnMQ$F7gG;iqrw1rPV_~PX^$GFt#Ir{Iyz1K(gf8+F_Gm=G%&!j6XA5J0#~Mt zWxKkznw9`_K4_j{WgWF)da5yBc@S>y<+K84!%n*hF?`<4s54?Xn7p07kACU6Fl|6B zG!j0DFII2p?&M;Z=1yvD^GMSug2eJr92x5nH2EuL-g;9KD2&oOx)n|dhAC>n>8v(UDAFL?u7V5E0Q zZokqfcbw#u^Aooj`HjO?lKT+XmGOBSLk+i*1MhrBT}xmrYhEF!dG#?daFuBdG+Q%z zMn)ufwYAv*6(2)?yj=e|)ouo~6%QJm^F_62_j8tGdTN0rd&v2&H_5@h1Z7gu`W$D7 z5FZ%Pot)%3E{Z8)p=-6eyND)J9OHv2)65Xdz>BL~(ZAS_cF0C+XUwVRRr?xO;j<5- z^wLdu_beyc|Fl*3$;ZFGf1`bxIEhA&-rRrsp~G<{u!BLyX~C7{XnQ`$XWjWKZ0Pp1 zGL8!Fff|=u0?rP)@IYyDdTmE0dtT?JQI^cAb=&3we{7>rY&laWh9G@LOQMMiqenr471}HRh6z#@1Eobi> z73c?L7XiI&SqIqXaO1(L+1lj7 zym@#nW?CDYlXM$L?zCWp#>?cq|0czp{S;?StupeR9*nusQK$1oq$%f(zy|3qJ@Ib@ zE4_AZ1bKzcJCQgvVMPmt%8;H%mo$eM^{d1+6}#~^GYIgo5zq~9Re zn;q4k{%BDjo??u)Y8U8Xaw^(t^L;cxuP(Pv)!7jZ9I&7W%KIve)rRtukkEl1)+!7} z$y>2Hw;eGCe2KJKbp5vT{P4WAzt#c0BYtXQcG(_9Irk&GiD@Ir4Qaum3oFr1&xpwt zwjx&r%Qif5z{TzJ5^)G;B0VJDj_c1lv}E91uO$tf_|&0+1sUX(v(g{+jp-cYQ;>m!!Me{ht1)0=zh9(~o% ziDP};hi*RUla4Y|U_B>>3<0#{g1eARAAHfP0LWbIe?GaI)H)X$5jFX$(v>`r#-XC{ zaf8y;qOF_wb=|YQryg=G3tyaH=)O^5wuVmv;gcb`M;Srkq>a08;d}kD`v@>TGme z{G*R(bhRFNwqaLvmF{|wR{wy((s31A#KSR>-7qFC36ma480k|(dWZi-Ey0S^@~pXn z@oL~%F^Oubr~4}&s1`>25Jc&(`NnFj-DRaM8GO`CIo(a!Z>mn?Okj1%r?2N#JzV~! zte6*kIm&c@xceX7A&F}4q6Gtbl%li4A8>hlQ9SpI$E8P?7%RW&KR)DK#=NDgIDG^Jx^=F#+aOV&eLRIT4rX z&YE=@{&g)9rP93PZeQQKuv^7g8aZwV|8z6+&#JS6KHdwiIM4}SX+biXF zpC1MAUHFgj5q@BuUQ5H^Y%Q*OgdKs_H#z+&^Wwnx#}fW-&_FA9?P>XOsu6W?#$PNOJHq5pog(3{(GGqzfH}6*P%a*9C1Vi*DI8Kh(Letsl%7YhC-); zhuS8J(5Sz~bzD&Pp2?foov01}8p5m93#o)fdHjyAwY}F4_~`MH!apkQH2DyX!crc%=at#RYuPd(S3;{Co(Y^&Q%Y5~X!(VJRBe7#$lh zRw!aYz#qY*fFihNP{aixe4gMSH5T0bB7FETAwfXck*_8rrn#MPvKm635Yuu6MihKl zQmQjWVd=(Zv%G|r6tQ3|GrYmd zkbNML%Kblxf)bEHe}$UZg6Wxzsf6b7x&8`!3VLdNREkJjj@DixyK+TXJaRP7DO7#G zARKJ|Si8#azrIZuk{KtTmCtLAB}tn!y;Q?H^3*hrEJ&ca4Zm78yH38oQ8Y}bu~hf} z@^^&pipd7{+ZiPCLme{yq;&lmsO7mv7I&MfJ3xUAH4-6s&E56 zT2uNPX^>Lr#1=smaz0J$e?@*kdAR_4Jv&}4bGFUJV}Y&bVT;HSo%yc_08IdI5T)s! z$VS<=`jc>^S9_q4@1JW63$vAyT{pcWYq6L#&ZDLR;Xm&D8?Ha>@6U!x_*8Gwh!PXd zNQEM#9FV`Z=79yGs-#FF;!Ws_xLBYAj{C2OFT67pkL${H%)B3Q$Z#48D4r$Jgr1#* zJzgtKE8C0PZ2J9AI7|fagQFyFJi1h6aX0d`q`cx|(hNW41BB#pP_0Te)bpAWiCwnK zgDUsCjb)do>KKB6xu+iKIeC`&;a#QAzJz({eBgYh<=S_Z z$KLqRP3v5s7PRIv$3%V8?c;wXM(?*ua=5h$w2PX=rpCVD)5$5x zD$5*PiByeEBS@X$gh7@Hx zQb=0xgJAc2>H}kVC9=5`_MR?$V2oH>%skReYpas-f%{uR$G0xV>jn&(sIiGt-zfCDQaw(fi)c3Oh=Z|i3{vb(*TvC(b#A5Dqx`-C(_p654> z9?Lj1x`|CJyGZoP`O`>5_;61qc5`8ua zupoHU0#PAyu<+~%DKIQ5wx4bLgFFE>qZVv&oNR%GyS(rmA4Jh{^SMlW?X84c{qNU7 zcI~<-==0pXZ5S9@m7CCq_6#5d_SmCMM3DEZ_ulBr9LDnfuC3m@{Kp9B*&k{*Ap98} zj|#D0gJI5Im}O2nrJ3#$j~k-~*-WzR*dT~D@hlgutCb_Xb4VkrMY*ut=$a_2vk;X( ziorEm(d`rIm`YUs_v0(hR@3RvDA-&73> z;ilY&tetE*b4R_idVhK?Q_^oiKB~w^I*7g;`e6I8TO|V(eI+(6UmK-7ddX~H-CWp2 z_&dGdp}sT7Ep-=H3tulsTjA0EZvSDqUge&3yqWc~KdIi$(69EF=w0WdGlKwoi?#U~ zF4CD=QWeTK98scg7EJz)iQt@)`Rnxg; zYP?I10pBZuM`Sj}AIH@?(KFneAb-c=#5HttL%{kQ4?}iL$UNdGdcjCk=wEzGdjb(` z1Xf*V9k`nyiNkz|SHYrtM5FkDK_tx$VD6L)?{z7rTT&IP3CVJAwG;v4x*tQjmSl5A zhxY>~s}ebz1Dug|xF#JlJUum(Za?c~EQ}b#CetvVQ6)X1V=Q>;h-Sf+`PkrK~wagO_TDf zu_v4FSCzL0wiO&0UbSq6hi!N9f0ESG-A3nL1^&qJTN25_nd5}fft^N;xTo|s5cdrW z0{FP9!FEJ&X?$=my?AN_18Nat41L2kWwjxxBk=2C^KkAJ%j0pNmTgp^KY3>(Lq#k0Mx~OZj{`)O*T)oN8|G4yI@SQEq%*VKC## zvG6^@p%Q57%}8gqP}oimL;TqaMT8EjTE+a2`h%B}ab_v!Qj)r1+q`|Ez28ykYZG-N zqqk`e5;eq9m}|?a|2yH6lYlpH+Jdh4qRFr2^pp!A`Z>#B$yqB7^haw zcY)35pU~L+aVdQlYVq#3X_u$nC0CpDk8Ke?Mwz_T#>nOH`U#z1_3$k$SdYOtpViHB>v1^_Sx!>QTEC|1Jq%RwQX{=DpS73rJPC@U zvut0pa)FrPI7~gREm+owXzG-FIDZXSNLq>iZ$HUD^xhOHM?~i12fp?1R#6fOnI3Pc>~z!>!XR)r)DN9Ai6d3;T6fn4@MeYwzB> zRzTIUpF~lsl&nJ*#kgm!Kx2(a6)!nWDPoZ$%}cXl+XtV&`@hSUUcL2TaXZ=qoBz$H zHfaib-lwe4FZ`YuL^#ez&%eU0w)NSNyBxpr%kT@7*VC=ua66UVj-FH5wG;T8B^irp}1cM<--ix>@)wB zM|3$}J=|6Ha=8r;EBe#OQD#7D>2k51R$GOu6^j(24zz5&e+-SDNU?ychE9CuVs`1$ zs)06>K$CNgjGB7g6ux-;9KWf_y#96H5FWzStT3UD7mLnjx0t3=Vk+B-c7u)1YAjGx zjWn#n4_ZEn`wwFbhW-Z(k^K5di$)RRi%_)JlFt8}witllnIzEX0a zkb-dbAj!;=hbnAzkc+2l(3XtwsbEt)@+O=p-pGy7wR6xm3dUD;5364Q#*=>*2i6lr z0Inl9E#6ti(b^f;i4vD%x~dgLXnaM!7dn4HL)Yvur9pDyYt?3 z{=9xEz4i*_3xiiq0m;7fA(3F)9?esJ z%X&i|VVMNw#acOZXuv191Uhqg`*7k9x2Oz!Vv-6Ourk3s3LKDt!lOO3uLC2MICEK> z@5v^Fmhh}*a}J3?y!swmE?6Z3f|9Hhp#FOday#_v!xtrAf;<5W=8dKbGZP?_hv8WXa5j}`sV!m)InRVr7$e+rv#DJ$^8xq41C@AMhEb=|!M5fIBu zMx@+Kp-BOi3VHZ1cmgsa#Tn$`XmP4QI;7XIghauLiK87jym}8U4M*?56+7W_lr27| z0r^ZuxiRYPi%<#&K{g;Cbjg<@5fsTi7?OAP*f&PnKbsPo!^c#mg2Dy^bs&l~v?=9` zBHOumG8NPgjgvjRz-D+Br7L7~OThJ#7(?yPn?-web+rfDM(hlhWL#fFn~LOg)H&Jv z_4$CqG5)n;z|dBC>1X@#X<|3_f+=Tj{Bm@QIz3EVohy^&o%y8|L6#HjT#vH~iAd!D zmmL7-twXp-jlE%WeLwGVifOveb$Gg@WBwL$jdB0y5{- zaoFHxFrlktePn0!0Ce|$3J$GcRU$g$;1TM4&AVrm)o|P3Hy7;El7w(%yiO-X1(YB-4EQKPzb9z?lJz(g=}l(AK+V!3l{H9Cm7tJAwT!Uwsx z?rQ8)&7`pB8WVROA=;#d$?jy1%T@p^bIsidej4v(co03}Dy^=ow_=9Tyr4q^3j#e^ zpGT8(pHO&^97D*W3aYG{0*8+1yMzCMhgiTKWrv67U>W;cPIm)tiL%14q+_Y-G%eywQKd=6{o)J>I!#W1MJv|$*v<{av+0EO1Q z0H;j!*SqE`sB3iOyuDvnC6C@N?b3^#TTeBmGHm_gfU6Q<4%mc=XC#z3Jw$Pq9oGtWmirj~dxGk%*~T zQD#5r#COX#DA{eF4YSjRpPziW;pmWQ+k0Uf0j+6>wF~e7@Z}1uC-4@H9IP&(!P&>% zTfJMgucTi-fiicSzKKR)(Ey0aqaf|}#F8p?vB6Ix74wp~$U%4h`;M~O*wM-g-g--U zs4$jy`?O|jiWMS#{~D^)UGX4ARuvCgd0l*1_X6Nv0!3dILJb?2K1H&jKq1--lmgkD zl446Nup`icB1`pcxvQ;c+D`qFxg7HYaDmoE8V3!73RI&U7v&2*-q>{IbkQWmYDF6n zB_$$CY9`m+9K#P;(A8py9aM+s z+HZ1)sVuM(p{hd8B;OPTP+imrTH}@4qsqL^qqRxHUFYRAC~Q8$e;QW2c56viKz+PU>XNsBby+6lpRpD0`PKwjUZs@9^Jry{yR~xt$1`zmIcwph~BLp zzhw_T-tg|j4rj61hjz=j8yTZLwBf_BhCR-mH-$vgt-m|}m zbO*UFuV|9GU~+F2d22Sxxr!9a);7*!4I06X%;0keDd+Q=RHtI#}!|#5*EtY zSK}D@JUaigT~Np)_#i9@j|xC^ujL>5G?CYg|MMW0Pi25JnJeb@$Ivmv@`TIPScnMb zOS+XE?vm>n2qhdCGv$&V7}5W!l^B~ zdv%<6nnevJ+4k5;d9x>iose9PJZE75Ro`ACbDP2BkTX*lrZFrr#+FhCt~*jJ>H@38 zA0|R^J}|)|l6UN_+DR%FTbVMD=em$>C2U z$lK0aLSHIAJnz%#t=8Jx2|O<+-WRG!({go_*F(SW%fqvj+M7)Ozbr7ZHYYBgD6*Ko z6smdItyKiUI}H3&cqhL|A6?pbO{tqBZ!<92DtybUSQ!dEb4~F&h?@P_)*L$SAtC2= zS!UgT|Mq@ymnt3`Q&qAEiJrwj!e1C%0FPpydR}@u+X&=MlczdJ>hM%;(mPe|xv~%_ zTz;ZbzuH}U3)opNIX~IkqrGB_+t0v+V%!nGLLp+LR3l3S#9UKrm=)P5ZnHWvw+-G< zsx}vjKP;~d#_%xvMW&N$uZ8h=1PH36FqgF~{ABqP7%vd20D6d0UL?CYD==<%?>};L zvm4zSQkXXxJPluWwxG*)Ke-#GVw#UsW-Q!dE`PrIDPD4!BI+}Z=>7>kRCmw$yX=cS zHL(-w+!dUD@29d9{u6$AX6pj5K`g+E~XB#ntFnA^saTg$1L9nxo5#@@(h4k+z7eSWbuOyw^7zv)> zZ=4bDn?*ql^?$RHt`^Kk46eGL+*F;RC4e##%SVQjoCQ2s12ltBt4To=17oZ#@(9q} zO*oN?te}e65Yc`+IJw*Nve8=mwg-Ife(z<4?|$12xzbho_B3R&*22^LxiKhR%jvvr z>n@*ql!L%`)}JUNp#uUuEt_M8{zJRX&a`2t_ z)}_?nlyL)=JVrao9a(f(+UQq_Z^Tx0YMO7FcdDfpRa&lZbdKo%Xq-~(Zhz+Hq9M7j3XBC)+N)8ta7Xh($q_e5HP@KU>g z!AX819ReA*Tw$EjweDdIdb+EJRB{y#O1c{$raLx zO$d_pcAs}|5t(m%Q$%_9MpN#J z&X2;9rd!mh!A68iPS_q#hh|oI!ghxO>Q{|Ejkr2Tide5oD0|uPAXN}U5F+V--VUMs zpM({hg-F}`>j;9mNV*__HbzHi@TjZBPQ@E2FDwPXpEw~&=e0>v$*Kxm>RobG3`|(m zY=Zp8)LwGPSW#FNawXb&p@W9{NfKLmnh6@5L|kf_u$}V3tM>$^(Dn&Sc=@d^fB;XZTk;XPj56lwI(j~|E5ARybmk32{AXB1RcVdXRn1G zJFE|gTVvw@HYGm`>L-o2#QgP6Y?ZgdNgHvC^3sZrBu%N0H%jZ9!_hM8yy_2`YRu;~5 zbcR2jneeO7momhJz*QKp?gevY#Vx#=aGHxGqsG55nn5*-SJERMw*yoHa{5O64bAik z?K$je^PuX^&q7L}DvjyvLr67YVF??>>m;YqJ(VxTF(Z(vc7U~oM+2PB-0hTu44-bj zy0QHmKhZKscSK;Rcr+}eVJXla17j2ZOric+#cWQ1I{G&mE6N{K4V56dSbm|nD7ZuV z*^_55LmYq!+bw= zc9yhBxYdOfxE1{QdpElL`gPl7rJb6Q@bSRMF^!fTIL zkMx4n@mxW%oSB@tY*(?XMBrGFjoqlzut^?j1Z7$hWN-!F%b6GtBsV-|EGkNT9w*PW zzVolYAziUxL~i^|g&-q+wAN+$jU!%C*@Ssn<%cVLlL;-s9+S=uPri&QTkO&Zfs^n7 zMK1gUqVKc9l^ilrq=De4u-11gWcbI4Gu#%NHqAStk9~FZm!jCTG>1Bwt1o}`L%aX) z5bKDkS(%1e@DMvVP@gvH@VjWxlSnS$T= zV{PRV9o|;~Batv!QFkq&MIF_&zX+6TI_7iZa@Clu>1l&n!=y%YadgHEA#NqJc_~eb zZ_xB~O+7KLbdTWE;Ad-_iU|asKR2OlH4-H(6E&(-ZgX}3>?Nn!x_z_+oK)pf^7qYI zxI9v_>yZX1)})0F{yU^VRfho#c-l&d>f7x-SfEhrC~M%;G;FSQJxsN!QIJk3u`r1>;f*iX2|}%Y>)M9Z1BW|! zE>hlI9^Zh+llX0G--dzO-^_Icbf5h=h?h4A*D-OC0qbxUn(1hgrb{#e$mO$?y3slZ zHfPX@z4g5-DtdQf&`}wejPzR_mY8%aaM6ir;t_tb14SYoX=$(qbK7Kwu%KyK{J0uU zrJx(C`5VnVFVBMv2xEEfw>DQM&D0&Eg*`jf((h9=A~KZmI{KdbJZBKnE0PPAEnJH6&6670s|3XJNzhsb2BR51>+cVc$0=xMz<4%A+obI^*{Uq?&SueR!VG^ zAm3aVH>SR>l`)(0JP(S7&Ymw@eV=Yq#u1fw%x*ENRxZ1CV@ibqo{ftVF%2a~B08#t z0vGPjV@NV(PIvaNpF<~rVgv&7Cqpq#20pWM?yQcXPnlCsu&k=8DkFS~X~HtcCdxOm zhpN7Y>FcW%?k`Wju7eDolUYA-cFVXcPC8$=V2-IyC|wEk=6~ReYTniiT=-~`Yzq30 zmzrF;@{bF&VdimHybx3z>fxW(cWZM@S{r0)h z^q5qg)bc8By2i6@^KUymU^D8W{5)+;=AXun?Ltp)7@BR-RS$)KWuPZ`D zCthr1WXO+I(6D@5u_a8B+HA88xGLVc`y7Mtp?81_aje54_gJ%#HwZk=oCKIQq~l@u z>?jPR=VhxaIVf36OtVv>zqxhbe?ev!XP34zqBV(yRM&x#iv>pVRNRG-z^j_cQ$FX1 z7i0xVp;b0IF;+!8&KcMnCKEN^859N7iJ4IZ;?(RzSZ>e#69~|~$PYT}geSgxkOlS{ zAWL*mIMmy-R(+n-`jYmXM;|k87^Y^jR7B;5l?Op)#)2RZNRTioO7wL-FPL|F>!87& zsl{TKtx)IWM$6^z0BqRQR#agwQv>`+RSu*(kFv_uqHU~jHaQ$d_DpG~hk_20>oMSZ zNUnD`xu#LlDF|R8NhBsPh^TTyi@M-<$XD>?@#YXal{^0qp=9W))P`yo+^C{BEkFK! z)IJ)ld8R(_tU<6PmSAs(15neRQ5h96*tseC&LOr!rpw)l^kh8 zg;F3g1goQ)Y#Q%t>8O_lZyg-$gFKByN2rx2iI!e8%~m~i!Z##}!h<2}-&7gL2eZ?N zwh1Fr!e5^l;B?33jQaIjef&jRWu|XcELEe(iE9{cxAR)OKGvIn!+`N!2kuInfZy zgmjy22Jg!nZOdI_*KKlli3AeJxYsQlh6<1ndg_CpMZ7f692i-%Il^xf_w#>?dZ@hs z^;|B#05?4#J|G?jnFiS&Xb?S#qJ6x^rjg5Vrz>BrfaB@=Ff?pjSTXV#D5hQ~nls7eZ4?s0CzS<1q6T*Kj>|w55=f?dHoKnt{wY{=wzX=xv$x^~jM{cJ& znk2lMpfQ@?LzTEC(srA;@dn)gzyW~@9yz< zy!c6dEq=&ByjVF)`y|MHxia+UL(wCz?PMX+$Z|CUftU>Wn?mIRmELE-Np1UXSM3Nw z@BNOR6Jb?FsGR>}M%e20R_}Aq*Kua!(M*@q{{3WYZY4{KK2fx-KmkPL&kf#M>&1=_ zXj+Vj)hn%LCy+#6#HN7tS*Na&57-~Q?D8M*yX4CdL{6+J#~ILGd-|hVAa;)0*j?Bg z*Bxv<8Xm=a{V%Nj_DG7u6Bpn&d*dKG;o#&$NFypZ(oNHD7q=bSNmF-bw!x4+AdX2I zyqLcb4u+1?lh_=Bkrr4u3 z;{XwQlhC3bNn_9Xf`f%e>&3Wvp}kY{U+;ZhlWrcBpYRgx&Vv{IHipjCwOV-F_51R8`cU zI<$dltx!jl8$8Um*Bzfv`x-E(q9aA)>uO@BAS6}uO_x9CR_AC>pcUeDmaQ^}_MMOO znUfva?!e&O1!dEaCiRFt1-#y_jJWXN-%Q;JOlR{Ml*=Y_Aebb@e?qYZWr`;i$FK_2 zVZ)5+vn73G0A<-J{`cU307>BVK5le*@U_T(uTZ>#tu@+L)R%?i{I@Q z|6G?q^W&-aluc`cXtoU<0eO#VnraEPUsPae#LFB^?tSu=0v1gWi^mvw4!zLA zw{ArmVotN)ZzTptP4#B7y{sOhf2rtUY?~4P9^Xv$&k)mvHQ6A1>2_v}w+o>?iO+!k zjPRU#)x5B~_|;umyk{QIw(zt679SI&lAOZwu0LOBbOJp*4hfK1rEH6lV>*;TT@7<=7tIW@?^1=Qrvjtg&US-kmnc1 z0!Xz?Sa3z~@un>fOO!iPtrs5#rYPrwA*^@6^K?shJm$)B)u)@?ZM^doVAv$8 zxZ|}udg3BGqwi1YLq!h{&_AF5mbsA zh?4|`a$Py#C8Ocx8^F5O8(|(Pk1~2Ht;Fy{@?v?~f(1V3|Lk__?{*8L{bV;)7{Ja`zIjUxeZMR>^-SMWn+S6<`k#;<>Ta##$q^RDcFEzo&8f()GEVa0q zjMmD8cLo#wrtM$0Jq8CyDQvrP`vpA_=6?}AK{k6*d!}F#w|~j|Wk(k?qOh+}@Tf$= z0;I>cIT{)*0f#jgWkr^*mzO`KrKO#vzvrvF-zi;+2hkl7QO|_PSggdhl8)`H$WUIy zf_{W$!FUe4Uy=_xBxy@5SpQ_9IDE?8CExu2O5!sPJU`naR7+(CJ_vBq5m5P+Yz46R zug1~+NA39vpLwuJb$fS3k?I2_TKl6!tOu+`QvS`!&7f|Se{yk8$SNj`?BSfOtAXPQUdG1ZMCKJ+h*y7 zl5!~6n|1MV2%Vn*-ZM*F@3|HE+$OpOzr2R>*|p%HQl=m|aQ%9RzqWez^3G#BZD(7Q znp|DardX+TGb1Wou419zXz+A6^=3SaJr{VlyO_@8(kRyZ0$Q9M3IGEZ?JxAfKh z;r*nyv^cLicl_BQHonSz^~*d>Wk*1_a^VdkKL8bfkcZ; z5lHTEKv{T(ia?ZJ6;UYmEfFdZY8oB=#+C$c=9`El&a5{96)i?&%>3#IA7bi28H@dB zw}(oVz(lp;In>H?WFTAG2Xt`1H7TcRiJlG8yBQfNHd8!j&f^;IL}khqW1S!^Xx5JE z4F4~1W?xZ0O8Op_GidVJ;cI7xQHh+>sEF*0T;wXXYuS@Je=(k(+eI%@QR9X44->K% zz3dvBH`*2oJ38BFOh$+HR+?IjtSEA}I|!a1BgSfs4QtVfq$59t!j^%^a!g>oxumTA zJs7$iBS?Q1qvQ>{G2}KnQNroK0PG-9{)18>ru>f-!}-5Wfd;Z=aM>QF~}W!x0E^Hp_1j8BFbY=6jcy5PllNis6>ugf2vJu-!hh8 z_XRdYZzyj+THl*55$S$UtT-f$PIb_2B$e@A%k+u)!SB~p)qIVt8Il06Jre$(?j-`t zz=tlu{34uK&(ySDYFdtZ^0e>HNdD;rSR3Vy?BNVxd`+ND9kvP;r?NmGmriz#e$JSW z5SptL+YIEWYjL5KroIm5#G^azcOA%zO>F>@I&-cwS_$T)vIDo7e4if=Jv6ZaW^t>73pFh3zm1izP|>R^)1kI4VUhPQ~2Pfg&C#qO-E#Nq4|t^`=+Tc?&Z+jCWe*Smm1 z2mObC9mbK0_vb#B=du1#Rz+VyfwsN_$>cYA+7R{B(XpW-T_p=iI7&a-w7$>O8g+L8 zhIEPMnBmxQ<-ofy*+}XtJQXWx4Me9-8_bG>d+eZaIARl_ZgsYpZB$r!p!L5%#j&GN^#e<419#Lb1zqzoY&5 zq&`NZ{rR*Ljdgd2>`{HQdSn?yxa%^Bd_Ft{8uA-upoi&Y>nff?1#A`T?w_Z>3gmbY zbP?9O#8oOdx05P7R(y48AXz?z2?6((q#_FBqOV!dlxOq5k)?lX&yW# z;!D1IZFYm3VnkQ+f)m^i8=*MK1n8`^UoEG-=>USKdl!sYsDcxWJRt0VCxUazt|)})VUKoTRWHo*>*5_sai zXvMy6Q_n&*91ZAb#r92(Mx6sw&b7VEPQ}I2=FO7*%Vw-d<%x|P5F8(F#?K*Wo6S2r z7T0Y5YQ0B0goER7fGnLARk#|&S078&SU7Hd>xiJRzG9fB#Z)yIG2M^LQo29cs_m-L zD5}?w##U3$RHD>ITPgC7q2g&G;%(!kGL=20($d3r9k5*=e3id$!g`cVZ6mn()Ge*b zDH4a!*>Z*EW1MHwOj@xYPc2ocHP-jsI)XZUiiVd>w-~n3=?@ic^FUWcgQZAu=Vi%! zgiOde*0y!87`45y!8!~JRYp8dymr?By-U0zrX<7l(eJDJ9_zD)#{xguTKX%lJ-~X` zfK;(OHoXzGVfXhwTx{aR)L=!5T^zhyUDm*K=g3l7k=;5WKn#Eb9Q3QM^WOv;tMId^38}-M}T~T=SU^7gQ zM6sS!hG_q?Nc+!oQ&ol+3!Wy+)f&&+Rw0LX??MQ%4@9pDcQ_G7Uu8H}LFYY*gY5{>Xypg_f;sfoDeusE-yP-$&&UkI7&;qgq>G~7(w+80 z7Y1zWg|O!e`^h|^=K;M}slKZB85+Y6wNq~}7z&5OX1!MT|2cf=0YM3Hl(NDSCqWg` zaqqYOh>Qo+^T;10Nq-0AA;X9-nbYP_($q?T0Dz58R8&@{YO5>t=H}Y$6$$H@c3Uv}!Nge?n~tQVtLA(tk)X z1=K=-R-#ZA zO)A2ON8JYxU9r$(j?mEP5dVRs)d&uEpGzc5j#Fsl(dx1c@YD^}l`#N2 zRGezXcr>th>Zhl%rO<`br|jeoFu~3Ap-@E#`r-}cYvJK`*O9lz33?L~=4tx3Iu!Ch z#?C3avL<}IS(QH<(xFp&mQe zFQ2@z@gckEALm};y6o2SMJMcY)%dEouw zZobjJF#lvm1`rMS7lM4k>lI*z!)R5w1?jo2hRYZOBA8f+8$6XVY;pH#VBQo;M@Ihp z7|aVhI(GW@q3QQ<|M~?(J4JWDA$jk8wx0Omz~z1XPnHXfbmUQ8>nVID@6dvLmbGl$*#!lxpUEDAw&h7@TM1y^M zMHeT39AGl5@Th0tUQHFZ8~fOUEbXjS6^38y@^FScr z^8y)L%G1f%n*^-nD&igA+xXcq%RdXF=GVyeL-2_Oty|DUy0ajbXC01)% zk4IpABY$U$w<{Xk&Bq7Je^fUxedrqH3*Z8q+kk)H4dHwp(iP1E+ia}~OVD7lrL)6( zdyVEFuK2x4LVj$%9tloRD;poFKN7SRYFr!8oG7sxB>G`bnC(Ewd15!~|Gr*F@or^* z)BaVyad15J?tY@XF!iB<|2-~v@V3i%ChAVqaE8w^_Wg}z05-Th{fdlWYG>l?;$&)Q zi~O&$H?l%z`Nhgi%1rvdOFlj(2}>InQzs?~8$%aUF;ioE6H_KRQ#*4P3sN>_E&+l6 z`4quoTQ!N_KA0IT%-wG!ww7l#11R-FG&!`8gx1o1j1a04cPfGGyRR)C&9(p3_wt$F z8J2f(OdA!kL6Nr-2ImxJOFO5$S`E(p5*E2Jz)fkYYOqSeGJxCJIU9%2dP}}xNAhyY zb~d_qVBrkYoaqB^HQe?uN|!q|){bBtyN0o!qgXFkcvTQ~cLdRPiDx%IR5Q==B$+2khK37; zmNJ$1sH(>Eh(9;#Rfy-OlMH!1HT*T48K$CSQc%@@s-};LWcr2wNx9D;26;R~zu+6B z{U{L$CH2^TJ233@1Jhk|p9VS;1a@g(lwpJsOYCL~T5NtHvf=HRe~bA;Ac2kW7wrGP zho0sCYv@^7n1B7xJg|^*v2$|%`oE{*(i_%8P3;M^{+{9u9|#2jg)xbo9+D&^Qc)Np zgb+9fpFk=FQHUr;lh#-e!Hn}491rR{>a>FNmltGFz%1Nsf#MI$9}Thl)NKQL${i=4 z%K|4M*|PAn)9>5Q+vX^O%h%plZOiLNNu)&<+G6-eNCc^Qc!KRFWFmSnlRueqK-PL> z@#vB4MXP_x)D^P%yV)Hvm4iu@RnJNDTWUUylGpee-;G!*lH>pAY<<)FcT`y7He ziNGC2(P<;H#D{jg-Y#D?;z2E6+%IeqFlKrJ?oOSaQ|sGeu!{XV#%`}msp;%bc9LI4 zCC@W?tN@)2gA@$;N&~;+6kr}JL$5s~dSq>64_>N}+IwVI4KpxXgY+AHje(C)) zLi99KvS%w}W@pjZ*p0|tJ9zd5brtf&M}Zr%8)*x)yIFF7i!xWaXwf%8UQ(Gd4i}Qv zvU)KpuQ;~_Qm>4+zYf~+kf&H)Ip+%;MkHs4<$UX66GfELv;`i9b39(jqYJ4nIdRH= zXp7v%MN^U$Qx`*;Y7}q%e=sz=k*i@I%^SDK>M%+u^K6E)%9j)!^Uh6sSXp1SZwG+% zco?<+sHwuONG=Af&&9SR;m^x?P4J9Rh$UMTcPRMCNUKUrJu-UrXNmV(@DgE*J0KTY z$8eq7luspID3a@4wrw{HlmX6z$_h%dE%APB%XFJcGOVly5X%+{u%}G^c<1#}8IJs? zZZD0V+t-SoO1w#wO`dR|zDSh@vL~v~eV)crJdpV^ok!K}>or2}2;YX@!g$aXLAx*< zpY@*h#y(JAVdjca;V~Wj{d2n*CqZ$I;sy6;U#uaXNR8D!LVQI=L9w`EWx~-WFsj*B zj_%+=awSZ(6NywJjI2#(+qW%}Z*P*<2hUJb;C-sb11GR84)9kLjC^|8PUjjYsBK*S zdGX8R_P6Z0Fogx-OlhbK7Jq=UZ`_xHezd*`QHhWEjpK)3uFs3-_Ds;BcXTsGnm} z58%r%g`7i0v|#hvll=?D*Mh+|!gmY)>pR#-q`H2@%CEM1S&?p8rqy)a>dM~|_JQt^ z;qA|;Q1RyKJ`L&&JW)$j&7V1(Ai0~Ru=xr^*RhYxs5N%P54HX7q`Km4YN2-HzM3NB z7U(O#G`*6c2UMQGAEb#;dFBOAYZAENSST(T6 zEuG-|mhRL%#r%pm7JgcDSw-K}uH-FlFG{btPK^(1SkQBEX1(*-@`vV0Z>KBz`gMJt z%`bq$s8i6o*js+KP(3tqjCR3%P^rM4!zrW(O}SC_2XB2=NVIP4TXwTl)XhhiO#3C&>=3cD%pB;Ae2!m1ROYz%sku7SZdyzJ*-_C1L1L%4gwF$0zkprW1{#McFQy_vizZwvd`wnFy9di{}6vN--@T+v*xymR5i}r^%dqO+8Nck)Ca1+v*$QBl~jnbIju%>Fa|r zYuxrwl^!ifqzuw2OhxC8$)mmxj!Y5n5Oi>L1OsC}QV5$3ls0Jo$) zEq#K%5gPru#X>kgny%vaN21g4!aj)+EPSK%1~tr-MU1-AGR9UR_OrG0zAHnNOr~Ta zIYIQ^9UZr}_oxq+mxPc^kHiXsyoteehd)_XFjj+hTcF%jI6L=$td%rd(4ODAr+8_r zqXeT))6MU#?D*1n?84W@d71=cx2bcrDbn4{u<6QSIC!(yW!e5MI8p0U6-Qnt) z8?mD7a>E#BeRE#ZckZXGr#Yxf{t%Ba{s*Ui{Kz`*q?z?Xao!@KbMf4}4*3Z#{2sHT zJS25EB6oF-W<{ZF1;sF;RDDuxHQm%W#$5B-HVoyF%b&|0SrWxH@(BRM+SRd=PcMMX^$LW_(=#j{07>t8FHB8x6p?*Bk+4+&!dms(;BG2zVa=@%-d zFfX=}@?tz9V+7BZlCAZRGH+L)cEHY;-~0RjDZX~zt%I0|pVU<}St3`5+JZ;^67yoT zfffumTmrBD67javuQK%-oIC_#Es(e=g4aY2G&G0p5ro>aKWUb(dd7$MvV*7n6}vQ~ zGYFL*nze@M(`vXo9%R(6aP!v~AnpRkUL(JBwF?Vv!PE!qUfXB{=|fJPGOj8TG)R76 z)U-+(9@z}d8o^$b0F0PgB(DgbjmmE!=sVIaNNgI@&%mDY>;IBn@^2Tl8)o;)f(E*H zVBRl_a~frjf!%jelbz0H`U2L+F=q>93YqMNF1HPZ+`i5457$d<)soM4y4^0bmnn(c zjiTCC?{2mmCI7WQwaeVK+WhU&G8&|mKgec}vR)ktde2Z)* z9rO(SeDdncJKXVu(xHC*KK(5ypY9p$=quQ1C77269?$1hzWn4hsAxK!gkJL(e}aBm z_1Zg|@ zd5Sx{L?nIm440J5qgVWwIH_?6vvHj&FTI#KSX*?~)7rZ4wh=Y5 zSJHEI4eBck^!-(7KN#pvZrWqiWIH(2jJH(K??2yUr|z@VIEwnmt=n{y4!TRsb@DWYm7>@|G}ck_CTFYLdWp#fKH!Psw_h72hW(d3dCQ#tWrypm1WT z8$SiIQaVzd=2c{an_`UJx>;f+ou|pU%6PmpN$y|Z_aRqDh3#b?0U4`59bXr`VZ@UW z#S|M4q9tCVC1U7qk6j8RmZp)4J8YPg1uP1tO`g}><>H8QThcbI{Whl zi)+wik@;W_oMcRPO;s;bYP8H6kJPq_}_7Exz^f zQ&U_LGyes)Ix>pSnmDgxUS?`9>{N#VV7&i=BO_hVG*x)$kfNzk)PW7sqEX+xBS4r2 z-VrSqN&D&72sWtD{gr`8eKozl0X4WWC?a8Rsz*u4;qdd8ymJ3UtEeDn=u+nW( zMUK-RnQE@o@_ zcuR<|tu<1LXeY@cakt_o991sh?$-^YFBffd7xjjRou(OsmPxTJztsj*bdoTZ_{+@| z>T_(?G>RmDS=R>87ZsP=M3jol_V-mic3uxMpq5>b5kMG z!9A`allYcF7muadO#Mu$|B{UQ`WU-ImkX(fqSW)iqSoTUL$INxX4+#FRB!cHN+ryy zs!(EQ9?#bg#6+@)sN1ET&`_SN{P?GBgaEUpLMV+o%MnnApPYOLZwG??19w}pw$GNf zAz(1AoFu&i4Fsw?Gcj{AaeI2$TY02C9sd5O50>0P1w727y$6%P!+r|bEt)v$8ErhJ zdjG);2i}(?9VuN(o$x3Vu=H{0WU`=AWsNW^U90@xPXM*V5^H8Qh7S9thWa_(kkJnc znFb|aVaP=;tgdbSSwxeLt-QSiHPWL%<#Acui230HSafTvS4=@B5GiWS)_a=`K4ytB zrLYVV)JI?eSo8$6RLs6gklCcr&lio%bEf=3vvJink+M~M^vkO4y?ONePw7%A@?M)Ux7=>~QQzFHH~`YZwjGk0}$zlMMmBjeQXL_~&tdr;GAVv5^WU=GJ$B4%C!k;Qq{bIc|xEqVgtzQZxtgD45TtcbX) z{wKDyG%A`DMPuW$^j9kV=w3O?{02Z+@C^Om7~T01vp1!wVoDxmR)@~cOoSQwhzdFj zsQswGI5_=ErZSU~e8_L=xm4C@_7GHvK8X1M9z%QUp+TC#*UabQV1) zth8Ku1)9c4tq?E+S1W=APj7rOLEQy?bpt(>1vYE& zKXhyJk3bcjnR1YGdJkN!;Gj~zXJ(v#5!2MEfFSMDF&gk|!m#vHiX}--1ePc9g3i-t zrXCaDI94Y-YICXv*w+JPf1YRX_-TSw)U(DUyZ1o;4u0^a_|I`BN0Fo+p$fk4->Se@uiu-Bnz^UWT5$Dm;2t~)^ zPk1{jU?uZ8*SzYM74qFCLh+TyHQSPtD#7~1)?)Zc&DIK|8sFi)*CEH=?{pHqe5=?1 zt7huB_qegGQagRs1>}^Nj)Bo^b|H|MacghJ_rV@9$~w_!vtI20)1%;gxD&iI&`xGZ z^KM-iM|g#mFMLEUrJcYxvj|k~8bzE|`!F=f+@_h2|K|{yQ^);RY{;tZ7>jAh*ys9< zKkQvZV`$mnXQtz7)5A~;f-NNwAO^GROf%RH5gqWft=hQED|>kpQ>Hnc4GQS=LV09& zs_5>^emjp{>XMasu}Im{$`5T6kjq+?2dqdeKptbC7ZHvADq{2u!Dj35nVUTK#Nw`fSfd(22>jRHPKUtkQg6Lni6~8n^(cMu=Ew!SvWT}YPE7`P29FFX1xm^>4NnJ zHStw0Dy65Kmq@F7nhohGeS+iRF5|@6%^tJPBwEdmR`BK4=Jz7gL>uzSZ7KOTRaGZ= zc{Wpz;2QfDUPgtnt9l2rwuo54y9Z@G%N7=|3+rQx2tusG3c)$EEkDue)>gRwK6@uf z6^Q4Yx2$QR`ZZgEZN_^(KKB_xSB$bgL~YJ^yaaR*G}D?Cc!A~E?fRj&yGmt4CDp2j zLcSBd7`TFaU+{o@@62_)LARLXT66;bV2HWY-7)lM%8x-DqH2kUbf<)+px1RM*y^FxmhR*b`n#*0FTky@q3h0<3&mDNHdFWLz0hVTPT@%oB#!|J8BI+ndU?3EK|2&h3lgf zV1|7vEgzWYvm#YJAPS>X>S z=zq5a#@iFz;B+ZCwYujfp#OE)JYVRJxC%-3((yxYLb>Cg>IaV53T`3yAkz!4bqlv= zo|7ezu94j1VH#cpw)P8fF%s$kI|qjh|I_ZadTAG30o&)b#-U*C^}}!#_1$_9SY`}+ zqH%#U*p`arL##|(hS_6CU>dalPh{4%d>LO$aC!6}X$%n4;5Xfw!Kp{@anZ)FdqJKdIg9IOgj{_z#(hX@^t&AaR_+_O*DoCh z=-dLk^~rt#Z-He2W&v?dA5mfTYvbHRc*m1T&ZUu>1b8QO_uo_oS3Uo{MZRzUE=J*u zY9aapn?=3VVE51&?yz_(1%RAO)ej582MG0Tn$x9)`XPRJsnBdCfHs2aD%0}2lKegfi}F&pH?pFC$T-SGRPaK$K75OI&D!P3w|`j|9D)m=W~YjPQXkQkxb5? zEp~#DUJf+t1Dify5jI)oT!BvbbDuX{u%FvYmUTA#vZKpI3tt;w`qlqvy17|r21Zb` zIM+qt!GSSSx*yic+1Fp~uCJahE**Jail23P?#fiztay2Z|9-f6M*b<3iV^+n+;{8G zM7Oc}C&^XHIze>v5y@Hpl|1Qw;#KkCuJ_j6-q60!m@Cj7T4!AKO7?*y$x%3@QvrjE zI`1y{?w|3PVRbDQ?=;lM&Ce$ILND?>Ovi#2DxG1W-rE%pR~4- z!BOkS&WAmw?>cMYr)-q4-~AsdJadQ^aH`>JAbXUgXP@T)l}T@{e|$eB~Wrn{E;1)t=^U#ALSd5U!e-jCUCJlQ3!Q9c_YeVn+? zX7N}%%_n>WM&2ebt6w7O1O$l{DuwhUIC<^ND&KPk>hw%=PrHU@zYx^)bGa96jyBa&(0yA=o&vZ-0X(xWBCjRF z(#W4^n)Tb-+d4at(%bA}rc%`D$BuHo9&zC(GETGm9Cx1X1S&r}%dTI9CnfA<@EQ-8;0jU70#+6^z%wXcQw40x}5V{8a2vjQ%4V8kr< z{nXup|AI642;A<6GS5?RSXM9O;T7{%BQR7kl>4_;+_6kez;XMoXgQ{zWXp#{DO5}o z`Vy3gjZs(}ClncaD7Cn66><&%!1KCcwSxT?YkSOkL2Ly>3ZpN@Ubm^KWu1TR(a!_R z@#c8<$?`LaP#K2|**c0d8lNGb=%ms)?a1D+3o-qhjG%zmKV&Gxb0J$RFj@`eic|by zyX*LCvqCa@q$dLGPR^;{&65vE;7f0!Dt{;e;h9+`39%=aOtBY2CHAj)|M&C>92k3@ z&yA124=w-qj^-O$U{>Sbs(^de4*(QNk@lQw+&K36*%85qwD*CLh*JF1(i44z1bm_R zqJ7VB3RY$RR9`ViKex>>79RM-Am$fD+-qSZ!g%XlKn3(haO@+A zcn1XJj@6EJVP)*EBEVku6qa9gVficM($-I1 zxLYus&bYlTkgVIPzUJ{l3UD<@koQqi-~D<2cV>XKK)UH1klw}WU;_8W*}ac=x^ZuP zr+oN%GmFlOUQz?L6Bgz_#)w zb$?g-bMhsqb*4JL!E@B0kKZrQiS#N{5qeU;IGQ0&lo0knB(|+{b3^Uw@I2_+CglH( z!r5EGGnZ}R6XVdg;k0hDEyw>zMKe{p4H(!C>|?>G;6HTn%cZKABOE%hEWBQFR8+NQ2U^#U1k3wvplpdI>x%7EQ;p=p!kF^%LxTq27&3cv z63lGl*$8`dasNKT6Bkh2??FF0VLoWt(VP}GkbhOui;`j3%{|+-4i9vj%r`9G>nZ;R ze}*V$JgNElph&PxB=ox@x9VEVa3?=ledBSKHwAG%T0nLP|Cmedr29aSM4WilaoK!! zEfuM`*m~~fnMUfnQdH1w(AcA{u_mI#9H7q)^iI21a?e$(ZdUO1KKM;aYFWEZT*y~2WXp*X)9n#cn$L>0fusQa)z;S}^ml>An!!`wA z3E#iyamz_X!4*MSyIe3hLGZB?H*d4ZtxQS{#O?;%zlH;lD8mYK2~Irq(?M-x_sPLX z1n0R!&;=g0{xCh?9cT^DRADDLu+G+lSMKd3TYiokS9cf7ptSe=xC4J4#_w7;{fK7= z1NlDWo;@YM?v;Pu$UPzZLBMk$N$SktMQ3dA&kQzwNZ3GoqMj-PfQn_&Cz10m!{c%r z4^ZnqU}uGJW(c3kZ*CYM}bi z>BZ7L+ARp~Cfu;E2p&D>zcKUrk5F53)tpG}E3X3N-VZaj{lx1>+OmXFe{8G&NFW`I zR7?ccExaL2)FPU3kU4i0;KmE)ExdIgS0elH<7NkZgZ6R;dER|ak^+ck(9%TH)Jia0 zWBb?_wzI_iB0pDw7!p!Wf15lo-%I6QVK^`Lsebtg810MSd9*3OEyj5`ho9t_r;Y?N4C*u9 zdKQdNU!bPg&6wrZKUfRMJ8UaHO7ePsk6Rm(9Lr+fAvr9A!2E!t_mho~B*x=1 zw9242j2d01Umz^iZP_dSO4s0CKr2k)ruX1=-ZJx-{f@2pws0<}uA5(mY z(bFWW_MMDQ%S}xPW$@U2lAuhm-o$g*p0FnQ+Mb|=<~%252qQJ-fNkgD+x$)e2rw9;jZI(JhQrOR(bPcG)kMA2L!JZCVHIrXb@P)p&HDUiB1Wp7-X z(fz-F_lP!)hecK%jyc8wft54rL0>zdRVcgTL4uAi@_XS3z$~!b%U0sxFzp- z-c1B9yp(#!I?{hH@|r1)=}|*};#kBu&yITU0RusMb@ttgfXmChyQ*iA4R|*Ri_}~4 z!Td43Gfc`X_sX3`sH66jK|r|CjXeUcj|OJg_AD>;jdbp1J8a5{(zuRm+F#wz<73}* zrkyhGb>~I>?nu_wm5NsE0>+PQnk(a&3FWK_K<0e2Mb@VAj@CdP-Xx$_MDKBf_T^9L zXIs?HX*-)f7^mTuA|>FJ*@7-=UN4BB7tB>K!cSLTw>9#{UgfK-iREyYD1+&~GS)3& z9T%SZUU)iIydj^{u;xvPpcmR^17rc`A+usnR3vvG=F3db#7t(_F9z%;n^illR9FyCQ z=6gVTAO@p8T>W4DJ*A$m4s6qq`)C1|0be}$>kWsTB>~t?(4NwjTcBeF%v->i*wWQB zII+8};7BE>GrpZUNx7~C>g8V9^^3LsZ>CfnOAlgFMU@epm1ZL7cC`Vyi#L9%~ zO6EX;>;=%wc;jH`fyXH8+>SJHJBTf@dZN&e#ab|0-RFQZ>J2}-+|P~gMYCY>b^JPH z^h^}D$(`XJ*5s$<1+ufxv->_@Zj8D-E44}s( z`*xAsX^9*~T+?~qJEGfuA^QWo+ao(-#u$4NFxuDIukq^m+5AoJw9il#r^|r)DWP`B z^HKA$J5Bw=Tk|sVE@x+P`O!>8^nfOcQ$xsn+bH*ezNwFyxRKsfJ^Hiy#Lvp2t-u1P znDDGJINO)&?m8z8xmtI?g?Frc8Q3K{hNDvGmUI_e_mM4o5ptiM?s3|q>YM5%i1yoC z_cHzUAI`+&-MtmQ#{4{GE~Y|YIj&0)UEEaZ=dqSv?C1QCB%@?6Nj-ybvK_cf$b$62 zK?I`p*+RP)LUEwi1uQ`eMXi$k*Rpb;5B570SdXregdr*b{g<@(sX-Z<_G=(Cz>ybcQ&q3H?Lo%kNV!l6dO!Wc7Tx;{5isYvnCv3kw@M3 zB`$c!>wTeii}mIV-pc81fTFc1MS|SxOO$}XTMd7C1l`bn(4c6G{H=5Pd5lT%CCp-G z|H7*b{{GlDz5?awn^@1q5VmRkABXjShfBX0BG-p@{$M8WQe5gLIJLvYV&u{G*D4d3m4;u4KbqL>;Ff*?Og#-**)h`|>RE z^r=97`1KQxr;*D=8`Ny!my!Jrd)CUih~S+qv9EnT?k-MUkCkuh0sQc@mOAu^m^xK( zS0sM5yQ=AR^grxQ_UiHq1~q%48u8i6FPHyGz9>@(!eL%@+j|CFf9{Iln_LD>|AFOR z4BnZ)`GamCs21dBg1I31@yE8_`5L`7?k#dF;knonvtWXtvN?TN6DV;5Iqn_77rkWP z-I*gVl=w;;%T)%JJ|8|gx^0lV%z0zKWf?IGfCLt8a5HrWS|%jN5`O=8(}B*aw4gXA zQ_RgDB;YfQ;XTTr*WeBOgZRaDu??{$;dm|B+&y1cvm(=0+WM&3tDe@|L@BFI$W5+I zTe6UW&B!hHIN24^KaR(RZlnin7!%kWoPM$31ms1igJf+=KDUKJ-nI&qe z&U(oavZJ)63={Omb9N&7{Jit^ciw&a=X;+g@OqkS$7koVZaePDXRl|U(*@U$HmhQ+~6OIozFp6!z^(k^Q-baPJWsQ;@yHJ@T^(Ae-;qY2Li& zkO%;)lvP>u{&THetm54|H>%EfN(uYeoa=#$WL=jw2O4j>NPH9ZuUW%b^QF;ExQPqa zy{+mHQ()V>0jh4aS+c!)^iBp{*N{}Gbr05gJ6gXh?w*&w$Tj5KijV|P=EI_%F87;2 zN;dKv8-)(ylkDD~EnXxoS2XU5YN_rM*Qoyrb`d38~5%cj2mFD)sdK`5N%b3vyqPxkl#y712$ z!lgu44?_m@1h>M?{Bf?+2Q65U6*OP)4&u>W?0sivIRD=MzW{g(uOP6yU>86zH^8Ax z^gPKOrErtAKY6&^+@l3MKcFq@V?T3**C4nLX+>e%mD2n_edupOuy-8jN0R;(mKL%f zmyysg80e2k+N7J1x1eI^4{c2X65mAqJEX6Cfs18+n2VQ(Q1h)*)=%8ayr^n_$;IFvopR;F)+lFr;XgYUXv!d}I^7feWfX z^n@PgC0(d*8RA?C7JOC16f+_(QAhfNNSDOQ&>oEF_Lt6c>n>oazr&S0d=~ZIA4U5vG~lJyCDrj z3XN|0|FFi8D(0jcjBa|u2p2T63z<&|Tsh@t6a_HI1p86h0s}w1`(b}}*u7Pw zxjR~%yV{|E$!|@gEV%0voZ;D`*hCP%lz5}TXt|tSmw-fTm+M10jSI{{1w1)%Gv61^ z5N(7{fIFb?EYpk8clOpZ>dCnQ1rcoyR+77E*=FeTb=idXtMpx*A9!+mU>`Y1>7Tjb zs#Ml@gG|J)zuEtV@~MX_QFL&r%de)DqwpxO+BM~bd@0iSKMIXA zg^z?!erGT>GCXvJ6GFzU`|iyg?vehO%+P*KdE0##XZV=GaImmXB5(Zb^nZ-oMao%@ zY%=iRyLO`(la};P27G8{DPw&C#83=xg{E)#SEits`qCx6@l0EIi<|NWy!E}OxF87X zLqfdfRrCr^xDwQ2$AWS&bFh=~_dN@Ycm5XS1`G$Z{y_VCev4giY8VSDnoE^S6^GpS zf<7z@qz3o~jQ)Xf0r)clc+=U$a<(RU8!e?ZX!vvo<2QCYvdx zvs0-otru@{6Uo#rjFoGsVt9@0)INf*4T=`R2Ml}E7j87SBp!kYHmB&U9efLVRo3WI z!+@}Quga}q<(QlmZY`{_C2c&~}VNc)dBaMufzL1PyQkg1fH*T}a+3yUfSH@k509 zAt=iO$agVAfM6@a(+Ed3O0x)+>Qeupoe(lkJYc;6Uq*FbMzf(jB_G^LkQG5Xh$Y&) zj6g7cNs)k1G&a#`Bo?+5o)I4y4Qhx-a2_yvd0xnXS4b~1CcSA8^r__+xAw6}p2Rt8 zzUAMlTPr^8*k|#($tZ{V=tgx%<0>J4-m<$EA7=YUwN z<2NTfZo&qt)d3-UY&;CPDm+m61DTAwQdTK@i57O2pq_=FTj6V5=rJuE^N&R&yl0j3 zm6)01p_$_+GiTRkJZ)!kK~}b-lymqI5+yI_Qsvrd`>$d9ujZW(D!}W8-#=~3Co_N1 zd8mn*%`^ocegsviD`CFDEM*2bb&S>2sm#fheOrv{CFxB4`1_n3)8A!v-AFtPg2$oY}J;6_2lEisex4&ue-w|6eDWk<;E%DIujQD2gZXw6YowC>4g4s zHj+J{POdW!Z6B!q5T43)1Ta%bAdvJQSl%qYBLMb)GK8O!+yrf^+%d%^?oCcGN#1L6 z(|+@LhCfs<{Nq*lFn|vDd$O4@E`z8w zp^}xz;ezybp(KPvwEW&;%Fw;5k$SKUyyBGN!opPz^uob?{@c37Zv|fQg)zr%`Nc=y zWZMJEs}b8{pH}R5dLZUy)3YimbY@JC}p2mmH++U<9z;M zCfl3PM$)X#`2-cebC(1LJ0CytUfbWP^cQtkVq=&L`C5jt48OrHp7_1&jKJk;DW1N{ z(hDONOoO+=e}OO(QL%+!G+_`PG1z~^q62$iwEv($LxhS5jv`8tB@~k^h!7yyh87@N zR0lIt!}Li+v|$7753MjuONAeW+9n0gXZv%l=*o zYz~&$bLvVEc~^G8xq>|aPKhCy3gJeX;(||Bd<*(t9Dk4?95gP~*Xu5HF|Mu?*yzHZ z67_mdam=5NFA3}vw$>*j?NAe3_j=86gw*SCy?Ht4PMxkBM1$teIllk%MxM|kvf&O{ zZehIQYmxY~lJuvx)(*MO?hN1CXk)VtaA7?*(syk4P8DlQ5j#Wa%m4RDv1vo<38SQ* zb6$hs>;nD@eqCcj&Dr6P=UOK=!PV_Qger22<@W8R+h%)eH zs@g3fKfqmV1~yS;TW9-I>o5|_M2mDydpfC)a|*;0_l(mlCe;RgLW(6_t8dr&BFN6p z&L=j0JVQITH-j!u7&daDKhMbnnoP|t&ipHPQL(%+A3EV9G@xKBq1YgK7Wr^_zzNMo zlTDue)6d|e`0zH&rHSa zkD0ld;<15*hE!WVQV*el7eqG11_UppHv}xCS5jlueMQ- zuaD%@8#5;gQ3uyTJyC$+aDNm`KAGJd5)sVSPd9?@WK&blQL{C-w(zAuywrp2r2ZDq zx3WXV1HFR^$4!sP3WBBh3&k_wDe%lyz*ndKjQ64U&F?e9FWs+xyFnHZZSEEOIr@Ww z4&QgQLz&GD*OfK?$L0oFK+NCc8AkcTM~0@x5^=Lk>^0Jsag&#>#hLTX*<&zm$R`$< zKYiG#5J3U|8NdsL`$0UU2XKM;!#JF(7d(R#L&hXxwx!kDruJ=$j26gJW~mxs7~iTI znGwI7KSKAJmrp}!+Vi8ICl@ok0ugInu8TCgHBFvxU?qS5wYegMDv$zK4bE#zdfXf> zx;hcuepp{5iPkSCb6STi4@jRkT|gf)0t{Fj(+x*UKk?^Z4rfOFP$H4|Ef-sP`^E^E zu~!K&;0hPGZ#>Ai-WXPHi!t zhOX38DB?uwwn$U*&yz`-1!7EDf@yUM_PjR6mRSrOkBv{=WvuYj?+1-;j6tN5tcgTf+^CZR2I*eN?)5Pk*z29TBL&=9DCoM=oP{{|#f|rus20V89y7w`k=GWp$YK4*+>X zta>ELTyM@Mrai{6r^%c|Bs6g9fFes8t=6V;H`ehbf$wR!7z`FUFu&=%CT zD1Gj>wS1xqABmw!_)WgWXy?l~WWEa!h=c7C+-ZU7?$!~!(dH)(RvY#76JdLtXd0Nj zn`K>AN;3auUOr)llbZagW*#)%X9Z~_8~k7>SkJ`d{A=p75-*kw-w~Y`ArY@KjFw`^ z&;Jfs4bfber`=XV&Q0*m8KE!l&Xnl`nshmQYX|P1=v&q&8TS-vmcICIRw>*bxx-6om{rvvD^7TgIfd8dLj zdNJ5$#JJS9GB$HPeswZEnA|N*YESE>47PGj<|0eakU;<5 zvz4+KfI~|!FQi;7x~%v>_M?2zzGDbI5z%C!5^K`|Rngz`h{Q>G_Avg%*IsRaa96LX z@d{{+l(Nwd(+Km*e#@4~dg6pny`2<;H4^V*J&aWy{>4A!mAn0Pm|M72xbvTf~-k+^<}eGDeXS8x7p>i6l!IWzO)1#6}xu z$jG>vT**##n6qfF&5mILceZQO99m$^axzjQhv`a3FJW*%&You6e`y)E$Pq&VD9)ZA zi1Lx=va*?`%E?PI6>CWBU>E(gtWz}t=&b@-c3v>w5IHkTnh?n4dX9Q(Y|&Ig*FU>q z7q7va2o{@LL7mjur@u$!!la&ep|EC!$!{^B#EyRo?V*(#%Nh@=wh9P5OVn~Nqs2(+ zO>1<~>cr@gpwPr5AxV}vppU)0{fFW;B;5wSLbXP#;fg-y>MC900U>=T-%$CVhk=pA zOhx)7Bu9HcsypiLz<@COFQHbx39+q;ja1P<)jUD(5+*d}UyFR-j&(rg+>;$xb(H8M zhx}j`vHK5`I-pYei6EH7G8%JJNWl+?rijxw$6rK8re3~t`7%H8%}Z>M)%FaSj}(6q z{io~rD+#_SZEyh0p284LL=)KD>3v*F%>B81DCLy7|DejCz=}wsf8SrsrRb-2CcWdm zgC!`?*JkXoJKj9y-{b679?gB3+kF1yI+jMm78Go=v+|)Vj_|olcL6Xydc9o1@izq= zEXdc5*;xSGY086R-S!?puIj5?A|BYf_RdJ#xN$5joIeE(d{^Hy9$DU%FHkQf1`xRd z+MDzl00WMw-suM$myoHjs~9x{!`i<_+48T9Tv>!$LUpL)T_tgGM#q%%Y=o&>}Kvtu#M3za0VR5CcV$g|A z7DOn|l1(1AcY`SUFCziK5v0>_zU7&J*>=3XuPz7I9&*1)re#8DW$o^gIvz>1%V4ku z{s`SLED|WN!{-U8L`Y;Fs|V7E13~ohu|n{*KqEKIP={LwlRJc{w)`P^w#~_)W;}W8 zIeZ_7F*M(+$weRIP1~Hu%c3gooRmJUo+~@??=H73@52%Ahe^P&IrPS#XxRCleqL#| zPIEnNMzcv=k;&quce-8G60v&@dAX{r>lmkqYL8MFONqHoeP25JToma5drrY#`)N7I z`GTS4rr(h}4`}5+adDFgy(`O6t_Yqjl8*2tn`*6bzb=_U#BG<~Qj1ykzXdPYg zs)B157;CRF!ioA!^r_^zcoiA3j055KoPCA^5*rdY{bQn66hr(M!;;A!+@cTwX-v*2 z1~KXRGWd4QO3JI;(Lu_m2R~(p`Yfue;Mfq@2514r1ddK^68DORg2p~aSc)}3rEzht z*rm;kzBn!(6JAw|g>yErT0j7C^uCDM-m5gMAbfyBtF@NhKR%7R{B*(~iwvBRBk4Gg z3Zvr3^=f5QTOP*7hpD0Zl0)lBzyRM5ZaZbG6re3fh5Dg1QLK$X$hd>kPQuf{UjMcL zw{N#}QVByH<#4oIes4%nFFhjJja7-29bRb%PN*m0F=7n*Z=eA{p#h(hS@HRKtuz`chza_@{7>j_u9YTybS+T7Z6WPs zB0Dh!sx$>^7;PwM5+nft9-@=vuf*%n&k`${tWyuE84ET#67%Jx)}bb6t7I{uGez8O z+Ub4o>S?CRkTQzbdYLoXH@@t&;t%0D+iXU$)GeE)-rc98mx5fh?SizS0wL2izkq_@ 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 Qpa?Au7nh +#include + + +/* 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 TX_MEMSET macro to remove library reference. */ + +#define TX_MEMSET(a,b,c) { \ + UCHAR *ptr; \ + UCHAR value; \ + UINT i, size; \ + ptr = (UCHAR *) ((VOID *) a); \ + value = (UCHAR) b; \ + size = (UINT) c; \ + for (i = 0; i < size; i++) \ + { \ + *ptr++ = value; \ + } \ + } + + + +/* 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 Cortex-M0 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_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE *((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 + + +/* 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 +#define TX_THREAD_EXTENSION_2 +#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. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#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 +#ifndef TX_MISRA_ENABLE + +__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()) +#else +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif +#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); +#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 GNU specific macros, with in-line assembly for performance. */ + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + __asm__ volatile (" CPSID i" : : : "memory" ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value) +{ + + __asm__ volatile (" MSR PRIMASK,%0": : "r" (primask_value): "memory" ); +} + +__attribute__( ( always_inline ) ) static inline unsigned int __get_primask_value(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + + __asm__ volatile (" CPSIE i": : : "memory" ); +} + + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + *((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_primask_value(); + __enable_interrupts(); + __restore_interrupts(interrupt_save); + } +} + + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupts(interrupt_save); + + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); +#endif + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M0/GNU Version 6.0 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + + + diff --git a/ports/cortex_m0/gnu/src/tx_initialize_low_level_sample.S b/ports/cortex_m0/gnu/src/tx_initialize_low_level_sample.S new file mode 100755 index 00000000..9698d64c --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_initialize_low_level_sample.S @@ -0,0 +1,185 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Initialize */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_initialize.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory + .global __RAM_segment_used_end__ + .global _tx_thread_context_save + .global _tx_thread_context_restore + .global _tx_timer_interrupt + .global _vectors +@ +@ +SYSTEM_CLOCK = 8000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_initialize_low_level Cortex-M0/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for any low-level processor */ +@/* initialization, including setting up interrupt vectors, setting */ +@/* up a periodic timer interrupt source, saving the system stack */ +@/* pointer for use in ISR processing later, and finding the first */ +@/* available RAM memory address for tx_application_define. */ +@/* */ +@/* INPUT */ +@/* */ +@/* None */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* None */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* _tx_initialize_kernel_enter ThreadX entry function */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_initialize_low_level(VOID) +@{ + .global _tx_initialize_low_level + .thumb_func +_tx_initialize_low_level: +@ +@ /* Disable interrupts during ThreadX initialization. */ +@ + CPSID i +@ +@ /* Set base of available memory to end of non-initialised RAM area. */ +@ + LDR r0, =_tx_initialize_unused_memory @ Build address of unused memory pointer + LDR r1, =__RAM_segment_used_end__ @ Build first free address + ADDS r1, r1, #4 @ + STR r1, [r0] @ Setup first unused memory pointer +@ +@ /* Enable the cycle count register. */ +@ + LDR r0, =0xE0001000 @ Build address of DWT register + LDR r1, [r0] @ Pickup the current value + MOVS r2, #1 + ORRS r1, r1, r2 @ Set the CYCCNTENA bit + STR r1, [r0] @ Enable the cycle count register +@ +@ /* Setup Vector Table Offset Register. */ +@ + LDR r0, =0xE000E000 @ Build address of NVIC registers + LDR r2, =0xD08 @ Offset to vector base register + ADD r0, r0, r2 @ Build vector base register + LDR r1, =_vectors @ Pickup address of vector table + STR r1, [r0] @ Set vector table address +@ +@ /* Set system stack pointer from vector value. */ +@ + LDR r0, =_tx_thread_system_stack_ptr @ Build address of system stack pointer + LDR r1, =_vectors @ Pickup address of vector table + LDR r1, [r1] @ Pickup reset stack pointer + STR r1, [r0] @ Save system stack pointer +@ +@ /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference. */ +@ + LDR r0, =0xE000E000 @ Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] @ Setup SysTick Reload Value + LDR r1, =0x7 @ Build SysTick Control Enable Value + STR r1, [r0, #0x10] @ Setup SysTick Control +@ +@ /* Configure handler priorities. */ +@ + LDR r1, =0x00000000 @ Rsrv, UsgF, BusF, MemM + LDR r0, =0xE000E000 @ Build address of NVIC registers + LDR r2, =0xD18 @ + ADD r0, r0, r2 @ + STR r1, [r0] @ Setup System Handlers 4-7 Priority Registers + LDR r1, =0xFF000000 @ SVCl, Rsrv, Rsrv, Rsrv + LDR r0, =0xE000E000 @ Build address of NVIC registers + LDR r2, =0xD1C @ + ADD r0, r0, r2 @ + STR r1, [r0] @ Setup System Handlers 8-11 Priority Registers + @ Note: SVC must be lowest priority, which is 0xFF + LDR r1, =0x40FF0000 @ SysT, PnSV, Rsrv, DbgM + LDR r0, =0xE000E000 @ Build address of NVIC registers + LDR r2, =0xD20 @ + ADD r0, r0, r2 @ + STR r1, [r0] @ Setup System Handlers 12-15 Priority Registers + @ Note: PnSV must be lowest priority, which is 0xFF + +@ +@ /* Return to caller. */ +@ + BX lr +@} +@ +@ /* System Tick timer interrupt handler */ + .global __tx_SysTickHandler + .global SysTick_Handler + .thumb_func +__tx_SysTickHandler: + .thumb_func +SysTick_Handler: +@ VOID SysTick_Handler (VOID) +@ { +@ + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter @ Call the ISR enter function +#endif + BL _tx_timer_interrupt +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit @ Call the ISR exit function +#endif + POP {r0, r1} + MOV lr, r1 + BX lr +@ } diff --git a/ports/cortex_m0/gnu/src/tx_thread_context_restore.S b/ports/cortex_m0/gnu/src/tx_thread_context_restore.S new file mode 100755 index 00000000..5581cdaf --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,96 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_thread_system_stack_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_schedule + .global _tx_thread_preempt_disable + .global _tx_execution_isr_exit +@ +@ + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_restore Cortex-M0/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_restore(VOID) +@{ + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: +@ +@ /* Not needed for this port - just return! */ + BX lr +@} + diff --git a/ports/cortex_m0/gnu/src/tx_thread_context_save.S b/ports/cortex_m0/gnu/src/tx_thread_context_save.S new file mode 100755 index 00000000..1d48d8fd --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_context_save.S @@ -0,0 +1,90 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_execution_isr_enter +@ +@ + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_save Cortex-M0/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_save(VOID) +@{ + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: +@ +@ /* Not needed for this port - just return! */ + BX lr +@} + diff --git a/ports/cortex_m0/gnu/src/tx_thread_interrupt_control.S b/ports/cortex_m0/gnu/src/tx_thread_interrupt_control.S new file mode 100755 index 00000000..f609c227 --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,94 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ + + +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ + +@/* #define TX_SOURCE_CODE */ + + +@/* Include necessary system files. */ + +@/* #include "tx_api.h" + #include "tx_thread.h" */ + + + .text 32 + .align 4 + .syntax unified + +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_interrupt_control Cortex-M0/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* UINT _tx_thread_interrupt_control(UINT new_posture) +{ */ + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: + +@/* Pickup current interrupt lockout posture. */ + + MRS r1, PRIMASK @ Pickup current interrupt lockout + + +@/* Apply the new interrupt posture. */ + + MSR PRIMASK, r0 @ Apply the new interrupt lockout + MOV r0, r1 @ Transfer old to return register + BX lr @ Return to caller + +@/* } */ + + + diff --git a/ports/cortex_m0/gnu/src/tx_thread_interrupt_disable.S b/ports/cortex_m0/gnu/src/tx_thread_interrupt_disable.S new file mode 100755 index 00000000..7cea30dc --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_interrupt_disable.S @@ -0,0 +1,88 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ + + +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ + +@/* #define TX_SOURCE_CODE */ + + +@/* Include necessary system files. */ + +@/* #include "tx_api.h" + #include "tx_thread.h" */ + + + .text 32 + .align 4 + .syntax unified + +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_interrupt_disable Cortex-M0/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for disabling interrupts. */ +@/* */ +@/* INPUT */ +@/* */ +@/* None */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* old_posture Old interrupt lockout posture */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* Application Code */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* UINT _tx_thread_interrupt_disable(VOID) +{ */ + .global _tx_thread_interrupt_disable + .thumb_func +_tx_thread_interrupt_disable: + +@/* Pickup current interrupt lockout posture. */ + + MRS r0, PRIMASK + CPSID i + BX lr + +@/* } */ + + + diff --git a/ports/cortex_m0/gnu/src/tx_thread_interrupt_restore.S b/ports/cortex_m0/gnu/src/tx_thread_interrupt_restore.S new file mode 100755 index 00000000..70d6b2eb --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_interrupt_restore.S @@ -0,0 +1,86 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ + + +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ + +@/* #define TX_SOURCE_CODE */ + + +@/* Include necessary system files. */ + +@/* #include "tx_api.h" + #include "tx_thread.h" */ + + + .text 32 + .align 4 + .syntax unified + +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_interrupt_restore Cortex-M0/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for restoring the interrupt lockout */ +@/* posture of the system. */ +@/* */ +@/* INPUT */ +@/* */ +@/* old_posture Old interrupt lockout posture */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* None */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* Application Code */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* VOID _tx_thread_interrupt_restore(UINT old_posture) +{ */ + .global _tx_thread_interrupt_restore + .thumb_func +_tx_thread_interrupt_restore: + + MSR PRIMASK, r0 + BX lr + +@/* } */ + + + diff --git a/ports/cortex_m0/gnu/src/tx_thread_schedule.S b/ports/cortex_m0/gnu/src/tx_thread_schedule.S new file mode 100755 index 00000000..61f3b113 --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_schedule.S @@ -0,0 +1,278 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_system_stack_ptr + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_schedule Cortex-M0/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_schedule(VOID) +@{ + .global _tx_thread_schedule + .thumb_func +_tx_thread_schedule: +@ +@ /* This function should only ever be called on Cortex-M0 +@ 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. */ +@ + MOVS 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. */ +@ + LDR r0, =#0x10000000 @ Load PENDSVSET bit + LDR r1, =#0xE000ED04 @ Load NVIC base + STR r0, [r1] @ 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 switch-out switch-in handler... Note that this handler is +@ common for both PendSV and SVCall. */ +@ + .global PendSV_Handler +.thumb_func +.thumb_func +PendSV_Handler: + .global __tx_PendSVHandler + .global __tx_SVCallHandler + .thumb_func +__tx_PendSVHandler: + .thumb_func +__tx_SVCallHandler: +@ +@ /* Get current thread value and new thread pointer. */ +@ + .thumb_func +__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, r1} @ Recover LR + MOV lr, r1 @ + 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 + MOVS r3, #0 @ Build NULL value + LDR r1, [r0] @ Pickup current thread pointer +@ +@ /* Determine if there is a current thread to finish preserving. */ +@ + CMP r1,#0 @ If NULL, skip preservation + BEQ __tx_ts_new @ +@ +@ /* Recover PSP and preserve current thread context. */ +@ + STR r3, [r0] @ Set _tx_thread_current_ptr to NULL + MRS r3, PSP @ Pickup PSP pointer (thread's stack pointer) + SUBS r3, r3, #16 @ Allocate stack space + STM r3!, {r4-r7} @ Save its remaining registers (M3 Instruction: STMDB r12!, {r4-r11}) + MOV r4,r8 @ + MOV r5,r9 @ + MOV r6,r10 @ + MOV r7,r11 @ + SUBS r3, r3, #32 @ Allocate stack space + STM r3!,{r4-r7} @ + SUBS r3, r3, #20 @ Allocate stack space + MOV r5, lr @ Move LR into R4 + STR r5, [r3] @ Save LR + STR r3, [r1, #8] @ Save its stack pointer +@ +@ /* Determine if time-slice is active. If it isn't, skip time handling processing. */ +@ + LDR r4, =_tx_timer_time_slice @ Build address of time-slice variable + LDR r5, [r4] @ Pickup current time-slice + CMP r5, #0 @ If not active, skip processing + BEQ __tx_ts_new @ +@ +@ /* 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. */ +@ + MOVS r5, #0 @ Build clear value + STR r5, [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? + CMP r1, #0 @ + BEQ __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 + ADDS 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 r3, [r1, #8] @ Pickup thread's stack pointer + LDR r5, [r3] @ Recover saved LR + ADDS r3, r3, #4 @ Position past LR + MOV lr, r5 @ Restore LR + LDM r3!,{r4-r7} @ Recover thread's registers (r4-r11) + MOV r11,r7 @ + MOV r10,r6 @ + MOV r9,r5 @ + MOV r8,r4 @ + LDM r3!,{r4-r7} @ + MSR PSP, r3 @ 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 + CMP r1, #0 @ If non-NULL, a new thread is ready! + BNE __tx_ts_ready @ +#ifdef TX_ENABLE_WFI + DSB @ Ensure no outstanding memory transactions + WFI @ Wait for interrupt + ISB @ Ensure pipeline is flushed +#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: + LDR r7, =0x08000000 @ Build clear PendSV value + LDR r5, =0xE000ED04 @ Build base NVIC address + STR r7, [r5] @ Clear any PendSV +@ +@ /* Re-enable interrupts and restore new thread. */ +@ + CPSIE i @ Enable interrupts + B __tx_ts_restore @ Restore the thread + diff --git a/ports/cortex_m0/gnu/src/tx_thread_stack_build.S b/ports/cortex_m0/gnu/src/tx_thread_stack_build.S new file mode 100755 index 00000000..ca66e1d5 --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,149 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_stack_build Cortex-M0/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@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-M0 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 (sl) Initial value for r10 (sl) +@ 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 + MOVS r3, #0x7 @ + BICS r2, r2, r3 @ Align frame for 8-byte alignment + SUBS 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. */ +@ + MOVS 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 + LDR r3, [r0, #12] @ Pickup stack starting address + STR r3, [r2, #28] @ Store initial r10 (sl) + MOVS r3, #0 @ Build initial register value + 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 + LDR r3, =0xFFFFFFFF @ Poison EXC_RETURN value + STR r3, [r2, #56] @ Store initial lr + STR r1, [r2, #60] @ Store initial pc + LDR 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_m0/gnu/src/tx_thread_system_return.S b/ports/cortex_m0/gnu/src/tx_thread_system_return.S new file mode 100755 index 00000000..6de1b19b --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_thread_system_return.S @@ -0,0 +1,97 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@/* #define TX_SOURCE_CODE */ +@ +@ +@/* Include necessary system files. */ +@ +@/* #include "tx_api.h" +@ #include "tx_thread.h" +@ #include "tx_timer.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_system_return Cortex-M0/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* 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. */ +@ + LDR r0, =0x10000000 @ Load PENDSVSET bit + LDR r1, =0xE000ED04 @ Load NVIC base + STR r0, [r1] @ 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 +@/* } */ + diff --git a/ports/cortex_m0/gnu/src/tx_timer_interrupt.S b/ports/cortex_m0/gnu/src/tx_timer_interrupt.S new file mode 100755 index 00000000..ab85d97d --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,271 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Timer */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_timer.h" +@#include "tx_thread.h" +@ +@ +@Define Assembly language external references... +@ + .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-M0/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_timer_interrupt(VOID) +@{ + .global _tx_timer_interrupt + .thumb_func +_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++; +@ + LDR r1, =_tx_timer_system_clock @ Pickup address of system clock + LDR r0, [r1, #0] @ Pickup system clock + ADDS 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 + CMP r2, #0 @ Is it non-active? + BEQ __tx_timer_no_time_slice @ Yes, skip time-slice processing +@ +@ /* Decrement the time_slice. */ +@ _tx_timer_time_slice--; +@ + SUBS 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) +@ + CMP r2, #0 @ Has it expired? + BNE __tx_timer_no_time_slice @ 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 + MOVS 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 + CMP r2, #0 @ Is there anything in the list? + BEQ __tx_timer_no_timer @ No, just increment the timer +@ +@ /* Set expiration flag. */ +@ _tx_timer_expired = TX_TRUE; +@ + LDR r3, =_tx_timer_expired @ Pickup expiration flag address + MOVS 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++; +@ + ADDS 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 + CMP r2, #0 @ Did a time-slice expire? + BNE __tx_something_expired @ 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 + CMP r0, #0 @ Did a timer expire? + BEQ __tx_timer_nothing_expired @ No, nothing expired +@ +__tx_something_expired: +@ +@ + PUSH {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 + CMP r0, #0 @ Check for timer expiration + BEQ __tx_timer_dont_activate @ 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 + CMP r2, #0 @ See if the flag is set + BEQ __tx_timer_not_ts_expiration @ 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? + CMP r1, #0 @ + BNE __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: +@ + POP {r0, r1} @ Recover lr register (r0 is just there for + MOV lr, r1 @ the 8-byte stack alignment +@ +@ } +@ +__tx_timer_nothing_expired: + + DSB @ Complete all memory access + BX lr @ Return to caller +@ +@} + + diff --git a/ports/cortex_m0/gnu/src/tx_vector_table_sample.S b/ports/cortex_m0/gnu/src/tx_vector_table_sample.S new file mode 100644 index 00000000..55395cd1 --- /dev/null +++ b/ports/cortex_m0/gnu/src/tx_vector_table_sample.S @@ -0,0 +1,102 @@ + + + .global reset_handler + + .global __tx_NMIHandler + .global __tx_BadHandler + .global __tx_SVCallHandler + .global __tx_DBGHandler + .global __tx_PendSVHandler + .global __tx_SysTickHandler + .global __tx_BadHandler + .global __tx_HardfaultHandler + + + .syntax unified + .section .vectors, "ax" + .code 16 + .align 0 + .global _vectors + +_vectors: + .word __stack_end__ + .word reset_handler + .word __tx_NMIHandler + .word __tx_HardfaultHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word __tx_SVCallHandler //_SVC_Handler - used by Threadx scheduler // + .word __tx_DBGHandler + .word 0 // Reserved + .word __tx_PendSVHandler + .word __tx_SysTickHandler // Used by Threadx timer functionality + .word __tx_BadHandler // Populate with user Interrupt handler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + + + + .section .init, "ax" + .thumb_func +reset_handler: + +// low level hardware config, such as PLL setup goes here + + b _start + + + + .text 32 + .align 4 + .syntax unified + + +__tx_NMIHandler: + b __tx_NMIHandler + +__tx_BadHandler: + b __tx_BadHandler + +__tx_DBGHandler: + b __tx_DBGHandler + +__tx_HardfaultHandler: + b __tx_HardfaultHandler + diff --git a/ports/cortex_m3/gnu/CMakeLists.txt b/ports/cortex_m3/gnu/CMakeLists.txt new file mode 100644 index 00000000..cb3091b9 --- /dev/null +++ b/ports/cortex_m3/gnu/CMakeLists.txt @@ -0,0 +1,19 @@ + +target_sources(${PROJECT_NAME} + PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) 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 00000000..76f9aea1 --- /dev/null +++ b/ports/cortex_m3/gnu/inc/tx_port.h @@ -0,0 +1,357 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M3/GNU */ +/* 6.0 */ +/* */ +/* 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 */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#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 + + +/* 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 Cortex-M7 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 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 +#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. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#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 +#ifndef TX_MISRA_ENABLE + +__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()) +#else +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif +#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); +#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++; + + +/* This 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) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); + +#endif + + +#ifndef TX_DISABLE_INLINE + +/* Define GNU specific macros, with in-line assembly for performance. */ + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + __asm__ volatile (" CPSID i" : : : "memory" ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value) +{ + + __asm__ volatile (" MSR PRIMASK,%0": : "r" (primask_value): "memory" ); +} + +__attribute__( ( always_inline ) ) static inline unsigned int __get_primask_value(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + + __asm__ volatile (" CPSIE i": : : "memory" ); +} + + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + *((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_primask_value(); + __enable_interrupts(); + __restore_interrupts(interrupt_save); + } +} + + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupts(interrupt_save); + + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); +#endif + + +/* Define the version ID of ThreadX. This may be utilized by the application. */ + +#ifdef TX_THREAD_INIT +CHAR _tx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M3/GNU Version 6.0 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + + + + + diff --git a/ports/cortex_m3/gnu/src/tx_initialize_low_level_sample.S b/ports/cortex_m3/gnu/src/tx_initialize_low_level_sample.S new file mode 100644 index 00000000..bfa6e423 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_initialize_low_level_sample.S @@ -0,0 +1,244 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Initialize */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_initialize.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory + .global __RAM_segment_used_end__ + .global _tx_timer_interrupt + .global __main + .global __tx_SVCallHandler + .global __tx_PendSVHandler + .global _vectors + .global __tx_NMIHandler @ NMI + .global __tx_BadHandler @ HardFault + .global __tx_SVCallHandler @ SVCall + .global __tx_DBGHandler @ Monitor + .global __tx_PendSVHandler @ PendSV + .global __tx_SysTickHandler @ SysTick + .global __tx_IntHandler @ Int 0 +@ +@ +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_initialize_low_level Cortex-M3/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for any low-level processor */ +@/* initialization, including setting up interrupt vectors, setting */ +@/* up a periodic timer interrupt source, saving the system stack */ +@/* pointer for use in ISR processing later, and finding the first */ +@/* available RAM memory address for tx_application_define. */ +@/* */ +@/* INPUT */ +@/* */ +@/* None */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* None */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* _tx_initialize_kernel_enter ThreadX entry function */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_initialize_low_level(VOID) +@{ + .global _tx_initialize_low_level + .thumb_func +_tx_initialize_low_level: +@ +@ /* Disable interrupts during ThreadX initialization. */ +@ + CPSID i +@ +@ /* Set base of available memory to end of non-initialised RAM area. */ +@ + LDR r0, =_tx_initialize_unused_memory @ Build address of unused memory pointer + LDR r1, =__RAM_segment_used_end__ @ Build first free address + ADD r1, r1, #4 @ + STR r1, [r0] @ Setup first unused memory pointer +@ +@ /* Setup Vector Table Offset Register. */ +@ + MOV r0, #0xE000E000 @ Build address of NVIC registers + LDR r1, =_vectors @ Pickup address of vector table + STR r1, [r0, #0xD08] @ Set vector table address +@ +@ /* Set system stack pointer from vector value. */ +@ + LDR r0, =_tx_thread_system_stack_ptr @ Build address of system stack pointer + LDR r1, =_vectors @ Pickup address of vector table + LDR r1, [r1] @ Pickup reset stack pointer + STR r1, [r0] @ Save system stack pointer +@ +@ /* Enable the cycle count register. */ +@ + LDR r0, =0xE0001000 @ Build address of DWT register + LDR r1, [r0] @ Pickup the current value + ORR r1, r1, #1 @ Set the CYCCNTENA bit + STR r1, [r0] @ Enable the cycle count register +@ +@ /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference. */ +@ + MOV r0, #0xE000E000 @ Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] @ Setup SysTick Reload Value + MOV r1, #0x7 @ Build SysTick Control Enable Value + STR r1, [r0, #0x10] @ Setup SysTick Control +@ +@ /* Configure handler priorities. */ +@ + LDR r1, =0x00000000 @ Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] @ Setup System Handlers 4-7 Priority Registers + + LDR r1, =0xFF000000 @ SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] @ Setup System Handlers 8-11 Priority Registers + @ Note: SVC must be lowest priority, which is 0xFF + + LDR r1, =0x40FF0000 @ SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] @ Setup System Handlers 12-15 Priority Registers + @ Note: PnSV must be lowest priority, which is 0xFF + +@ +@ /* Return to caller. */ +@ + BX lr +@} +@ + +@/* Define shells for each of the unused vectors. */ +@ + .global __tx_BadHandler + .thumb_func +__tx_BadHandler: + B __tx_BadHandler + +@ /* added to catch the hardfault */ + + .global __tx_HardfaultHandler + .thumb_func +__tx_HardfaultHandler: + B __tx_HardfaultHandler + + +@ /* added to catch the SVC */ + + .global __tx_SVCallHandler + .thumb_func +__tx_SVCallHandler: + B __tx_SVCallHandler + + +@ /* Generic interrupt handler template */ + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +@ VOID InterruptHandler (VOID) +@ { + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter ; Call the ISR enter function +#endif + +@ /* Do interrupt handler work here */ +@ /* BL .... */ + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit ; Call the ISR exit function +#endif + POP {r0, lr} + BX LR +@ } + +@ /* System Tick timer interrupt handler */ + .global __tx_SysTickHandler + .global SysTick_Handler + .thumb_func +__tx_SysTickHandler: + .thumb_func +SysTick_Handler: +@ VOID TimerInterruptHandler (VOID) +@ { +@ + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter ; Call the ISR enter function +#endif + BL _tx_timer_interrupt +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit ; Call the ISR exit function +#endif + POP {r0, lr} + BX LR +@ } + + +@ /* NMI, DBG handlers */ + .global __tx_NMIHandler + .thumb_func +__tx_NMIHandler: + B __tx_NMIHandler + + .global __tx_DBGHandler + .thumb_func +__tx_DBGHandler: + B __tx_DBGHandler + + + + + 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 00000000..91937893 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,96 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_thread_system_stack_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_schedule + .global _tx_thread_preempt_disable + .global _tx_execution_isr_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_restore Cortex-M3/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_restore(VOID) +@{ + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: +@ +@ /* Not needed for this port - just return! */ + 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 00000000..29a7631a --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_context_save.S @@ -0,0 +1,89 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_execution_isr_enter +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_save Cortex-M3/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_save(VOID) +@{ + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: +@ +@ /* Not needed for this port - 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 00000000..5890a93d --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,92 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ + + +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ + +@/* #define TX_SOURCE_CODE */ + + +@/* Include necessary system files. */ + +@/* #include "tx_api.h" + #include "tx_thread.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_interrupt_control Cortex-M3/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* UINT _tx_thread_interrupt_control(UINT new_posture) +{ */ + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: + +@/* Pickup current interrupt lockout posture. */ + + MRS r1, PRIMASK @ Pickup current interrupt lockout + +@/* Apply the new interrupt posture. */ + + MSR PRIMASK, r0 @ Apply the new interrupt lockout + MOV r0, r1 @ Transfer old to return register + BX lr @ Return to caller + +@/* } */ + + + 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 00000000..6cf8ab54 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_schedule.S @@ -0,0 +1,252 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_system_stack_ptr + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_schedule Cortex-M3/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_schedule(VOID) +@{ + .global _tx_thread_schedule + .thumb_func +_tx_thread_schedule: +@ +@ /* This function should only ever be called on Cortex-M3 +@ 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 +@} +@ +@ /* Generic context switch-out switch-in handler... Note that this handler is +@ common for both PendSV and SVCall. */ +@ + .global PendSV_Handler + .global __tx_PendSVHandler + .thumb_func +PendSV_Handler: + .thumb_func +__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 + 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 + 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 + 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! +#ifdef TX_ENABLE_WFI + DSB @ Ensure no outstanding memory transactions + WFI @ Wait for interrupt + ISB @ Ensure pipeline is flushed +#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 + 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 00000000..bec56d45 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,148 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_stack_build Cortex-M3/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@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-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 (sl) Initial value for r10 (sl) +@ 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 + 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 + LDR r3, [r0, #12] @ Pickup stack starting address + STR r3, [r2, #28] @ Store initial r10 (sl) + MOV r3, #0 @ Build initial register value + 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 00000000..0ac8ce08 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_thread_system_return.S @@ -0,0 +1,98 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@/* #define TX_SOURCE_CODE */ +@ +@ +@/* Include necessary system files. */ +@ +@/* #include "tx_api.h" +@ #include "tx_thread.h" +@ #include "tx_timer.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_system_return Cortex-M3/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* 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 + 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 + +@/* } */ + 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 00000000..340d70e9 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,270 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Timer */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_timer.h" +@#include "tx_thread.h" +@ +@ +@Define Assembly language external references... +@ + .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.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_timer_interrupt(VOID) +@{ + .global _tx_timer_interrupt + .thumb_func +_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++; +@ + 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 + CMP r2, #0 @ Is it non-active? + BEQ __tx_timer_no_time_slice @ 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) +@ + CMP r2, #0 @ Has it expired? + BNE __tx_timer_no_time_slice @ 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 + CMP r2, #0 @ Is there anything in the list? + BEQ __tx_timer_no_timer @ 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 + CMP r2, #0 @ Did a time-slice expire? + BNE __tx_something_expired @ 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 + CMP r0, #0 @ Did a timer expire? + BEQ __tx_timer_nothing_expired @ 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 + CMP r0, #0 @ Check for timer expiration + BEQ __tx_timer_dont_activate @ 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 + CMP r2, #0 @ See if the flag is set + BEQ __tx_timer_not_ts_expiration @ 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 +@ +@} + + diff --git a/ports/cortex_m3/gnu/src/tx_vector_table_sample.S b/ports/cortex_m3/gnu/src/tx_vector_table_sample.S new file mode 100644 index 00000000..cf0db974 --- /dev/null +++ b/ports/cortex_m3/gnu/src/tx_vector_table_sample.S @@ -0,0 +1,84 @@ + + + .global reset_handler + + .global __tx_NMIHandler + .global __tx_BadHandler + .global __tx_SVCallHandler + .global __tx_DBGHandler + .global __tx_PendSVHandler + .global __tx_SysTickHandler + .global __tx_BadHandler + + + .syntax unified + .section .vectors, "ax" + .code 16 + .align 0 + .global _vectors + +_vectors: + .word __stack_end__ + .word reset_handler + .word __tx_NMIHandler + .word __tx_HardfaultHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word __tx_SVCallHandler //_SVC_Handler - used by Threadx scheduler // + .word __tx_DBGHandler + .word 0 // Reserved + .word __tx_PendSVHandler + .word __tx_SysTickHandler // Used by Threadx timer functionality + .word __tx_BadHandler // Populate with user Interrupt handler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + + + + .section .init, "ax" + .thumb_func +reset_handler: + +// low level hardware config, such as PLL setup goes here + + b _start + + + diff --git a/ports/cortex_m4/gnu/CMakeLists.txt b/ports/cortex_m4/gnu/CMakeLists.txt new file mode 100644 index 00000000..cb3091b9 --- /dev/null +++ b/ports/cortex_m4/gnu/CMakeLists.txt @@ -0,0 +1,19 @@ + +target_sources(${PROJECT_NAME} + PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) diff --git a/ports/cortex_m4/gnu/inc/tx_port.h b/ports/cortex_m4/gnu/inc/tx_port.h new file mode 100644 index 00000000..bca31b3d --- /dev/null +++ b/ports/cortex_m4/gnu/inc/tx_port.h @@ -0,0 +1,499 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M4/GNU */ +/* 6.0 */ +/* */ +/* 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 */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#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 + + +/* 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 Cortex-M7 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 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 +#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. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) + + +#ifdef TX_ENABLE_FPU_SUPPORT + + +#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 + +__attribute__( ( always_inline ) ) static inline ULONG __get_control(void) +{ + +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + + +__attribute__( ( always_inline ) ) static inline void __set_control(ULONG control_value) +{ + + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + + +#endif + + +/* 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(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control(_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(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + __asm__ volatile ("vmov.f32 s0, s0"); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control(_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 + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif + + + + +/* 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 + +__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()) +#else +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif +#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); +#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++; + + +/* This 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) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); + +#endif + + +#ifndef TX_DISABLE_INLINE + +/* Define GNU specific macros, with in-line assembly for performance. */ + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + __asm__ volatile (" CPSID i" : : : "memory" ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value) +{ + + __asm__ volatile (" MSR PRIMASK,%0": : "r" (primask_value): "memory" ); +} + +__attribute__( ( always_inline ) ) static inline unsigned int __get_primask_value(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + + __asm__ volatile (" CPSIE i": : : "memory" ); +} + + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + *((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_primask_value(); + __enable_interrupts(); + __restore_interrupts(interrupt_save); + } +} + + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupts(interrupt_save); + + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); +#endif + + +/* Define FPU extension for the Cortex-M4. Each is assumed to be called in the context of the executing + thread. This is for legacy only, and not needed anylonger. */ + +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) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M4/GNU Version 6.0 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + + + + + diff --git a/ports/cortex_m4/gnu/src/tx_initialize_low_level_sample.S b/ports/cortex_m4/gnu/src/tx_initialize_low_level_sample.S new file mode 100644 index 00000000..ce57f6e7 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_initialize_low_level_sample.S @@ -0,0 +1,240 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Initialize */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_initialize.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory + .global __RAM_segment_used_end__ + .global _tx_timer_interrupt + .global __main + .global __tx_SVCallHandler + .global __tx_PendSVHandler + .global _vectors + .global __tx_NMIHandler @ NMI + .global __tx_BadHandler @ HardFault + .global __tx_SVCallHandler @ SVCall + .global __tx_DBGHandler @ Monitor + .global __tx_PendSVHandler @ PendSV + .global __tx_SysTickHandler @ SysTick + .global __tx_IntHandler @ Int 0 +@ +@ +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_initialize_low_level Cortex-M4/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for any low-level processor */ +@/* initialization, including setting up interrupt vectors, setting */ +@/* up a periodic timer interrupt source, saving the system stack */ +@/* pointer for use in ISR processing later, and finding the first */ +@/* available RAM memory address for tx_application_define. */ +@/* */ +@/* INPUT */ +@/* */ +@/* None */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* None */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* _tx_initialize_kernel_enter ThreadX entry function */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_initialize_low_level(VOID) +@{ + .global _tx_initialize_low_level + .thumb_func +_tx_initialize_low_level: +@ +@ /* Disable interrupts during ThreadX initialization. */ +@ + CPSID i +@ +@ /* Set base of available memory to end of non-initialised RAM area. */ +@ + LDR r0, =_tx_initialize_unused_memory @ Build address of unused memory pointer + LDR r1, =__RAM_segment_used_end__ @ Build first free address + ADD r1, r1, #4 @ + STR r1, [r0] @ Setup first unused memory pointer +@ +@ /* Setup Vector Table Offset Register. */ +@ + MOV r0, #0xE000E000 @ Build address of NVIC registers + LDR r1, =_vectors @ Pickup address of vector table + STR r1, [r0, #0xD08] @ Set vector table address +@ +@ /* Set system stack pointer from vector value. */ +@ + LDR r0, =_tx_thread_system_stack_ptr @ Build address of system stack pointer + LDR r1, =_vectors @ Pickup address of vector table + LDR r1, [r1] @ Pickup reset stack pointer + STR r1, [r0] @ Save system stack pointer +@ +@ /* Enable the cycle count register. */ +@ + LDR r0, =0xE0001000 @ Build address of DWT register + LDR r1, [r0] @ Pickup the current value + ORR r1, r1, #1 @ Set the CYCCNTENA bit + STR r1, [r0] @ Enable the cycle count register +@ +@ /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference. */ +@ + MOV r0, #0xE000E000 @ Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] @ Setup SysTick Reload Value + MOV r1, #0x7 @ Build SysTick Control Enable Value + STR r1, [r0, #0x10] @ Setup SysTick Control +@ +@ /* Configure handler priorities. */ +@ + LDR r1, =0x00000000 @ Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] @ Setup System Handlers 4-7 Priority Registers + + LDR r1, =0xFF000000 @ SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] @ Setup System Handlers 8-11 Priority Registers + @ Note: SVC must be lowest priority, which is 0xFF + + LDR r1, =0x40FF0000 @ SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] @ Setup System Handlers 12-15 Priority Registers + @ Note: PnSV must be lowest priority, which is 0xFF + +@ +@ /* Return to caller. */ +@ + BX lr +@} +@ + +@/* Define shells for each of the unused vectors. */ +@ + .global __tx_BadHandler + .thumb_func +__tx_BadHandler: + B __tx_BadHandler + +@ /* added to catch the hardfault */ + + .global __tx_HardfaultHandler + .thumb_func +__tx_HardfaultHandler: + B __tx_HardfaultHandler + + +@ /* added to catch the SVC */ + + .global __tx_SVCallHandler + .thumb_func +__tx_SVCallHandler: + B __tx_SVCallHandler + + +@ /* Generic interrupt handler template */ + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +@ VOID InterruptHandler (VOID) +@ { + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter ; Call the ISR enter function +#endif + +@ /* Do interrupt handler work here */ +@ /* BL .... */ + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit ; Call the ISR exit function +#endif + POP {r0, lr} + BX LR +@ } + +@ /* System Tick timer interrupt handler */ + .global __tx_SysTickHandler + .global SysTick_Handler + .thumb_func +__tx_SysTickHandler: + .thumb_func +SysTick_Handler: +@ VOID TimerInterruptHandler (VOID) +@ { +@ + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter ; Call the ISR enter function +#endif + BL _tx_timer_interrupt +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit ; Call the ISR exit function +#endif + POP {r0, lr} + BX LR +@ } + + +@ /* NMI, DBG handlers */ + .global __tx_NMIHandler + .thumb_func +__tx_NMIHandler: + B __tx_NMIHandler + + .global __tx_DBGHandler + .thumb_func +__tx_DBGHandler: + B __tx_DBGHandler + diff --git a/ports/cortex_m4/gnu/src/tx_thread_context_restore.S b/ports/cortex_m4/gnu/src/tx_thread_context_restore.S new file mode 100644 index 00000000..37e37c28 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,96 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_thread_system_stack_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_schedule + .global _tx_thread_preempt_disable + .global _tx_execution_isr_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_restore Cortex-M4/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_restore(VOID) +@{ + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: +@ +@ /* Not needed for this port - just return! */ + BX lr +@} + diff --git a/ports/cortex_m4/gnu/src/tx_thread_context_save.S b/ports/cortex_m4/gnu/src/tx_thread_context_save.S new file mode 100644 index 00000000..b2196ac4 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_thread_context_save.S @@ -0,0 +1,89 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_execution_isr_enter +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_save Cortex-M4/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_save(VOID) +@{ + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: +@ +@ /* Not needed for this port - just return! */ + BX lr +@} diff --git a/ports/cortex_m4/gnu/src/tx_thread_interrupt_control.S b/ports/cortex_m4/gnu/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..31e83f46 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,92 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ + + +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ + +@/* #define TX_SOURCE_CODE */ + + +@/* Include necessary system files. */ + +@/* #include "tx_api.h" + #include "tx_thread.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_interrupt_control Cortex-M4/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* UINT _tx_thread_interrupt_control(UINT new_posture) +{ */ + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: + +@/* Pickup current interrupt lockout posture. */ + + MRS r1, PRIMASK @ Pickup current interrupt lockout + +@/* Apply the new interrupt posture. */ + + MSR PRIMASK, r0 @ Apply the new interrupt lockout + MOV r0, r1 @ Transfer old to return register + BX lr @ Return to caller + +@/* } */ + + + diff --git a/ports/cortex_m4/gnu/src/tx_thread_schedule.S b/ports/cortex_m4/gnu/src/tx_thread_schedule.S new file mode 100644 index 00000000..11bdbe09 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_thread_schedule.S @@ -0,0 +1,296 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_system_stack_ptr + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_schedule Cortex-M4/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_schedule(VOID) +@{ + .global _tx_thread_schedule + .thumb_func +_tx_thread_schedule: +@ +@ /* This function should only ever be called on Cortex-M4 +@ 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 +@ +@ /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ +@ +#ifdef TX_ENABLE_FPU_SUPPORT + 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 switch-out switch-in handler... Note that this handler is +@ common for both PendSV and SVCall. */ +@ + .global PendSV_Handler + .global __tx_PendSVHandler + .thumb_func +PendSV_Handler: + .thumb_func +__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 +#ifdef TX_ENABLE_FPU_SUPPORT + 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! */ +@ + 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 + LDMIA r12!, {LR} @ Pickup LR +#ifdef TX_ENABLE_FPU_SUPPORT + 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: + 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_ENABLE_WFI + DSB @ Ensure no outstanding memory transactions + WFI @ Wait for interrupt + ISB @ Ensure pipeline is flushed +#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 + + +#ifdef TX_ENABLE_FPU_SUPPORT + + .global tx_thread_fpu_enable + .thumb_func +tx_thread_fpu_enable: +@ +@ /* Automatic VPF logic is supported, this function is present only for +@ backward compatibility purposes and therefore simply returns. */ +@ + BX LR @ Return to caller + + .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_m4/gnu/src/tx_thread_stack_build.S b/ports/cortex_m4/gnu/src/tx_thread_stack_build.S new file mode 100644 index 00000000..f9ca6842 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,148 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_stack_build Cortex-M4/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@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-M4 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 (sl) Initial value for r10 (sl) +@ 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 + 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 + LDR r3, [r0, #12] @ Pickup stack starting address + STR r3, [r2, #28] @ Store initial r10 (sl) + MOV r3, #0 @ Build initial register value + 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_m4/gnu/src/tx_thread_system_return.S b/ports/cortex_m4/gnu/src/tx_thread_system_return.S new file mode 100644 index 00000000..d570bb73 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_thread_system_return.S @@ -0,0 +1,98 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@/* #define TX_SOURCE_CODE */ +@ +@ +@/* Include necessary system files. */ +@ +@/* #include "tx_api.h" +@ #include "tx_thread.h" +@ #include "tx_timer.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_system_return Cortex-M4/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* 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 + 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 + +@/* } */ + diff --git a/ports/cortex_m4/gnu/src/tx_timer_interrupt.S b/ports/cortex_m4/gnu/src/tx_timer_interrupt.S new file mode 100644 index 00000000..6d96eaf9 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,270 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Timer */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_timer.h" +@#include "tx_thread.h" +@ +@ +@Define Assembly language external references... +@ + .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-M4/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_timer_interrupt(VOID) +@{ + .global _tx_timer_interrupt + .thumb_func +_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++; +@ + 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 + CMP r2, #0 @ Is it non-active? + BEQ __tx_timer_no_time_slice @ 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) +@ + CMP r2, #0 @ Has it expired? + BNE __tx_timer_no_time_slice @ 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 + CMP r2, #0 @ Is there anything in the list? + BEQ __tx_timer_no_timer @ 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 + CMP r2, #0 @ Did a time-slice expire? + BNE __tx_something_expired @ 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 + CMP r0, #0 @ Did a timer expire? + BEQ __tx_timer_nothing_expired @ 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 + CMP r0, #0 @ Check for timer expiration + BEQ __tx_timer_dont_activate @ 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 + CMP r2, #0 @ See if the flag is set + BEQ __tx_timer_not_ts_expiration @ 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 +@ +@} + + diff --git a/ports/cortex_m4/gnu/src/tx_vector_table_sample.S b/ports/cortex_m4/gnu/src/tx_vector_table_sample.S new file mode 100644 index 00000000..cf0db974 --- /dev/null +++ b/ports/cortex_m4/gnu/src/tx_vector_table_sample.S @@ -0,0 +1,84 @@ + + + .global reset_handler + + .global __tx_NMIHandler + .global __tx_BadHandler + .global __tx_SVCallHandler + .global __tx_DBGHandler + .global __tx_PendSVHandler + .global __tx_SysTickHandler + .global __tx_BadHandler + + + .syntax unified + .section .vectors, "ax" + .code 16 + .align 0 + .global _vectors + +_vectors: + .word __stack_end__ + .word reset_handler + .word __tx_NMIHandler + .word __tx_HardfaultHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word __tx_SVCallHandler //_SVC_Handler - used by Threadx scheduler // + .word __tx_DBGHandler + .word 0 // Reserved + .word __tx_PendSVHandler + .word __tx_SysTickHandler // Used by Threadx timer functionality + .word __tx_BadHandler // Populate with user Interrupt handler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + + + + .section .init, "ax" + .thumb_func +reset_handler: + +// low level hardware config, such as PLL setup goes here + + b _start + + + diff --git a/ports/cortex_m7/gnu/CMakeLists.txt b/ports/cortex_m7/gnu/CMakeLists.txt new file mode 100644 index 00000000..a361adf0 --- /dev/null +++ b/ports/cortex_m7/gnu/CMakeLists.txt @@ -0,0 +1,17 @@ + +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.S + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) diff --git a/ports/cortex_m7/gnu/inc/tx_port.h b/ports/cortex_m7/gnu/inc/tx_port.h new file mode 100644 index 00000000..95adfab4 --- /dev/null +++ b/ports/cortex_m7/gnu/inc/tx_port.h @@ -0,0 +1,496 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Cortex-M7/GNU */ +/* 6.0 */ +/* */ +/* 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 */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#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 + + +/* 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 Cortex-M7 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 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 +#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. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) + +#ifdef TX_ENABLE_FPU_SUPPORT + + +#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 + +__attribute__( ( always_inline ) ) static inline ULONG __get_control(void) +{ + +ULONG control_value; + + __asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) ); + return(control_value); +} + + +__attribute__( ( always_inline ) ) static inline void __set_control(ULONG control_value) +{ + + __asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" ); +} + + +#endif + + +/* 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(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control(_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(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control(_tx_vfp_state); \ + } \ + else \ + { \ + ULONG _tx_fpccr; \ + _tx_fpccr = *((ULONG *) 0xE000EF34); \ + _tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \ + if (_tx_fpccr == ((ULONG) 0x01)) \ + { \ + ULONG _tx_vfp_state; \ + _tx_vfp_state = __get_control(); \ + _tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \ + __asm__ volatile ("vmov.f32 s0, s0"); \ + if (_tx_vfp_state == ((ULONG) 0)) \ + { \ + _tx_vfp_state = __get_control(); \ + _tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \ + __set_control(_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 + +#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) +#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) + +#endif + + +/* 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 + +__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()) +#else +ULONG _tx_misra_ipsr_get(VOID); +#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get()) +#endif +#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); +#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++; + + +/* This 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) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \ + __asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) ); + +#endif + + +#ifndef TX_DISABLE_INLINE + +/* Define GNU specific macros, with in-line assembly for performance. */ + +__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + __asm__ volatile (" CPSID i" : : : "memory" ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value) +{ + + __asm__ volatile (" MSR PRIMASK,%0": : "r" (primask_value): "memory" ); +} + +__attribute__( ( always_inline ) ) static inline unsigned int __get_primask_value(void) +{ + +unsigned int primask_value; + + __asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) ); + return(primask_value); +} + +__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void) +{ + + __asm__ volatile (" CPSIE i": : : "memory" ); +} + + +__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void) +{ +unsigned int interrupt_save; + + *((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000); + if (__get_ipsr_value() == 0) + { + interrupt_save = __get_primask_value(); + __enable_interrupts(); + __restore_interrupts(interrupt_save); + } +} + + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = __disable_interrupts(); +#define TX_RESTORE __restore_interrupts(interrupt_save); + + +/* Redefine _tx_thread_system_return for improved performance. */ + +#define _tx_thread_system_return _tx_thread_system_return_inline + + +#else + +#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save; + +#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE); +#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save); +#endif + + +/* Define FPU extension for the Cortex-M7. Each is assumed to be called in the context of the executing + thread. This is for legacy only, and not needed any longer. */ + +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) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M7/GNU Version 6.0 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +#endif + + + + + diff --git a/ports/cortex_m7/gnu/src/tx_initialize_low_level_sample.S b/ports/cortex_m7/gnu/src/tx_initialize_low_level_sample.S new file mode 100755 index 00000000..1957867c --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_initialize_low_level_sample.S @@ -0,0 +1,239 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** 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" +@ +@ + .global _tx_thread_system_stack_ptr + .global _tx_initialize_unused_memory + .global __RAM_segment_used_end__ + .global _tx_timer_interrupt + .global __main + .global __tx_SVCallHandler + .global __tx_PendSVHandler + .global _vectors + .global __tx_NMIHandler @ NMI + .global __tx_BadHandler @ HardFault + .global __tx_SVCallHandler @ SVCall + .global __tx_DBGHandler @ Monitor + .global __tx_PendSVHandler @ PendSV + .global __tx_SysTickHandler @ SysTick + .global __tx_IntHandler @ Int 0 +@ +@ +SYSTEM_CLOCK = 6000000 +SYSTICK_CYCLES = ((SYSTEM_CLOCK / 100) -1) + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_initialize_low_level Cortex-M7/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* This function is responsible for any low-level processor */ +@/* initialization, including setting up interrupt vectors, setting */ +@/* up a periodic timer interrupt source, saving the system stack */ +@/* pointer for use in ISR processing later, and finding the first */ +@/* available RAM memory address for tx_application_define. */ +@/* */ +@/* INPUT */ +@/* */ +@/* None */ +@/* */ +@/* OUTPUT */ +@/* */ +@/* None */ +@/* */ +@/* CALLS */ +@/* */ +@/* None */ +@/* */ +@/* CALLED BY */ +@/* */ +@/* _tx_initialize_kernel_enter ThreadX entry function */ +@/* */ +@/* RELEASE HISTORY */ +@/* */ +@/* DATE NAME DESCRIPTION */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_initialize_low_level(VOID) +@{ + .global _tx_initialize_low_level + .thumb_func +_tx_initialize_low_level: +@ +@ /* Disable interrupts during ThreadX initialization. */ +@ + CPSID i +@ +@ /* Set base of available memory to end of non-initialised RAM area. */ +@ + LDR r0, =_tx_initialize_unused_memory @ Build address of unused memory pointer + LDR r1, =__RAM_segment_used_end__ @ Build first free address + ADD r1, r1, #4 @ + STR r1, [r0] @ Setup first unused memory pointer +@ +@ /* Setup Vector Table Offset Register. */ +@ + MOV r0, #0xE000E000 @ Build address of NVIC registers + LDR r1, =_vectors @ Pickup address of vector table + STR r1, [r0, #0xD08] @ Set vector table address +@ +@ /* Set system stack pointer from vector value. */ +@ + LDR r0, =_tx_thread_system_stack_ptr @ Build address of system stack pointer + LDR r1, =_vectors @ Pickup address of vector table + LDR r1, [r1] @ Pickup reset stack pointer + STR r1, [r0] @ Save system stack pointer +@ +@ /* Enable the cycle count register. */ +@ + LDR r0, =0xE0001000 @ Build address of DWT register + LDR r1, [r0] @ Pickup the current value + ORR r1, r1, #1 @ Set the CYCCNTENA bit + STR r1, [r0] @ Enable the cycle count register +@ +@ /* Configure SysTick for 100Hz clock, or 16384 cycles if no reference. */ +@ + MOV r0, #0xE000E000 @ Build address of NVIC registers + LDR r1, =SYSTICK_CYCLES + STR r1, [r0, #0x14] @ Setup SysTick Reload Value + MOV r1, #0x7 @ Build SysTick Control Enable Value + STR r1, [r0, #0x10] @ Setup SysTick Control +@ +@ /* Configure handler priorities. */ +@ + LDR r1, =0x00000000 @ Rsrv, UsgF, BusF, MemM + STR r1, [r0, #0xD18] @ Setup System Handlers 4-7 Priority Registers + + LDR r1, =0xFF000000 @ SVCl, Rsrv, Rsrv, Rsrv + STR r1, [r0, #0xD1C] @ Setup System Handlers 8-11 Priority Registers + @ Note: SVC must be lowest priority, which is 0xFF + + LDR r1, =0x40FF0000 @ SysT, PnSV, Rsrv, DbgM + STR r1, [r0, #0xD20] @ Setup System Handlers 12-15 Priority Registers + @ Note: PnSV must be lowest priority, which is 0xFF + +@ +@ /* Return to caller. */ +@ + BX lr +@} +@ + +@/* Define shells for each of the unused vectors. */ +@ + .global __tx_BadHandler + .thumb_func +__tx_BadHandler: + B __tx_BadHandler + +@ /* added to catch the hardfault */ + + .global __tx_HardfaultHandler + .thumb_func +__tx_HardfaultHandler: + B __tx_HardfaultHandler + + +@ /* added to catch the SVC */ + + .global __tx_SVCallHandler + .thumb_func +__tx_SVCallHandler: + B __tx_SVCallHandler + + +@ /* Generic interrupt handler template */ + .global __tx_IntHandler + .thumb_func +__tx_IntHandler: +@ VOID InterruptHandler (VOID) +@ { + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter ; Call the ISR enter function +#endif + +@ /* Do interrupt handler work here */ +@ /* BL .... */ + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit ; Call the ISR exit function +#endif + POP {r0, lr} + BX LR +@ } + +@ /* System Tick timer interrupt handler */ + .global __tx_SysTickHandler + .global SysTick_Handler + .thumb_func +__tx_SysTickHandler: + .thumb_func +SysTick_Handler: +@ VOID TimerInterruptHandler (VOID) +@ { +@ + PUSH {r0, lr} +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_enter ; Call the ISR enter function +#endif + BL _tx_timer_interrupt +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + BL _tx_execution_isr_exit ; Call the ISR exit function +#endif + POP {r0, lr} + BX LR +@ } + + +@ /* NMI, DBG handlers */ + .global __tx_NMIHandler + .thumb_func +__tx_NMIHandler: + B __tx_NMIHandler + + .global __tx_DBGHandler + .thumb_func +__tx_DBGHandler: + B __tx_DBGHandler diff --git a/ports/cortex_m7/gnu/src/tx_thread_context_restore.S b/ports/cortex_m7/gnu/src/tx_thread_context_restore.S new file mode 100755 index 00000000..53a7a18f --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,96 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_thread_system_stack_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_schedule + .global _tx_thread_preempt_disable + .global _tx_execution_isr_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_restore Cortex-M7/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_restore(VOID) +@{ + .global _tx_thread_context_restore + .thumb_func +_tx_thread_context_restore: +@ +@ /* Not needed for this port - just return! */ + BX lr +@} + diff --git a/ports/cortex_m7/gnu/src/tx_thread_context_save.S b/ports/cortex_m7/gnu/src/tx_thread_context_save.S new file mode 100755 index 00000000..1c7eff9e --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_thread_context_save.S @@ -0,0 +1,89 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ +@ + .global _tx_thread_system_state + .global _tx_thread_current_ptr + .global _tx_execution_isr_enter +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_context_save Cortex-M7/GNU */ +@/* 6.0 */ +@/* AUTHOR */ +@/* */ +@/* William E. Lamie, Microsoft Corporation */ +@/* */ +@/* DESCRIPTION */ +@/* */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_context_save(VOID) +@{ + .global _tx_thread_context_save + .thumb_func +_tx_thread_context_save: +@ +@ /* Not needed for this port - just return! */ + BX lr +@} diff --git a/ports/cortex_m7/gnu/src/tx_thread_interrupt_control.S b/ports/cortex_m7/gnu/src/tx_thread_interrupt_control.S new file mode 100755 index 00000000..f4e3f61c --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,92 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ + + +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ + +@/* #define TX_SOURCE_CODE */ + + +@/* Include necessary system files. */ + +@/* #include "tx_api.h" + #include "tx_thread.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_interrupt_control Cortex-M7/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* UINT _tx_thread_interrupt_control(UINT new_posture) +{ */ + .global _tx_thread_interrupt_control + .thumb_func +_tx_thread_interrupt_control: + +@/* Pickup current interrupt lockout posture. */ + + MRS r1, PRIMASK @ Pickup current interrupt lockout + +@/* Apply the new interrupt posture. */ + + MSR PRIMASK, r0 @ Apply the new interrupt lockout + MOV r0, r1 @ Transfer old to return register + BX lr @ Return to caller + +@/* } */ + + + diff --git a/ports/cortex_m7/gnu/src/tx_thread_schedule.S b/ports/cortex_m7/gnu/src/tx_thread_schedule.S new file mode 100755 index 00000000..99af8be2 --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_thread_schedule.S @@ -0,0 +1,296 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@#include "tx_timer.h" +@ + .global _tx_thread_current_ptr + .global _tx_thread_execute_ptr + .global _tx_timer_time_slice + .global _tx_thread_system_stack_ptr + .global _tx_execution_thread_enter + .global _tx_execution_thread_exit +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_schedule Cortex-M7/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_thread_schedule(VOID) +@{ + .global _tx_thread_schedule + .thumb_func +_tx_thread_schedule: +@ +@ /* This function should only ever be called on Cortex-M7 +@ 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 +@ +@ /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */ +@ +#ifdef TX_ENABLE_FPU_SUPPORT + 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 switch-out switch-in handler... Note that this handler is +@ common for both PendSV and SVCall. */ +@ + .global PendSV_Handler + .global __tx_PendSVHandler + .thumb_func +PendSV_Handler: + .thumb_func +__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 +#ifdef TX_ENABLE_FPU_SUPPORT + 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! */ +@ + 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 + LDMIA r12!, {LR} @ Pickup LR +#ifdef TX_ENABLE_FPU_SUPPORT + 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: + 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_ENABLE_WFI + DSB @ Ensure no outstanding memory transactions + WFI @ Wait for interrupt + ISB @ Ensure pipeline is flushed +#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 + + +#ifdef TX_ENABLE_FPU_SUPPORT + + .global tx_thread_fpu_enable + .thumb_func +tx_thread_fpu_enable: +@ +@ /* Automatic VPF logic is supported, this function is present only for +@ backward compatibility purposes and therefore simply returns. */ +@ + BX LR @ Return to caller + + .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_m7/gnu/src/tx_thread_stack_build.S b/ports/cortex_m7/gnu/src/tx_thread_stack_build.S new file mode 100755 index 00000000..19417731 --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,148 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_thread.h" +@ +@ + .text + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_stack_build Cortex-M7/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@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-M7 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 (sl) Initial value for r10 (sl) +@ 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 + 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 + LDR r3, [r0, #12] @ Pickup stack starting address + STR r3, [r2, #28] @ Store initial r10 (sl) + MOV r3, #0 @ Build initial register value + 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_m7/gnu/src/tx_thread_system_return.S b/ports/cortex_m7/gnu/src/tx_thread_system_return.S new file mode 100755 index 00000000..3c609279 --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_thread_system_return.S @@ -0,0 +1,98 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Thread */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@/* #define TX_SOURCE_CODE */ +@ +@ +@/* Include necessary system files. */ +@ +@/* #include "tx_api.h" +@ #include "tx_thread.h" +@ #include "tx_timer.h" */ + + + .text 32 + .align 4 + .syntax unified +@/**************************************************************************/ +@/* */ +@/* FUNCTION RELEASE */ +@/* */ +@/* _tx_thread_system_return Cortex-M7/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@/* 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 + 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 + +@/* } */ + diff --git a/ports/cortex_m7/gnu/src/tx_timer_interrupt.S b/ports/cortex_m7/gnu/src/tx_timer_interrupt.S new file mode 100755 index 00000000..b58b60b7 --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_timer_interrupt.S @@ -0,0 +1,270 @@ +@/**************************************************************************/ +@/* */ +@/* Copyright (c) Microsoft Corporation. All rights reserved. */ +@/* */ +@/* This software is licensed under the Microsoft Software License */ +@/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +@/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +@/* and in the root directory of this software. */ +@/* */ +@/**************************************************************************/ +@ +@ +@/**************************************************************************/ +@/**************************************************************************/ +@/** */ +@/** ThreadX Component */ +@/** */ +@/** Timer */ +@/** */ +@/**************************************************************************/ +@/**************************************************************************/ +@ +@#define TX_SOURCE_CODE +@ +@ +@/* Include necessary system files. */ +@ +@#include "tx_api.h" +@#include "tx_timer.h" +@#include "tx_thread.h" +@ +@ +@Define Assembly language external references... +@ + .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-M7/GNU */ +@/* 6.0 */ +@/* 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 */ +@/* */ +@/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +@/* */ +@/**************************************************************************/ +@VOID _tx_timer_interrupt(VOID) +@{ + .global _tx_timer_interrupt + .thumb_func +_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++; +@ + 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 + CMP r2, #0 @ Is it non-active? + BEQ __tx_timer_no_time_slice @ 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) +@ + CMP r2, #0 @ Has it expired? + BNE __tx_timer_no_time_slice @ 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 + CMP r2, #0 @ Is there anything in the list? + BEQ __tx_timer_no_timer @ 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 + CMP r2, #0 @ Did a time-slice expire? + BNE __tx_something_expired @ 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 + CMP r0, #0 @ Did a timer expire? + BEQ __tx_timer_nothing_expired @ 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 + CMP r0, #0 @ Check for timer expiration + BEQ __tx_timer_dont_activate @ 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 + CMP r2, #0 @ See if the flag is set + BEQ __tx_timer_not_ts_expiration @ 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 +@ +@} + + diff --git a/ports/cortex_m7/gnu/src/tx_vector_table_sample.S b/ports/cortex_m7/gnu/src/tx_vector_table_sample.S new file mode 100644 index 00000000..cf0db974 --- /dev/null +++ b/ports/cortex_m7/gnu/src/tx_vector_table_sample.S @@ -0,0 +1,84 @@ + + + .global reset_handler + + .global __tx_NMIHandler + .global __tx_BadHandler + .global __tx_SVCallHandler + .global __tx_DBGHandler + .global __tx_PendSVHandler + .global __tx_SysTickHandler + .global __tx_BadHandler + + + .syntax unified + .section .vectors, "ax" + .code 16 + .align 0 + .global _vectors + +_vectors: + .word __stack_end__ + .word reset_handler + .word __tx_NMIHandler + .word __tx_HardfaultHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word 0 // Reserved + .word __tx_SVCallHandler //_SVC_Handler - used by Threadx scheduler // + .word __tx_DBGHandler + .word 0 // Reserved + .word __tx_PendSVHandler + .word __tx_SysTickHandler // Used by Threadx timer functionality + .word __tx_BadHandler // Populate with user Interrupt handler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + .word __tx_BadHandler + + + + .section .init, "ax" + .thumb_func +reset_handler: + +// low level hardware config, such as PLL setup goes here + + b _start + + + diff --git a/ports/linux/gnu/CMakeLists.txt b/ports/linux/gnu/CMakeLists.txt new file mode 100644 index 00000000..8d7ee023 --- /dev/null +++ b/ports/linux/gnu/CMakeLists.txt @@ -0,0 +1,25 @@ +# For this port, we need to tell the common subdirectory to not include these files +set(TX_SRC_OVERRIDES + "tx_thread_delete.c" + "tx_thread_reset.c" +CACHE STRING "tx source overrides") + +target_sources(${PROJECT_NAME} + PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) + diff --git a/ports/linux/gnu/inc/tx_port.h b/ports/linux/gnu/inc/tx_port.h new file mode 100644 index 00000000..05677bd9 --- /dev/null +++ b/ports/linux/gnu/inc/tx_port.h @@ -0,0 +1,575 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* tx_port.h Linux/GNU */ +/* 6.0 */ +/* */ +/* 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 */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef TX_PORT_H +#define TX_PORT_H + + +#define TX_MAX_PRIORITIES 32 +/* #define TX_MISRA_ENABLE */ + + +/* #define TX_INLINE_INITIALIZATION */ + +/* #define TX_NOT_INTERRUPTABLE */ +/* #define TX_TIMER_PROCESS_IN_ISR */ +/* #define TX_REACTIVATE_INLINE */ +/* #define TX_DISABLE_STACK_FILLING */ +/* #define TX_ENABLE_STACK_CHECKING */ +/* #define TX_DISABLE_PREEMPTION_THRESHOLD */ +/* #define TX_DISABLE_REDUNDANT_CLEARING */ +/* #define TX_DISABLE_NOTIFY_CALLBACKS */ +/* #define TX_INLINE_THREAD_RESUME_SUSPEND */ +/* #define TX_ENABLE_EVENT_TRACE */ + + +/* For MISRA, define enable performance info. Also, for MISRA TX_DISABLE_NOTIFY_CALLBACKS should not be defined. */ + + +/* #define TX_BLOCK_POOL_ENABLE_PERFORMANCE_INFO +#define TX_BYTE_POOL_ENABLE_PERFORMANCE_INFO +#define TX_EVENT_FLAGS_ENABLE_PERFORMANCE_INFO +#define TX_MUTEX_ENABLE_PERFORMANCE_INFO +#define TX_QUEUE_ENABLE_PERFORMANCE_INFO +#define TX_SEMAPHORE_ENABLE_PERFORMANCE_INFO +#define TX_THREAD_ENABLE_PERFORMANCE_INFO +#define TX_TIMER_ENABLE_PERFORMANCE_INFO */ + + + +/* 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 +#ifndef __USE_POSIX199309 +#define __USE_POSIX199309 +#include +#include +#include +#undef __USE_POSIX199309 +#else /* __USE_POSIX199309 */ +#include +#include +#include +#endif /* __USE_POSIX199309 */ + + +/* Define ThreadX basic types for this port. */ + +typedef void VOID; +typedef char CHAR; +typedef unsigned char UCHAR; +typedef int INT; +typedef unsigned int UINT; +#if __x86_64__ +typedef int LONG; +typedef unsigned int ULONG; +#else /* __x86_64__ */ +typedef long LONG; +typedef unsigned long ULONG; +#endif /* __x86_64__ */ +typedef short SHORT; +typedef unsigned short USHORT; +typedef uint64_t ULONG64; + + +/* Override the alignment type to use 64-bit alignment and storage for pointers. */ + +#if __x86_64__ +#define ALIGN_TYPE_DEFINED +typedef unsigned long long ALIGN_TYPE; + +/* Override the free block marker for byte pools to be a 64-bit constant. */ + +#define TX_BYTE_BLOCK_FREE ((ALIGN_TYPE) 0xFFFFEEEEFFFFEEEE) +#endif + +/* Define automated coverage test extensions... These are required for the + ThreadX regression test. */ + +typedef unsigned int TEST_FLAG; +extern TEST_FLAG threadx_byte_allocate_loop_test; +extern TEST_FLAG threadx_byte_release_loop_test; +extern TEST_FLAG threadx_mutex_suspension_put_test; +extern TEST_FLAG threadx_mutex_suspension_priority_test; +#ifndef TX_TIMER_PROCESS_IN_ISR +extern TEST_FLAG threadx_delete_timer_thread; +#endif + +extern void abort_and_resume_byte_allocating_thread(void); +extern void abort_all_threads_suspended_on_mutex(void); +extern void suspend_lowest_priority(void); +#ifndef TX_TIMER_PROCESS_IN_ISR +extern void delete_timer_thread(void); +#endif +extern TEST_FLAG test_stack_analyze_flag; +extern TEST_FLAG test_initialize_flag; +extern TEST_FLAG test_forced_mutex_timeout; + + +#ifdef TX_REGRESSION_TEST + +/* Define extension macros for automated coverage tests. */ + + +#define TX_BYTE_ALLOCATE_EXTENSION if (threadx_byte_allocate_loop_test == ((TEST_FLAG) 1)) \ + { \ + pool_ptr -> tx_byte_pool_owner = TX_NULL; \ + threadx_byte_allocate_loop_test = ((TEST_FLAG) 0); \ + } + +#define TX_BYTE_RELEASE_EXTENSION if (threadx_byte_release_loop_test == ((TEST_FLAG) 1)) \ + { \ + threadx_byte_release_loop_test = ((TEST_FLAG) 0); \ + abort_and_resume_byte_allocating_thread(); \ + } + +#define TX_MUTEX_PUT_EXTENSION_1 if (threadx_mutex_suspension_put_test == ((TEST_FLAG) 1)) \ + { \ + threadx_mutex_suspension_put_test = ((TEST_FLAG) 0); \ + abort_all_threads_suspended_on_mutex(); \ + } + + +#define TX_MUTEX_PUT_EXTENSION_2 if (test_forced_mutex_timeout == ((TEST_FLAG) 1)) \ + { \ + test_forced_mutex_timeout = ((TEST_FLAG) 0); \ + _tx_thread_wait_abort(mutex_ptr -> tx_mutex_suspension_list); \ + } + + +#define TX_MUTEX_PRIORITY_CHANGE_EXTENSION if (threadx_mutex_suspension_priority_test == ((TEST_FLAG) 1)) \ + { \ + threadx_mutex_suspension_priority_test = ((TEST_FLAG) 0); \ + suspend_lowest_priority(); \ + } + +#ifndef TX_TIMER_PROCESS_IN_ISR + +#define TX_TIMER_INITIALIZE_EXTENSION(a) if (threadx_delete_timer_thread == ((TEST_FLAG) 1)) \ + { \ + threadx_delete_timer_thread = ((TEST_FLAG) 0); \ + delete_timer_thread(); \ + (a) = ((UINT) 1); \ + } + +#endif + +#define TX_THREAD_STACK_ANALYZE_EXTENSION if (test_stack_analyze_flag == ((TEST_FLAG) 1)) \ + { \ + thread_ptr -> tx_thread_id = ((TEST_FLAG) 0); \ + test_stack_analyze_flag = ((TEST_FLAG) 0); \ + } \ + else if (test_stack_analyze_flag == ((TEST_FLAG) 2)) \ + { \ + stack_ptr = thread_ptr -> tx_thread_stack_start; \ + test_stack_analyze_flag = ((TEST_FLAG) 0); \ + } \ + else if (test_stack_analyze_flag == ((TEST_FLAG) 3)) \ + { \ + *stack_ptr = TX_STACK_FILL; \ + test_stack_analyze_flag = ((TEST_FLAG) 0); \ + } \ + else \ + { \ + test_stack_analyze_flag = ((TEST_FLAG) 0); \ + } + +#define TX_INITIALIZE_KERNEL_ENTER_EXTENSION if (test_initialize_flag == ((TEST_FLAG) 1)) \ + { \ + test_initialize_flag = ((TEST_FLAG) 0); \ + return; \ + } + +#endif + + + +/* Add Linux debug insert prototype. */ + +void _tx_linux_debug_entry_insert(char *action, char *file, unsigned long line); + +#ifndef TX_LINUX_DEBUG_ENABLE + +/* If Linux debug is not enabled, turn logging into white-space. */ + +#define _tx_linux_debug_entry_insert(a, b, c) + +#endif + + + +/* Define the TX_MEMSET macro to remove library reference. */ + +#ifndef TX_MISRA_ENABLE +#define TX_MEMSET(a,b,c) { \ + UCHAR *ptr; \ + UCHAR value; \ + UINT i, size; \ + ptr = (UCHAR *) ((VOID *) a); \ + value = (UCHAR) b; \ + size = (UINT) c; \ + for (i = 0; i < size; i++) \ + { \ + *ptr++ = value; \ + } \ + } +#endif + + +/* 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 400 /* Default timer thread stack size - Not used in Linux port! */ +#endif + +#ifndef TX_TIMER_THREAD_PRIORITY +#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */ +#endif + + +/* Define various constants for the ThreadX 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_MISRA_ENABLE +#ifndef TX_TRACE_TIME_SOURCE +#define TX_TRACE_TIME_SOURCE ((ULONG) (_tx_linux_time_stamp.tv_nsec)); +#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 + + +/* Define the port-specific trace extension to pickup the Windows timer. */ + +#define TX_TRACE_PORT_EXTENSION clock_gettime(CLOCK_REALTIME, &_tx_linux_time_stamp); + + +/* 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 + + +/* Define the Linux-specific initialization code that is expanded in the generic source. */ + +void _tx_initialize_start_interrupts(void); + +#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION _tx_initialize_start_interrupts(); + + +/* 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 pthread_t tx_thread_linux_thread_id; \ + sem_t tx_thread_linux_thread_run_semaphore; \ + UINT tx_thread_linux_suspension_type; \ + UINT tx_thread_linux_int_disabled_flag; + +#define TX_THREAD_EXTENSION_1 VOID *tx_thread_extension_ptr; +#define TX_THREAD_EXTENSION_2 +#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. */ + + +#define TX_THREAD_CREATE_EXTENSION(thread_ptr) +#define TX_THREAD_DELETE_EXTENSION(thread_ptr) +#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) + +struct TX_THREAD_STRUCT; + +/* Define post completion processing for tx_thread_delete, so that the Linux thread resources are properly removed. */ + +void _tx_thread_delete_port_completion(struct TX_THREAD_STRUCT *thread_ptr, UINT tx_saved_posture); +#define TX_THREAD_DELETE_PORT_COMPLETION(thread_ptr) _tx_thread_delete_port_completion(thread_ptr, tx_saved_posture); + +/* Define post completion processing for tx_thread_reset, so that the Linux thread resources are properly removed. */ + +void _tx_thread_reset_port_completion(struct TX_THREAD_STRUCT *thread_ptr, UINT tx_saved_posture); +#define TX_THREAD_RESET_PORT_COMPLETION(thread_ptr) _tx_thread_reset_port_completion(thread_ptr, tx_saved_posture); + +#if __x86_64__ +/* 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 internal timer extension to also hold the thread pointer such that _tx_thread_timeout + can figure out what thread timeout to process. */ + +#define TX_TIMER_INTERNAL_EXTENSION VOID *tx_timer_internal_extension_ptr; + + +/* Define the thread timeout setup logic in _tx_thread_create. */ + +#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 = 0; \ + (t) -> tx_thread_timer.tx_timer_internal_extension_ptr = (VOID *) (t); + + +/* Define the thread timeout pointer setup in _tx_thread_timeout. */ + +#define TX_THREAD_TIMEOUT_POINTER_SETUP(t) (t) = (TX_THREAD *) _tx_timer_expired_timer_ptr -> tx_timer_internal_extension_ptr; +#endif /* __x86_64__ */ + + +/* 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. */ + +UINT _tx_thread_interrupt_disable(void); +VOID _tx_thread_interrupt_restore(UINT previous_posture); + +#define TX_INTERRUPT_SAVE_AREA UINT tx_saved_posture; + +#ifndef TX_LINUX_DEBUG_ENABLE +#define TX_DISABLE tx_saved_posture = _tx_thread_interrupt_disable(); +#define TX_RESTORE _tx_thread_interrupt_restore(tx_saved_posture); +#else +#define TX_DISABLE _tx_linux_debug_entry_insert("DISABLE", __FILE__, __LINE__); \ + tx_saved_posture = _tx_thread_interrupt_disable(); + +#define TX_RESTORE _tx_linux_debug_entry_insert("RESTORE", __FILE__, __LINE__); \ + _tx_thread_interrupt_restore(tx_saved_posture); +#endif /* TX_LINUX_DEBUG_ENABLE */ +#define tx_linux_mutex_lock(p) pthread_mutex_lock(&p) +#define tx_linux_mutex_unlock(p) pthread_mutex_unlock(&p) +#define tx_linux_mutex_recursive_unlock(p) {\ + int _recursive_count = tx_linux_mutex_recursive_count;\ + while(_recursive_count)\ + {\ + pthread_mutex_unlock(&p);\ + _recursive_count--;\ + }\ + } +#define tx_linux_mutex_recursive_count _tx_linux_mutex.__data.__count +#define tx_linux_sem_post(p) tx_linux_mutex_lock(_tx_linux_mutex);\ + sem_post(p);\ + tx_linux_mutex_unlock(_tx_linux_mutex) +#define tx_linux_sem_post_nolock(p) sem_post(p) +#define tx_linux_sem_wait(p) sem_wait(p) + + +/* 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) Microsoft Corporation * ThreadX Linux/gcc Version 6.0 *"; +#else +extern CHAR _tx_version_id[]; +#endif + + +/* Define externals for the Linux port of ThreadX. */ + +extern pthread_mutex_t _tx_linux_mutex; +extern sem_t _tx_linux_semaphore; +extern sem_t _tx_linux_semaphore_no_idle; +extern ULONG _tx_linux_global_int_disabled_flag; +extern struct timespec _tx_linux_time_stamp; +extern __thread int _tx_linux_threadx_thread; + +/* Define functions for linux thread. */ +void _tx_linux_thread_suspend(pthread_t thread_id); +void _tx_linux_thread_resume(pthread_t thread_id); +void _tx_linux_thread_init(); + +#ifndef TX_LINUX_MEMORY_SIZE +#define TX_LINUX_MEMORY_SIZE 64000 +#endif + +#define TX_TIMER_TICKS_PER_SECOND 100UL + +/* Define priorities of pthreads. */ + +#define TX_LINUX_PRIORITY_SCHEDULE (3) +#define TX_LINUX_PRIORITY_ISR (2) +#define TX_LINUX_PRIORITY_USER_THREAD (1) + +#endif + diff --git a/ports/linux/gnu/src/tx_initialize_low_level_sample.c b/ports/linux/gnu/src/tx_initialize_low_level_sample.c new file mode 100644 index 00000000..a4bc0c18 --- /dev/null +++ b/ports/linux/gnu/src/tx_initialize_low_level_sample.c @@ -0,0 +1,443 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include +#include +#include +#include +#include +#include + + +/* Define various Linux objects used by the ThreadX port. */ + +pthread_mutex_t _tx_linux_mutex; +sem_t _tx_linux_semaphore; +sem_t _tx_linux_semaphore_no_idle; +ULONG _tx_linux_global_int_disabled_flag; +struct timespec _tx_linux_time_stamp; +__thread int _tx_linux_threadx_thread = 0; + +/* Define signals for linux thread. */ +#define SUSPEND_SIG SIGUSR1 +#define RESUME_SIG SIGUSR2 + +static sigset_t _tx_linux_thread_wait_mask; +static __thread int _tx_linux_thread_suspended; +static sem_t _tx_linux_thread_timer_wait; +static sem_t _tx_linux_thread_other_wait; + +/* Define simulated timer interrupt. This is done inside a thread, which is + how other interrupts may be defined as well. See code below for an + example. */ + +pthread_t _tx_linux_timer_id; +sem_t _tx_linux_timer_semaphore; +sem_t _tx_linux_isr_semaphore; +void *_tx_linux_timer_interrupt(void *p); + + +#ifdef TX_LINUX_DEBUG_ENABLE + +extern ULONG _tx_thread_system_state; +extern UINT _tx_thread_preempt_disable; +extern TX_THREAD *_tx_thread_current_ptr; +extern TX_THREAD *_tx_thread_execute_ptr; + + +/* Define debug log in order to debug Linux issues with this port. */ + +typedef struct TX_LINUX_DEBUG_ENTRY_STRUCT +{ + char *tx_linux_debug_entry_action; + struct timespec tx_linux_debug_entry_timestamp; + char *tx_linux_debug_entry_file; + unsigned long tx_linux_debug_entry_line; + pthread_mutex_t tx_linux_debug_entry_mutex; + unsigned long tx_linux_debug_entry_int_disabled_flag; + ULONG tx_linux_debug_entry_system_state; + UINT tx_linux_debug_entry_preempt_disable; + TX_THREAD *tx_linux_debug_entry_current_thread; + TX_THREAD *tx_linux_debug_entry_execute_thread; +} TX_LINUX_DEBUG_ENTRY; + + +/* Define the maximum size of the Linux debug array. */ + +#ifndef TX_LINUX_DEBUG_EVENT_SIZE +#define TX_LINUX_DEBUG_EVENT_SIZE 400 +#endif + + +/* Define the circular array of Linux debug entries. */ + +TX_LINUX_DEBUG_ENTRY _tx_linux_debug_entry_array[TX_LINUX_DEBUG_EVENT_SIZE]; + + +/* Define the Linux debug index. */ + +unsigned long _tx_linux_debug_entry_index = 0; + + +/* Now define the debug entry function. */ +void _tx_linux_debug_entry_insert(char *action, char *file, unsigned long line) +{ + +pthread_mutex_t temp_copy; + + /* Save the current critical section value. */ + temp_copy = _tx_linux_mutex; + + /* Lock mutex. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Get the time stamp. */ + clock_gettime(CLOCK_REALTIME, &_tx_linux_time_stamp); + + /* Setup the debub entry. */ + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_action = action; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_timestamp = _tx_linux_time_stamp; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_file = file; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_line = line; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_mutex = temp_copy; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_int_disabled_flag = _tx_linux_global_int_disabled_flag; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_system_state = _tx_thread_system_state; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_preempt_disable = _tx_thread_preempt_disable; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_current_thread = _tx_thread_current_ptr; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_execute_thread = _tx_thread_execute_ptr; + + /* Now move to the next entry. */ + _tx_linux_debug_entry_index++; + + /* Determine if we need to wrap the list. */ + if (_tx_linux_debug_entry_index >= TX_LINUX_DEBUG_EVENT_SIZE) + { + + /* Yes, wrap the list! */ + _tx_linux_debug_entry_index = 0; + } + + /* Unlock mutex. */ + tx_linux_mutex_unlock(_tx_linux_mutex); +} + +#endif + + +/* Define the ThreadX timer interrupt handler. */ + +void _tx_timer_interrupt(void); + + +/* Define other external function references. */ + +VOID _tx_initialize_low_level(VOID); +VOID _tx_thread_context_save(VOID); +VOID _tx_thread_context_restore(VOID); + + +/* Define other external variable references. */ + +extern VOID *_tx_initialize_unused_memory; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Linux/GNU */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* sched_setaffinity */ +/* getpid */ +/* _tx_linux_thread_init */ +/* pthread_setschedparam */ +/* pthread_mutexattr_init */ +/* pthread_mutex_init */ +/* _tx_linux_thread_suspend */ +/* sem_init */ +/* pthread_create */ +/* printf */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_initialize_low_level(VOID) +{ +struct sched_param sp; +pthread_mutexattr_t attr; + +#ifdef TX_LINUX_MULTI_CORE +cpu_set_t mask; + + sched_getaffinity(getpid(), sizeof(mask), &mask); + if (CPU_COUNT(&mask) > 1) + { + + srand((ULONG)pthread_self()); + + /* Limit this ThreadX simulation on Linux to a single core. */ + CPU_ZERO(&mask); + CPU_SET(rand() % get_nprocs(), &mask); + if (sched_setaffinity(getpid(), sizeof(mask), &mask) != 0) + { + + /* Error restricting the process to one core. */ + printf("ThreadX Linux error restricting the process to one core!\n"); + while(1) + { + } + } + } +#endif + + /* Pickup the first available memory address. */ + + /* Save the first available memory address. */ + _tx_initialize_unused_memory = malloc(TX_LINUX_MEMORY_SIZE); + + /* Init Linux thread. */ + _tx_linux_thread_init(); + + /* Set priority and schedual of main thread. */ + sp.sched_priority = TX_LINUX_PRIORITY_SCHEDULE; + pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp); + + /* Create the system critical section. This is used by the + scheduler thread (which is the main thread) to block all + other stuff out. */ + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_tx_linux_mutex, &attr); + sem_init(&_tx_linux_semaphore, 0, 0); +#ifdef TX_LINUX_NO_IDLE_ENABLE + sem_init(&_tx_linux_semaphore_no_idle, 0, 0); +#endif /* TX_LINUX_NO_IDLE_ENABLE */ + + /* Initialize the global interrupt disabled flag. */ + _tx_linux_global_int_disabled_flag = TX_FALSE; + + /* Create semaphore for timer thread. */ + sem_init(&_tx_linux_timer_semaphore, 0, 0); + + /* Create semaphore for ISR thread. */ + sem_init(&_tx_linux_isr_semaphore, 0, 0); + + /* Setup periodic timer interrupt. */ + if(pthread_create(&_tx_linux_timer_id, NULL, _tx_linux_timer_interrupt, NULL)) + { + + /* Error creating the timer interrupt. */ + printf("ThreadX Linux error creating timer interrupt thread!\n"); + while(1) + { + } + } + + /* Otherwise, we have a good thread create. Now set the priority to + a level lower than the system thread but higher than the application + threads. */ + sp.sched_priority = TX_LINUX_PRIORITY_ISR; + pthread_setschedparam(_tx_linux_timer_id, SCHED_FIFO, &sp); + + /* Done, return to caller. */ +} + + +/* This routine is called after initialization is complete in order to start + all interrupt threads. Interrupt threads in addition to the timer may + be added to this routine as well. */ + +void _tx_initialize_start_interrupts(void) +{ + + /* Kick the timer thread off to generate the ThreadX periodic interrupt + source. */ + tx_linux_sem_post(&_tx_linux_timer_semaphore); +} + + +/* Define the ThreadX system timer interrupt. Other interrupts may be simulated + in a similar way. */ + +void *_tx_linux_timer_interrupt(void *p) +{ +struct timespec ts; +long timer_periodic_nsec; +int err; + + /* Calculate periodic timer. */ + timer_periodic_nsec = 1000000000 / TX_TIMER_TICKS_PER_SECOND; + nice(10); + + /* Wait startup semaphore. */ + tx_linux_sem_wait(&_tx_linux_timer_semaphore); + + while(1) + { + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += timer_periodic_nsec; + if (ts.tv_nsec > 1000000000) + { + ts.tv_nsec -= 1000000000; + ts.tv_sec++; + } + do + { + if (sem_timedwait(&_tx_linux_timer_semaphore, &ts) == 0) + { + break; + } + err = errno; + } while (err != ETIMEDOUT); + + /* Call ThreadX context save for interrupt preparation. */ + _tx_thread_context_save(); + + /* Call trace ISR enter event insert. */ + _tx_trace_isr_enter_insert(0); + + /* Call the ThreadX system timer interrupt processing. */ + _tx_timer_interrupt(); + + /* Call trace ISR exit event insert. */ + _tx_trace_isr_exit_insert(0); + + /* Call ThreadX context restore for interrupt completion. */ + _tx_thread_context_restore(); + +#ifdef TX_LINUX_NO_IDLE_ENABLE + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Make sure semaphore is 0. */ + while(!sem_trywait(&_tx_linux_semaphore_no_idle)); + + /* Wakeup the system thread by setting the system semaphore. */ + tx_linux_sem_post(&_tx_linux_semaphore_no_idle); + + tx_linux_mutex_unlock(_tx_linux_mutex); +#endif /* TX_LINUX_NO_IDLE_ENABLE */ + } +} + +/* Define functions for linux thread. */ +void _tx_linux_thread_resume_handler(int sig) +{ +} + +void _tx_linux_thread_suspend_handler(int sig) +{ + if(pthread_equal(pthread_self(), _tx_linux_timer_id)) + tx_linux_sem_post_nolock(&_tx_linux_thread_timer_wait); + else + tx_linux_sem_post_nolock(&_tx_linux_thread_other_wait); + + if(_tx_linux_thread_suspended) + return; + + _tx_linux_thread_suspended = 1; + sigsuspend(&_tx_linux_thread_wait_mask); + _tx_linux_thread_suspended = 0; +} + +void _tx_linux_thread_suspend(pthread_t thread_id) +{ + + /* Send signal. */ + tx_linux_mutex_lock(_tx_linux_mutex); + pthread_kill(thread_id, SUSPEND_SIG); + tx_linux_mutex_unlock(_tx_linux_mutex); + + /* Wait until signal is received. */ + if(pthread_equal(thread_id, _tx_linux_timer_id)) + tx_linux_sem_wait(&_tx_linux_thread_timer_wait); + else + tx_linux_sem_wait(&_tx_linux_thread_other_wait); +} + +void _tx_linux_thread_resume(pthread_t thread_id) +{ + + /* Send signal. */ + tx_linux_mutex_lock(_tx_linux_mutex); + pthread_kill(thread_id, RESUME_SIG); + tx_linux_mutex_unlock(_tx_linux_mutex); +} + +void _tx_linux_thread_init() +{ +struct sigaction sa; + + /* Create semaphore for linux thread. */ + sem_init(&_tx_linux_thread_timer_wait, 0, 0); + sem_init(&_tx_linux_thread_other_wait, 0, 0); + + sigfillset(&_tx_linux_thread_wait_mask); + sigdelset(&_tx_linux_thread_wait_mask, RESUME_SIG); + + sigfillset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = _tx_linux_thread_resume_handler; + sigaction(RESUME_SIG, &sa, NULL); + + sa.sa_handler = _tx_linux_thread_suspend_handler; + sigaction(SUSPEND_SIG, &sa, NULL); +} + + diff --git a/ports/linux/gnu/src/tx_thread_context_restore.c b/ports/linux/gnu/src/tx_thread_context_restore.c new file mode 100644 index 00000000..69a16b18 --- /dev/null +++ b/ports/linux/gnu/src/tx_thread_context_restore.c @@ -0,0 +1,163 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" + +extern sem_t _tx_linux_isr_semaphore; +UINT _tx_linux_timer_waiting = 0; +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore Linux/GNU */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* 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_linux_debug_entry_insert */ +/* tx_linux_mutex_lock */ +/* sem_trywait */ +/* tx_linux_sem_post */ +/* tx_linux_sem_wait */ +/* _tx_linux_thread_resume */ +/* tx_linux_mutex_recursive_unlock */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_thread_context_restore(VOID) +{ + + /* Debug entry. */ + _tx_linux_debug_entry_insert("CONTEXT_RESTORE", __FILE__, __LINE__); + + /* Lock mutex to ensure other threads are not playing with + the core ThreadX data structures. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Decrement the nested interrupt count. */ + _tx_thread_system_state--; + + /* Determine if this is the first nested interrupt and if a ThreadX + application thread was running at the time. */ + if ((!_tx_thread_system_state) && (_tx_thread_current_ptr)) + { + + /* Yes, this is the first and last interrupt processed. */ + + /* Check to see if preemption is required. */ + if ((_tx_thread_preempt_disable == 0) && (_tx_thread_current_ptr != _tx_thread_execute_ptr)) + { + + /* Preempt the running application thread. We don't need to suspend the + application thread since that is done in the context save processing. */ + + /* Indicate that this thread was suspended asynchronously. */ + _tx_thread_current_ptr -> tx_thread_linux_suspension_type = 1; + + /* Save the remaining time-slice and disable it. */ + if (_tx_timer_time_slice) + { + + _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + _tx_timer_time_slice = 0; + } + + /* Clear the current thread pointer. */ + _tx_thread_current_ptr = TX_NULL; + + /* Make sure semaphore is 0. */ + while(!sem_trywait(&_tx_linux_semaphore)); + + /* Indicate it is in timer ISR. */ + _tx_linux_timer_waiting = 1; + + /* Wakeup the system thread by setting the system semaphore. */ + tx_linux_sem_post(&_tx_linux_semaphore); + + if(_tx_thread_execute_ptr) + { + if(_tx_thread_execute_ptr -> tx_thread_linux_suspension_type == 0) + { + + /* Unlock linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + + /* Wait until TX_THREAD start running. */ + tx_linux_sem_wait(&_tx_linux_isr_semaphore); + + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Make sure semaphore is 0. */ + while(!sem_trywait(&_tx_linux_isr_semaphore)); + } + } + + /* Indicate it is not in timer ISR. */ + _tx_linux_timer_waiting = 0; + } + else + { + + /* Since preemption is not required, resume the interrupted thread. */ + _tx_linux_thread_resume(_tx_thread_current_ptr -> tx_thread_linux_thread_id); + } + } + + /* Unlock linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); +} + diff --git a/ports/linux/gnu/src/tx_thread_context_save.c b/ports/linux/gnu/src/tx_thread_context_save.c new file mode 100644 index 00000000..90ff05f1 --- /dev/null +++ b/ports/linux/gnu/src/tx_thread_context_save.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** 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_context_save Linux/GNU */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* 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 */ +/* */ +/* _tx_linux_debug_entry_insert */ +/* tx_linux_mutex_lock */ +/* _tx_linux_thread_suspend */ +/* tx_linux_mutex_unlock */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_thread_context_save(VOID) +{ + + /* Debug entry. */ + _tx_linux_debug_entry_insert("CONTEXT_SAVE", __FILE__, __LINE__); + + /* Lock mutex to ensure other threads are not playing with + the core ThreadX data structures. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* If an application thread is running, suspend it to simulate preemption. */ + if ((_tx_thread_current_ptr) && (_tx_thread_system_state == 0)) + { + + /* Debug entry. */ + _tx_linux_debug_entry_insert("CONTEXT_SAVE-suspend_thread", __FILE__, __LINE__); + + /* Yes, this is the first interrupt and an application thread is running... + suspend it! */ + _tx_linux_thread_suspend(_tx_thread_current_ptr -> tx_thread_linux_thread_id); + + /* Indicate that this thread was suspended asynchronously. */ + _tx_thread_current_ptr -> tx_thread_linux_suspension_type = 1; + } + + /* Increment the nested interrupt condition. */ + _tx_thread_system_state++; + + /* Unlock linux mutex. */ + tx_linux_mutex_unlock(_tx_linux_mutex); +} + diff --git a/ports/linux/gnu/src/tx_thread_interrupt_control.c b/ports/linux/gnu/src/tx_thread_interrupt_control.c new file mode 100644 index 00000000..f1e71d2c --- /dev/null +++ b/ports/linux/gnu/src/tx_thread_interrupt_control.c @@ -0,0 +1,183 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" + +/* Define small routines used for the TX_DISABLE/TX_RESTORE macros. */ + +UINT _tx_thread_interrupt_disable(void) +{ + +UINT previous_value; + + + previous_value = _tx_thread_interrupt_control(TX_INT_DISABLE); + return(previous_value); +} + + +VOID _tx_thread_interrupt_restore(UINT previous_posture) +{ + + previous_posture = _tx_thread_interrupt_control(previous_posture); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control Linux/GNU */ +/* 6.0 */ +/* 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 */ +/* */ +/* tx_linux_mutex_lock */ +/* pthread_self */ +/* pthread_getschedparam */ +/* tx_linux_mutex_recursive_unlock */ +/* pthread_exit */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _tx_thread_interrupt_control(UINT new_posture) +{ + +UINT old_posture; +TX_THREAD *thread_ptr; +pthread_t thread_id; +int exit_code = 0; + + + /* Lock Linux mutex. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Pickup the id of the current thread. */ + thread_id = pthread_self(); + + /* Pickup the current thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Determine if this is a thread and it does not + match the current thread pointer. */ + if ((_tx_linux_threadx_thread) && + ((!thread_ptr) || (!pthread_equal(thread_ptr -> tx_thread_linux_thread_id, thread_id)))) + { + + /* This indicates the Linux thread was actually terminated by ThreadX is only + being allowed to run in order to cleanup its resources. */ + /* Unlock linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + pthread_exit((void *)&exit_code); + } + + /* Determine the current interrupt lockout condition. */ + if (tx_linux_mutex_recursive_count == 1) + { + + /* Interrupts are enabled. */ + old_posture = TX_INT_ENABLE; + } + else + { + + /* Interrupts are disabled. */ + old_posture = TX_INT_DISABLE; + } + + /* First, determine if this call is from a non-thread. */ + if (_tx_thread_system_state) + { + + /* Determine how to apply the new posture. */ + if (new_posture == TX_INT_ENABLE) + { + + /* Clear the disabled flag. */ + _tx_linux_global_int_disabled_flag = TX_FALSE; + + /* Determine if the critical section is locked. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + } + else if (new_posture == TX_INT_DISABLE) + { + + /* Set the disabled flag. */ + _tx_linux_global_int_disabled_flag = TX_TRUE; + } + } + else if (thread_ptr) + { + + /* Determine how to apply the new posture. */ + if (new_posture == TX_INT_ENABLE) + { + + /* Clear the disabled flag. */ + _tx_thread_current_ptr -> tx_thread_linux_int_disabled_flag = TX_FALSE; + + /* Determine if the critical section is locked. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + } + else if (new_posture == TX_INT_DISABLE) + { + + /* Set the disabled flag. */ + _tx_thread_current_ptr -> tx_thread_linux_int_disabled_flag = TX_TRUE; + } + } + + /* Return the previous interrupt disable posture. */ + return(old_posture); +} + diff --git a/ports/linux/gnu/src/tx_thread_schedule.c b/ports/linux/gnu/src/tx_thread_schedule.c new file mode 100644 index 00000000..2bc91228 --- /dev/null +++ b/ports/linux/gnu/src/tx_thread_schedule.c @@ -0,0 +1,264 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include +#include + +extern sem_t _tx_linux_timer_semaphore; +extern sem_t _tx_linux_isr_semaphore; +extern UINT _tx_linux_timer_waiting; +extern pthread_t _tx_linux_timer_id; +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule Linux/GNU */ +/* 6.0 */ +/* 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 */ +/* */ +/* tx_linux_mutex_lock */ +/* tx_linux_mutex_unlock */ +/* _tx_linux_debug_entry_insert */ +/* _tx_linux_thread_resume */ +/* tx_linux_sem_post */ +/* sem_trywait */ +/* tx_linux_sem_wait */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_thread_schedule(VOID) +{ +struct timespec ts; + + /* Set timer. */ + ts.tv_sec = 0; + ts.tv_nsec = 200000; + + /* Loop forever. */ + while(1) + { + + /* Wait for a thread to execute and all ISRs to complete. */ + while(1) + { + + /* Lock Linux mutex. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Determine if there is a thread ready to execute AND all ISRs + are complete. */ + if ((_tx_thread_execute_ptr != TX_NULL) && (_tx_thread_system_state == 0)) + { + + /* Get out of this loop and schedule the thread! */ + break; + } + else + { + + /* Unlock linux mutex. */ + tx_linux_mutex_unlock(_tx_linux_mutex); + + /* Don't waste all the processor time here in the master thread... */ +#ifdef TX_LINUX_NO_IDLE_ENABLE + while(!sem_trywait(&_tx_linux_timer_semaphore)); + tx_linux_sem_post(&_tx_linux_timer_semaphore); + /*nanosleep(&ts, &ts);*/ + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += 200000; + if (ts.tv_nsec > 1000000000) + { + ts.tv_nsec -= 1000000000; + ts.tv_sec++; + } + sem_timedwait(&_tx_linux_semaphore_no_idle, &ts); +#else + nanosleep(&ts, &ts); +#endif /* TX_LINUX_NO_IDLE_ENABLE */ + } + } + + /* Yes! We have a thread to execute. Note that the critical section is already + active from the scheduling loop above. */ + + /* Setup the current thread pointer. */ + _tx_thread_current_ptr = _tx_thread_execute_ptr; + + /* Increment the run count for this thread. */ + _tx_thread_current_ptr -> tx_thread_run_count++; + + /* Setup time-slice, if present. */ + _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; + + /* Determine how the thread was suspended. */ + if (_tx_thread_current_ptr -> tx_thread_linux_suspension_type) + { + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SCHEDULE-resume_thread", __FILE__, __LINE__); + + /* Pseudo interrupt suspension. The thread is not waiting on + its run semaphore. */ + _tx_linux_thread_resume(_tx_thread_current_ptr -> tx_thread_linux_thread_id); + } + else + { + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SCHEDULE-release_sem", __FILE__, __LINE__); + + /* Make sure semaphore is 0. */ + while(!sem_trywait(&_tx_thread_current_ptr -> tx_thread_linux_thread_run_semaphore)); + + /* Let the thread run again by releasing its run semaphore. */ + tx_linux_sem_post(&_tx_thread_current_ptr -> tx_thread_linux_thread_run_semaphore); + + /* Block timer ISR. */ + if(_tx_linux_timer_waiting) + { + + /* It is woken up by timer ISR. */ + /* Let ThreadX thread wake up first. */ + tx_linux_sem_wait(&_tx_linux_semaphore); + + /* Wake up timer ISR. */ + tx_linux_sem_post_nolock(&_tx_linux_isr_semaphore); + } + else + { + + /* It is woken up by TX_THREAD. */ + /* Suspend timer thread and let ThreadX thread wake up first. */ + _tx_linux_thread_suspend(_tx_linux_timer_id); + tx_linux_sem_wait(&_tx_linux_semaphore); + _tx_linux_thread_resume(_tx_linux_timer_id); + + } + } + + /* Unlock linux mutex. */ + tx_linux_mutex_unlock(_tx_linux_mutex); + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SCHEDULE-self_suspend_sem", __FILE__, __LINE__); + + /* Now suspend the main thread so the application thread can run. */ + tx_linux_sem_wait(&_tx_linux_semaphore); + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SCHEDULE-wake_up", __FILE__, __LINE__); + + } +} + +void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_saved_posture) +{ +INT linux_status; +sem_t *threadrunsemaphore; +pthread_t thread_id; +struct timespec ts; + + thread_id = thread_ptr -> tx_thread_linux_thread_id; + threadrunsemaphore = &(thread_ptr -> tx_thread_linux_thread_run_semaphore); + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + TX_RESTORE + do + { + linux_status = pthread_cancel(thread_id); + if(linux_status != EAGAIN) + { + break; + } + _tx_linux_thread_resume(thread_id); + tx_linux_sem_post(threadrunsemaphore); + nanosleep(&ts, &ts); + } while (1); + pthread_join(thread_id, NULL); + sem_destroy(threadrunsemaphore); + TX_DISABLE +} + +void _tx_thread_reset_port_completion(TX_THREAD *thread_ptr, UINT tx_saved_posture) +{ +INT linux_status; +sem_t *threadrunsemaphore; +pthread_t thread_id; +struct timespec ts; + + thread_id = thread_ptr -> tx_thread_linux_thread_id; + threadrunsemaphore = &(thread_ptr -> tx_thread_linux_thread_run_semaphore); + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + TX_RESTORE + do + { + linux_status = pthread_cancel(thread_id); + if(linux_status != EAGAIN) + { + break; + } + _tx_linux_thread_resume(thread_id); + tx_linux_sem_post(threadrunsemaphore); + nanosleep(&ts, &ts); + } while (1); + pthread_join(thread_id, NULL); + sem_destroy(threadrunsemaphore); + TX_DISABLE +} diff --git a/ports/linux/gnu/src/tx_thread_stack_build.c b/ports/linux/gnu/src/tx_thread_stack_build.c new file mode 100644 index 00000000..22f49ead --- /dev/null +++ b/ports/linux/gnu/src/tx_thread_stack_build.c @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include +#include + + +/* Prototype for new thread entry function. */ + +void *_tx_linux_thread_entry(void *ptr); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build Linux/GNU */ +/* 6.0 */ +/* 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 */ +/* */ +/* pthread_create */ +/* pthread_setschedparam */ +/* _tx_linux_thread_suspend */ +/* sem_init */ +/* printf */ +/* _tx_linux_thread_resume */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* _tx_thread_reset Reset thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +{ +struct sched_param sp; + + /* Create the run semaphore for the thread. This will allow the scheduler + control over when the thread actually runs. */ + if(sem_init(&thread_ptr -> tx_thread_linux_thread_run_semaphore, 0, 0)) + { + + /* Display an error message. */ + printf("ThreadX Linux error creating thread running semaphore!\n"); + while(1) + { + } + } + + /* Create a Linux thread for the application thread. */ + if(pthread_create(&thread_ptr -> tx_thread_linux_thread_id, NULL, _tx_linux_thread_entry, thread_ptr)) + { + + /* Display an error message. */ + printf("ThreadX Linux error creating thread!\n"); + while(1) + { + } + } + + /* Otherwise, we have a good thread create. */ + sp.sched_priority = TX_LINUX_PRIORITY_USER_THREAD; + pthread_setschedparam(thread_ptr -> tx_thread_linux_thread_id, SCHED_FIFO, &sp); + + /* Setup the thread suspension type to solicited thread suspension. + Pseudo interrupt handlers will suspend with this field set to 1. */ + thread_ptr -> tx_thread_linux_suspension_type = 0; + + /* Clear the disabled count that will keep track of the + tx_interrupt_control nesting. */ + thread_ptr -> tx_thread_linux_int_disabled_flag = 0; + + /* Setup a fake thread stack pointer. */ + thread_ptr -> tx_thread_stack_ptr = (VOID *) (((CHAR *) thread_ptr -> tx_thread_stack_end) - 8); + + /* Clear the first word of the stack. */ + *(((ULONG *) thread_ptr -> tx_thread_stack_ptr) - 1) = 0; +} + + +void *_tx_linux_thread_entry(void *ptr) +{ + +TX_THREAD *thread_ptr; + + /* Pickup the current thread pointer. */ + thread_ptr = (TX_THREAD *) ptr; + _tx_linux_threadx_thread = 1; + nice(20); + + /* Now suspend the thread initially. If the thread has already + been scheduled, this will return immediately. */ + tx_linux_sem_wait(&thread_ptr -> tx_thread_linux_thread_run_semaphore); + tx_linux_sem_post_nolock(&_tx_linux_semaphore); + + /* Call ThreadX thread entry point. */ + _tx_thread_shell_entry(); + + return EXIT_SUCCESS; +} + diff --git a/ports/linux/gnu/src/tx_thread_system_return.c b/ports/linux/gnu/src/tx_thread_system_return.c new file mode 100644 index 00000000..e7db8750 --- /dev/null +++ b/ports/linux/gnu/src/tx_thread_system_return.c @@ -0,0 +1,207 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return Linux/GNU */ +/* 6.0 */ +/* 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 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_linux_debug_entry_insert */ +/* tx_linux_mutex_lock */ +/* pthread_self */ +/* pthread_getschedparam */ +/* pthread_equal */ +/* tx_linux_mutex_recursive_unlock */ +/* tx_linux_mutex_unlock */ +/* pthread_exit */ +/* tx_linux_sem_post */ +/* sem_trywait */ +/* tx_linux_sem_wait */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_thread_system_return(VOID) +{ + +TX_THREAD *temp_thread_ptr; +sem_t *temp_run_semaphore; +UINT temp_thread_state; +pthread_t thread_id; +int exit_code = 0; + + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SYSTEM_RETURN", __FILE__, __LINE__); + + /* Lock Linux mutex. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* First, determine if the thread was terminated. */ + + /* Pickup the id of the current thread. */ + thread_id = pthread_self(); + + /* Pickup the current thread pointer. */ + temp_thread_ptr = _tx_thread_current_ptr; + + /* Determine if this is a thread (0) and it does not + match the current thread pointer. */ + if ((_tx_linux_threadx_thread) && + ((!temp_thread_ptr) || (!pthread_equal(temp_thread_ptr -> tx_thread_linux_thread_id, thread_id)))) + { + + /* This indicates the Linux thread was actually terminated by ThreadX is only + being allowed to run in order to cleanup its resources. */ + /* Unlock linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + pthread_exit((void *)&exit_code); + } + + /* Determine if the time-slice is active. */ + if (_tx_timer_time_slice) + { + + /* Preserve current remaining time-slice for the thread and clear the current time-slice. */ + temp_thread_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + _tx_timer_time_slice = 0; + } + + /* Save the run semaphore into a temporary variable as well. */ + temp_run_semaphore = &temp_thread_ptr -> tx_thread_linux_thread_run_semaphore; + + /* Pickup the current thread state. */ + temp_thread_state = temp_thread_ptr -> tx_thread_state; + + /* Setup the suspension type for this thread. */ + temp_thread_ptr -> tx_thread_linux_suspension_type = 0; + + /* Set the current thread pointer to NULL. */ + _tx_thread_current_ptr = TX_NULL; + + /* Unlock Linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SYSTEM_RETURN-release_sem", __FILE__, __LINE__); + + /* Make sure semaphore is 0. */ + while(!sem_trywait(&_tx_linux_semaphore)); + + /* Release the semaphore that the main scheduling thread is waiting + on. Note that the main scheduling algorithm will take care of + setting the current thread pointer to NULL. */ + tx_linux_sem_post(&_tx_linux_semaphore); + + /* Determine if the thread was self-terminating. */ + if (temp_thread_state == TX_TERMINATED) + { + + /* Exit the thread instead of waiting on the semaphore! */ + pthread_exit((void *)&exit_code); + } + + /* Wait on the run semaphore for this thread. This won't get set again + until the thread is scheduled. */ + tx_linux_sem_wait(temp_run_semaphore); + tx_linux_sem_post_nolock(&_tx_linux_semaphore); + + /* Lock Linux mutex. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SYSTEM_RETURN-wake_up", __FILE__, __LINE__); + + /* Determine if the thread was terminated. */ + + /* Pickup the current thread pointer. */ + temp_thread_ptr = _tx_thread_current_ptr; + + /* Determine if this is a thread and it does not + match the current thread pointer. */ + if ((_tx_linux_threadx_thread) && + ((!temp_thread_ptr) || (!pthread_equal(temp_thread_ptr -> tx_thread_linux_thread_id, thread_id)))) + { + + /* Unlock Linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + + /* This indicates the Linux thread was actually terminated by ThreadX and is only + being allowed to run in order to cleanup its resources. */ + pthread_exit((void *)&exit_code); + } + + /* Now determine if the application thread last had interrupts disabled. */ + + /* Determine if this thread had interrupts disabled. */ + if (!_tx_thread_current_ptr -> tx_thread_linux_int_disabled_flag) + { + + /* Unlock Linux mutex. */ + tx_linux_mutex_recursive_unlock(_tx_linux_mutex); + } + + /* Debug entry. */ + _tx_linux_debug_entry_insert("SYSTEM_RETURN-finish", __FILE__, __LINE__); +} + diff --git a/ports/linux/gnu/src/tx_timer_interrupt.c b/ports/linux/gnu/src/tx_timer_interrupt.c new file mode 100644 index 00000000..5461b302 --- /dev/null +++ b/ports/linux/gnu/src/tx_timer_interrupt.c @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt Linux/GNU */ +/* 6.0 */ +/* 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_linux_debug_entry_insert */ +/* tx_linux_mutex_lock */ +/* tx_linux_mutex_unlock */ +/* _tx_timer_expiration_process */ +/* _tx_thread_time_slice */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_timer_interrupt(VOID) +{ + + /* Debug entry. */ + _tx_linux_debug_entry_insert("TIMER INTERRUPT", __FILE__, __LINE__); + + /* Lock mutex to ensure other threads are not playing with + the core ThreadX data structures. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Increment the system clock. */ + _tx_timer_system_clock++; + + /* Test for time-slice expiration. */ + if (_tx_timer_time_slice) + { + + /* Decrement the time_slice. */ + _tx_timer_time_slice--; + + /* Check for expiration. */ + if (_tx_timer_time_slice == 0) + { + + /* Set the time-slice expired flag. */ + _tx_timer_expired_time_slice = TX_TRUE; + } + } + + /* Test for timer expiration. */ + if (*_tx_timer_current_ptr) + { + + /* Set expiration flag. */ + _tx_timer_expired = TX_TRUE; + } + else + { + + /* No timer expired, increment the timer pointer. */ + _tx_timer_current_ptr++; + + /* Check for wrap-around. */ + if (_tx_timer_current_ptr == _tx_timer_list_end) + { + + /* Wrap to beginning of list. */ + _tx_timer_current_ptr = _tx_timer_list_start; + } + } + + /* See if anything has expired. */ + if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + { + + /* Did a timer expire? */ + if (_tx_timer_expired) + { + + /* Process timer expiration. */ + _tx_timer_expiration_process(); + } + + /* Did time slice expire? */ + if (_tx_timer_expired_time_slice) + { + + /* Time slice interrupted thread. */ + _tx_thread_time_slice(); + } + } + + /* Unlock linux mutex. */ + tx_linux_mutex_unlock(_tx_linux_mutex); +} + diff --git a/ports/win32/gnu/CMakeLists.txt b/ports/win32/gnu/CMakeLists.txt new file mode 100644 index 00000000..ecc3683d --- /dev/null +++ b/ports/win32/gnu/CMakeLists.txt @@ -0,0 +1,18 @@ +target_sources(${PROJECT_NAME} + PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/tx_initialize_low_level.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_restore.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_context_save.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_control.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_schedule.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_stack_build.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_system_return.c + ${CMAKE_CURRENT_LIST_DIR}/src/tx_timer_interrupt.c + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) diff --git a/samples/demo_threadx.c b/samples/demo_threadx.c new file mode 100644 index 00000000..597f373c --- /dev/null +++ b/samples/demo_threadx.c @@ -0,0 +1,370 @@ +/* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight + threads of different priorities, using a message queue, semaphore, mutex, event flags group, + byte pool, and block pool. */ + +#include "tx_api.h" + +#define DEMO_STACK_SIZE 1024 +#define DEMO_BYTE_POOL_SIZE 9120 +#define DEMO_BLOCK_POOL_SIZE 100 +#define DEMO_QUEUE_SIZE 100 + + +/* Define the ThreadX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +TX_THREAD thread_2; +TX_THREAD thread_3; +TX_THREAD thread_4; +TX_THREAD thread_5; +TX_THREAD thread_6; +TX_THREAD thread_7; +TX_QUEUE queue_0; +TX_SEMAPHORE semaphore_0; +TX_MUTEX mutex_0; +TX_EVENT_FLAGS_GROUP event_flags_0; +TX_BYTE_POOL byte_pool_0; +TX_BLOCK_POOL block_pool_0; +UCHAR memory_area[DEMO_BYTE_POOL_SIZE]; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG thread_1_messages_sent; +ULONG thread_2_counter; +ULONG thread_2_messages_received; +ULONG thread_3_counter; +ULONG thread_4_counter; +ULONG thread_5_counter; +ULONG thread_6_counter; +ULONG thread_7_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_2_entry(ULONG thread_input); +void thread_3_and_4_entry(ULONG thread_input); +void thread_5_entry(ULONG thread_input); +void thread_6_and_7_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer = TX_NULL; + + + /* Create a byte memory pool from which to allocate the thread stacks. */ + tx_byte_pool_create(&byte_pool_0, "byte pool 0", memory_area, DEMO_BYTE_POOL_SIZE); + + /* Put system definition stuff in here, e.g. thread creates and other assorted + create information. */ + + /* Allocate the stack for thread 0. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); + + + /* Allocate the stack for thread 1. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 1 and 2. These threads pass information through a ThreadX + message queue. It is also interesting to note that these threads have a time + slice. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 2. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2, + pointer, DEMO_STACK_SIZE, + 16, 16, 4, TX_AUTO_START); + + /* Allocate the stack for thread 3. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore. + An interesting thing here is that both threads share the same instruction area. */ + tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 4. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 5. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create thread 5. This thread simply pends on an event flag which will be set + by thread_0. */ + tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 6. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */ + tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the stack for thread 7. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT); + + tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + /* Allocate the message queue. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT); + + /* Create the message queue shared by threads 1 and 2. */ + tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG)); + + /* Create the semaphore used by threads 3 and 4. */ + tx_semaphore_create(&semaphore_0, "semaphore 0", 1); + + /* Create the event flags group used by threads 1 and 5. */ + tx_event_flags_create(&event_flags_0, "event flags 0"); + + /* Create the mutex used by thread 6 and 7 without priority inheritance. */ + tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT); + + /* Allocate the memory for a small block pool. */ + tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT); + + /* Create a block memory pool to allocate a message buffer from. */ + tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE); + + /* Allocate a block and release the block memory. */ + tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT); + + /* Release the block back to the pool. */ + tx_block_release(pointer); +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sits in while-forever-sleep loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_0_counter++; + + /* Sleep for 10 ticks. */ + tx_thread_sleep(10); + + /* Set event flag 0 to wakeup thread 5. */ + status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; + + + /* This thread simply sends messages to a queue shared by thread 2. */ + while(1) + { + + /* Increment the thread counter. */ + thread_1_counter++; + + /* Send message to queue 0. */ + status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER); + + /* Check completion status. */ + if (status != TX_SUCCESS) + break; + + /* Increment the message sent. */ + thread_1_messages_sent++; + } +} + + +void thread_2_entry(ULONG thread_input) +{ + +ULONG received_message; +UINT status; + + /* This thread retrieves messages placed on the queue by thread 1. */ + while(1) + { + + /* Increment the thread counter. */ + thread_2_counter++; + + /* Retrieve a message from the queue. */ + status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER); + + /* Check completion status and make sure the message is what we + expected. */ + if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received)) + break; + + /* Otherwise, all is okay. Increment the received message count. */ + thread_2_messages_received++; + } +} + + +void thread_3_and_4_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 3 and thread 4. As the loop + below shows, these function compete for ownership of semaphore_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 3) + thread_3_counter++; + else + thread_4_counter++; + + /* Get the semaphore with suspension. */ + status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the semaphore. */ + tx_thread_sleep(2); + + /* Release the semaphore. */ + status = tx_semaphore_put(&semaphore_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +} + + +void thread_5_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_flags; + + + /* This thread simply waits for an event in a forever loop. */ + while(1) + { + + /* Increment the thread counter. */ + thread_5_counter++; + + /* Wait for event flag 0. */ + status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR, + &actual_flags, TX_WAIT_FOREVER); + + /* Check status. */ + if ((status != TX_SUCCESS) || (actual_flags != 0x1)) + break; + } +} + + +void thread_6_and_7_entry(ULONG thread_input) +{ + +UINT status; + + + /* This function is executed from thread 6 and thread 7. As the loop + below shows, these function compete for ownership of mutex_0. */ + while(1) + { + + /* Increment the thread counter. */ + if (thread_input == 6) + thread_6_counter++; + else + thread_7_counter++; + + /* Get the mutex with suspension. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Get the mutex again with suspension. This shows + that an owning thread may retrieve the mutex it + owns multiple times. */ + status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Sleep for 2 ticks to hold the mutex. */ + tx_thread_sleep(2); + + /* Release the mutex. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + + /* Release the mutex again. This will actually + release ownership since it was obtained twice. */ + status = tx_mutex_put(&mutex_0); + + /* Check status. */ + if (status != TX_SUCCESS) + break; + } +}