summaryrefslogtreecommitdiff
path: root/ports/linux/gnu
diff options
context:
space:
mode:
authortameraw <[email protected]>2020-07-16 14:32:40 -0700
committertameraw <[email protected]>2020-07-16 14:32:40 -0700
commit2c35570dc9ced8690ea269d1efab201c361fea98 (patch)
treea950c056346ab9a2260ba92a6be8ee3dd91ab7b6 /ports/linux/gnu
parentf8e91d47625881614fe28efbcd43470922590d42 (diff)
updated to 6.0.1 and added additional processors/toolchains
Diffstat (limited to 'ports/linux/gnu')
-rw-r--r--ports/linux/gnu/example_build/file_list.mk201
-rw-r--r--ports/linux/gnu/example_build/sample_threadx.c380
-rw-r--r--ports/linux/gnu/inc/tx_port.h575
-rw-r--r--ports/linux/gnu/readme_threadx.txt155
-rw-r--r--ports/linux/gnu/src/tx_initialize_low_level.c443
-rw-r--r--ports/linux/gnu/src/tx_thread_context_restore.c163
-rw-r--r--ports/linux/gnu/src/tx_thread_context_save.c107
-rw-r--r--ports/linux/gnu/src/tx_thread_interrupt_control.c183
-rw-r--r--ports/linux/gnu/src/tx_thread_schedule.c264
-rw-r--r--ports/linux/gnu/src/tx_thread_stack_build.c153
-rw-r--r--ports/linux/gnu/src/tx_thread_system_return.c207
-rw-r--r--ports/linux/gnu/src/tx_timer_interrupt.c153
12 files changed, 2984 insertions, 0 deletions
diff --git a/ports/linux/gnu/example_build/file_list.mk b/ports/linux/gnu/example_build/file_list.mk
new file mode 100644
index 00000000..73497590
--- /dev/null
+++ b/ports/linux/gnu/example_build/file_list.mk
@@ -0,0 +1,201 @@
+LINUX_SRCS = \
+tx_initialize_low_level.c \
+tx_thread_context_restore.c \
+tx_thread_context_save.c \
+tx_thread_interrupt_control.c \
+tx_thread_schedule.c \
+tx_thread_stack_build.c \
+tx_thread_system_return.c \
+tx_timer_interrupt.c \
+
+LINUX_OBJS = $(LINUX_SRCS:%.c=.tmp/%.o)
+
+
+GENERIC_SRCS = \
+tx_block_allocate.c \
+tx_block_pool_cleanup.c \
+tx_block_pool_create.c \
+tx_block_pool_delete.c \
+tx_block_pool_info_get.c \
+tx_block_pool_initialize.c \
+tx_block_pool_performance_info_get.c \
+tx_block_pool_performance_system_info_get.c \
+tx_block_pool_prioritize.c \
+tx_block_release.c \
+tx_byte_allocate.c \
+tx_byte_pool_cleanup.c \
+tx_byte_pool_create.c \
+tx_byte_pool_delete.c \
+tx_byte_pool_info_get.c \
+tx_byte_pool_initialize.c \
+tx_byte_pool_performance_info_get.c \
+tx_byte_pool_performance_system_info_get.c \
+tx_byte_pool_prioritize.c \
+tx_byte_pool_search.c \
+tx_byte_release.c \
+txe_block_allocate.c \
+txe_block_pool_create.c \
+txe_block_pool_delete.c \
+txe_block_pool_info_get.c \
+txe_block_pool_prioritize.c \
+txe_block_release.c \
+txe_byte_allocate.c \
+txe_byte_pool_create.c \
+txe_byte_pool_delete.c \
+txe_byte_pool_info_get.c \
+txe_byte_pool_prioritize.c \
+txe_byte_release.c \
+txe_event_flags_create.c \
+txe_event_flags_delete.c \
+txe_event_flags_get.c \
+txe_event_flags_info_get.c \
+txe_event_flags_set.c \
+txe_event_flags_set_notify.c \
+txe_mutex_create.c \
+txe_mutex_delete.c \
+txe_mutex_get.c \
+txe_mutex_info_get.c \
+txe_mutex_prioritize.c \
+txe_mutex_put.c \
+txe_queue_create.c \
+txe_queue_delete.c \
+txe_queue_flush.c \
+txe_queue_front_send.c \
+txe_queue_info_get.c \
+txe_queue_prioritize.c \
+txe_queue_receive.c \
+txe_queue_send.c \
+txe_queue_send_notify.c \
+txe_semaphore_ceiling_put.c \
+txe_semaphore_create.c \
+txe_semaphore_delete.c \
+txe_semaphore_get.c \
+txe_semaphore_info_get.c \
+txe_semaphore_prioritize.c \
+txe_semaphore_put.c \
+txe_semaphore_put_notify.c \
+txe_thread_create.c \
+txe_thread_delete.c \
+txe_thread_entry_exit_notify.c \
+txe_thread_info_get.c \
+txe_thread_preemption_change.c \
+txe_thread_priority_change.c \
+txe_thread_relinquish.c \
+txe_thread_reset.c \
+txe_thread_resume.c \
+txe_thread_suspend.c \
+txe_thread_terminate.c \
+txe_thread_time_slice_change.c \
+txe_thread_wait_abort.c \
+txe_timer_activate.c \
+txe_timer_change.c \
+txe_timer_create.c \
+txe_timer_deactivate.c \
+txe_timer_delete.c \
+txe_timer_info_get.c \
+tx_event_flags_cleanup.c \
+tx_event_flags_create.c \
+tx_event_flags_delete.c \
+tx_event_flags_get.c \
+tx_event_flags_info_get.c \
+tx_event_flags_initialize.c \
+tx_event_flags_performance_info_get.c \
+tx_event_flags_performance_system_info_get.c \
+tx_event_flags_set.c \
+tx_event_flags_set_notify.c \
+tx_initialize_high_level.c \
+tx_initialize_kernel_enter.c \
+tx_initialize_kernel_setup.c \
+tx_misra.c \
+tx_mutex_cleanup.c \
+tx_mutex_create.c \
+tx_mutex_delete.c \
+tx_mutex_get.c \
+tx_mutex_info_get.c \
+tx_mutex_initialize.c \
+tx_mutex_performance_info_get.c \
+tx_mutex_performance_system_info_get.c \
+tx_mutex_prioritize.c \
+tx_mutex_priority_change.c \
+tx_mutex_put.c \
+tx_queue_cleanup.c \
+tx_queue_create.c \
+tx_queue_delete.c \
+tx_queue_flush.c \
+tx_queue_front_send.c \
+tx_queue_info_get.c \
+tx_queue_initialize.c \
+tx_queue_performance_info_get.c \
+tx_queue_performance_system_info_get.c \
+tx_queue_prioritize.c \
+tx_queue_receive.c \
+tx_queue_send.c \
+tx_queue_send_notify.c \
+tx_semaphore_ceiling_put.c \
+tx_semaphore_cleanup.c \
+tx_semaphore_create.c \
+tx_semaphore_delete.c \
+tx_semaphore_get.c \
+tx_semaphore_info_get.c \
+tx_semaphore_initialize.c \
+tx_semaphore_performance_info_get.c \
+tx_semaphore_performance_system_info_get.c \
+tx_semaphore_prioritize.c \
+tx_semaphore_put.c \
+tx_semaphore_put_notify.c \
+tx_thread_create.c \
+tx_thread_delete.c \
+tx_thread_entry_exit_notify.c \
+tx_thread_identify.c \
+tx_thread_info_get.c \
+tx_thread_initialize.c \
+tx_thread_performance_info_get.c \
+tx_thread_performance_system_info_get.c \
+tx_thread_preemption_change.c \
+tx_thread_priority_change.c \
+tx_thread_relinquish.c \
+tx_thread_reset.c \
+tx_thread_resume.c \
+tx_thread_shell_entry.c \
+tx_thread_sleep.c \
+tx_thread_stack_analyze.c \
+tx_thread_stack_error_handler.c \
+tx_thread_stack_error_notify.c \
+tx_thread_suspend.c \
+tx_thread_system_preempt_check.c \
+tx_thread_system_resume.c \
+tx_thread_system_suspend.c \
+tx_thread_terminate.c \
+tx_thread_timeout.c \
+tx_thread_time_slice.c \
+tx_thread_time_slice_change.c \
+tx_thread_wait_abort.c \
+tx_time_get.c \
+tx_timer_activate.c \
+tx_timer_change.c \
+tx_timer_create.c \
+tx_timer_deactivate.c \
+tx_timer_delete.c \
+tx_timer_expiration_process.c \
+tx_timer_info_get.c \
+tx_timer_initialize.c \
+tx_timer_performance_info_get.c \
+tx_timer_performance_system_info_get.c \
+tx_timer_system_activate.c \
+tx_timer_system_deactivate.c \
+tx_timer_thread_entry.c \
+tx_time_set.c \
+tx_trace_buffer_full_notify.c \
+tx_trace_disable.c \
+tx_trace_enable.c \
+tx_trace_event_filter.c \
+tx_trace_event_unfilter.c \
+tx_trace_initialize.c \
+tx_trace_interrupt_control.c \
+tx_trace_isr_enter_insert.c \
+tx_trace_isr_exit_insert.c \
+tx_trace_object_register.c \
+tx_trace_object_unregister.c \
+tx_trace_user_event_insert.c \
+
+GENERIC_OBJS = $(GENERIC_SRCS:%.c=.tmp/generic/%.o)
diff --git a/ports/linux/gnu/example_build/sample_threadx.c b/ports/linux/gnu/example_build/sample_threadx.c
new file mode 100644
index 00000000..080be3c4
--- /dev/null
+++ b/ports/linux/gnu/example_build/sample_threadx.c
@@ -0,0 +1,380 @@
+/* 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"
+#include <stdio.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;
+
+
+/* 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", first_unused_memory, 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++;
+
+ /* Print results. */
+ printf("**** ThreadX Linux Demonstration **** (c) 1996-2020 Microsoft Corporation\n\n");
+ printf(" thread 0 events sent: %lu\n", thread_0_counter);
+ printf(" thread 1 messages sent: %lu\n", thread_1_counter);
+ printf(" thread 2 messages received: %lu\n", thread_2_counter);
+ printf(" thread 3 obtained semaphore: %lu\n", thread_3_counter);
+ printf(" thread 4 obtained semaphore: %lu\n", thread_4_counter);
+ printf(" thread 5 events received: %lu\n", thread_5_counter);
+ printf(" thread 6 mutex obtained: %lu\n", thread_6_counter);
+ printf(" thread 7 mutex obtained: %lu\n\n", thread_7_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;
+ }
+}
diff --git a/ports/linux/gnu/inc/tx_port.h b/ports/linux/gnu/inc/tx_port.h
new file mode 100644
index 00000000..9422e100
--- /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.1 */
+/* */
+/* 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+
+#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 <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#ifndef __USE_POSIX199309
+#define __USE_POSIX199309
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#undef __USE_POSIX199309
+#else /* __USE_POSIX199309 */
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#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/readme_threadx.txt b/ports/linux/gnu/readme_threadx.txt
new file mode 100644
index 00000000..5fdd6c3f
--- /dev/null
+++ b/ports/linux/gnu/readme_threadx.txt
@@ -0,0 +1,155 @@
+ Microsoft's Azure RTOS ThreadX for Linux
+
+ Using the GNU GCC Tools
+
+1. Building the ThreadX run-time Library
+
+First make sure you are in the "example_build" directory. Also, make sure that
+you have setup your path and other environment variables necessary for the GNU
+development environment. The following command retrieves and installs GCC
+multilib on a Ubuntu system:
+
+sudo apt-get install gcc-multilib
+
+At this point you may run the GNU make command to build the ThreadX core
+library. This will build the ThreadX run-time environment in the
+"example_build" directory.
+
+ make tx.a
+
+you should now observe the compilation of the ThreadX library source. At the
+end of the make, they are all combined into the run-time library file: tx.a.
+This file must be linked with your application in order to use ThreadX.
+
+
+2. Demonstration System
+
+Building the demonstration is easy; simply execute the GNU make command while
+inside the "example_build" directory.
+
+ make sample_threadx
+
+You should observe the compilation of sample_threadx.c (which is the demonstration
+application) and linking with tx.a. The resulting file DEMO is a binary file
+that can be executed.
+
+
+3. System Initialization
+
+The system entry point is at main(), which is defined in the application.
+Once the application calls tx_kernel_enter, ThreadX starts running and
+performs various initialization duties prior to starting the scheduler. The
+Linux-specific initialization is done in the function _tx_initialize_low_level,
+which is located in the file tx_initialize_low_level.c. This function is
+responsible for setting up various system data structures and simulated
+interrupts - including the periodic timer interrupt source for ThreadX.
+
+In addition, _tx_initialize_low_level determines the first available
+address for use by the application. In Linux, this is basically done
+by using malloc to get a big block of memory from Linux.
+
+
+4. Linux Implementation
+
+ThreadX for Linux is implemented using POSIX pthreads. Each application
+thread in ThreadX actually runs as a Linux pthread. The determination of
+which application thread to run is made by the ThreadX scheduler, which
+itself is a Linux pthread. The ThreadX scheduler is the highest priority
+thread in the system.
+
+Interrupts in ThreadX/Linux are also simulated by pthreads. A good example
+is the ThreadX system timer interrupt, which can be found in
+tx_initialize_low_level.c.
+
+ThreadX for linux utilizes the API pthread_setschedparam() which requires
+the ThreadX application running with privilege. The following command is used
+to run a ThreadX application:
+
+./sample_threadx
+
+5. Improving Performance
+
+The distribution version of ThreadX is built without any compiler
+optimizations. This makes it easy to debug because you can trace or set
+breakpoints inside of ThreadX itself. Of course, this costs some
+performance. To make it run faster, you can change the makefile to
+enable all compiler optimizations. In addition, you can eliminate the
+ThreadX basic API error checking by compiling your application code with the
+symbol TX_DISABLE_ERROR_CHECKING defined.
+
+
+6. Interrupt Handling
+
+ThreadX provides simulated interrupt handling with Linux pthreads. Simulated
+interrupt threads may be created by the application or may be added to the
+simulated timer interrupt defined in tx_initialize_low_level.c. The following
+format for creating simulated interrupts should be used:
+
+6.1 Data structures
+
+Here is an example of how to define the Linux data structures and prototypes
+necessary to create a simulated interrupt thread:
+
+pthread_t _sample_linux_interrupt_thread;
+void *_sample_linux_interrupt_entry(void *p);
+
+6.2 Creating a Simulated Interrupt Thread
+
+Here is an example of how to create a simulated interrupt thread in Linux.
+This may be done inside of tx_initialize_low_level.c or from your application code
+
+
+struct sched_param sp;
+
+ /* Create the ISR thread */
+ pthread_create(&_sample_linux_interrupt_thread, NULL, _sample_linux_interrupt_entry, &_sample_linux_interrupt_thread);
+
+ /* Set up the ISR priority */
+ sp.sched_priority = TX_LINUX_PRIORITY_ISR;
+ pthread_setschedparam(_sample_linux_interrupt_thread, SCHED_FIFO, &sp);
+
+
+
+6.3 Simulated Interrupt Thread Template
+
+The following is a template for the simulated interrupt thread. This interrupt will occur on
+a periodic basis.
+
+void *_sample_linux_interrupt_entry(void *p)
+{
+struct timespec ts;
+
+ while(1)
+ {
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 10000;
+ while(nanosleep(&ts, &ts));
+
+ /* Call ThreadX context save for interrupt preparation. */
+ _tx_thread_context_save();
+
+ /* Call the real ISR routine */
+ _sample_linux_interrupt_isr();
+
+ /* Call ThreadX context restore for interrupt completion. */
+ _tx_thread_context_restore();
+ }
+}
+
+
+
+7. Revision History
+
+For generic code revision information, please refer to the readme_threadx_generic.txt
+file, which is included in your distribution. The following details the revision
+information associated with this specific port of ThreadX:
+
+06/30/2020 Initial ThreadX 6.0.1 version for Linux using GNU GCC tools.
+
+
+Copyright(c) 1996-2020 Microsoft Corporation
+
+
+https://azure.com/rtos
+
diff --git a/ports/linux/gnu/src/tx_initialize_low_level.c b/ports/linux/gnu/src/tx_initialize_low_level.c
new file mode 100644
index 00000000..f8cd604b
--- /dev/null
+++ b/ports/linux/gnu/src/tx_initialize_low_level.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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/sysinfo.h>
+
+
+/* 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.1 */
+/* 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..ab24759e
--- /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.1 */
+/* 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..d2b54b23
--- /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.1 */
+/* 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..ea75e19f
--- /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.1 */
+/* AUTHOR */
+/* */
+/* William E. Lamie, Microsoft Corporation */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function is responsible for changing the interrupt lockout */
+/* posture of the system. */
+/* */
+/* INPUT */
+/* */
+/* new_posture New interrupt lockout posture */
+/* */
+/* OUTPUT */
+/* */
+/* old_posture Old interrupt lockout posture */
+/* */
+/* CALLS */
+/* */
+/* tx_linux_mutex_lock */
+/* pthread_self */
+/* pthread_getschedparam */
+/* tx_linux_mutex_recursive_unlock */
+/* pthread_exit */
+/* */
+/* CALLED BY */
+/* */
+/* Application Code */
+/* */
+/* RELEASE HISTORY */
+/* */
+/* DATE NAME DESCRIPTION */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..7843a3ec
--- /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 <stdio.h>
+#include <errno.h>
+
+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.1 */
+/* 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..b18ae2fb
--- /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 <stdio.h>
+#include <unistd.h>
+
+
+/* Prototype for new thread entry function. */
+
+void *_tx_linux_thread_entry(void *ptr);
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _tx_thread_stack_build Linux/GNU */
+/* 6.0.1 */
+/* AUTHOR */
+/* */
+/* William E. Lamie, Microsoft Corporation */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function builds a stack frame on the supplied thread's stack. */
+/* The stack frame results in a fake interrupt return to the supplied */
+/* function pointer. */
+/* */
+/* INPUT */
+/* */
+/* thread_ptr Pointer to thread control blk */
+/* function_ptr Pointer to return function */
+/* */
+/* OUTPUT */
+/* */
+/* None */
+/* */
+/* CALLS */
+/* */
+/* 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..9ee68d0d
--- /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 <stdio.h>
+
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _tx_thread_system_return Linux/GNU */
+/* 6.0.1 */
+/* AUTHOR */
+/* */
+/* William E. Lamie, Microsoft Corporation */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function is target processor specific. It is used to transfer */
+/* control from a thread back to the 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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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..55207c14
--- /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.1 */
+/* AUTHOR */
+/* */
+/* William E. Lamie, Microsoft Corporation */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function processes the hardware timer interrupt. This */
+/* processing includes incrementing the system clock and checking for */
+/* time slice and/or timer expiration. If either is found, the */
+/* interrupt context save/restore functions are called along with the */
+/* expiration functions. */
+/* */
+/* INPUT */
+/* */
+/* None */
+/* */
+/* OUTPUT */
+/* */
+/* None */
+/* */
+/* CALLS */
+/* */
+/* _tx_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 */
+/* */
+/* 06-30-2020 William E. Lamie Initial Version 6.0.1 */
+/* */
+/**************************************************************************/
+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);
+}
+