commit 852421fda03a7722d7adb45b187235cd66fa264e Author: PProvost Date: Mon May 11 08:55:07 2020 -0600 Initial commit 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 00000000..90160770 Binary files /dev/null and b/docs/ThreadX_User_Guide.pdf differ diff --git a/ports/cortex_m0/gnu/CMakeLists.txt b/ports/cortex_m0/gnu/CMakeLists.txt new file mode 100644 index 00000000..0e3cc8ec --- /dev/null +++ b/ports/cortex_m0/gnu/CMakeLists.txt @@ -0,0 +1,21 @@ + +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_interrupt_disable.S + ${CMAKE_CURRENT_LIST_DIR}/src/tx_thread_interrupt_restore.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_m0/gnu/inc/tx_port.h b/ports/cortex_m0/gnu/inc/tx_port.h new file mode 100644 index 00000000..2f798966 --- /dev/null +++ b/ports/cortex_m0/gnu/inc/tx_port.h @@ -0,0 +1,371 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the 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-M0/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 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; + } +}