6.1 minor release

This commit is contained in:
Scott Larson
2020-09-30 15:42:41 -07:00
parent 7287542cc8
commit 1b5816a206
3038 changed files with 377204 additions and 8606 deletions

View File

@@ -0,0 +1,219 @@
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_smp_core_get.c \
tx_thread_smp_core_preempt.c \
tx_thread_smp_current_state_get.c \
tx_thread_smp_current_thread_get.c \
tx_thread_smp_initialize_wait.c \
tx_thread_smp_low_level_initialize.c \
tx_thread_smp_protect.c \
tx_thread_smp_time_get.c \
tx_thread_smp_unprotect.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_smp_core_exclude.c \
tx_thread_smp_core_exclude_get.c \
tx_thread_smp_current_state_set.c \
tx_thread_smp_debug_entry_insert.c \
tx_thread_smp_high_level_initialize.c \
tx_thread_smp_rebalance_execute_list.c \
tx_thread_smp_utilities.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_smp_core_exclude.c \
tx_timer_smp_core_exclude_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)

View File

@@ -0,0 +1,380 @@
/* This is a small demo of the high-performance ThreadX SMP 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 SMP 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;
}
}

View File

@@ -0,0 +1,678 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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 SMP/Linux/GCC */
/* 6.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 */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
#ifndef TX_PORT_H
#define TX_PORT_H
/************* Define ThreadX SMP constants. *************/
#define TX_DISABLE_INLINE
/* Define the ThreadX SMP maximum number of cores. */
#ifndef TX_THREAD_SMP_MAX_CORES
#define TX_THREAD_SMP_MAX_CORES 4
#endif
/* Define the ThreadX SMP core mask. */
#ifndef TX_THREAD_SMP_CORE_MASK
#define TX_THREAD_SMP_CORE_MASK 0xF /* Where bit 0 represents Core 0, bit 1 represents Core 1, etc. */
#endif
/* Define dynamic number of cores option. When commented out, the number of cores is static. */
/* #define TX_THREAD_SMP_DYNAMIC_CORE_MAX */
/* Define ThreadX SMP initialization macro. */
#define TX_PORT_SPECIFIC_PRE_INITIALIZATION
/* Enable the inter-core interrupt logic. */
#define TX_THREAD_SMP_INTER_CORE_INTERRUPT
/* Determine if there is customer-specific wakeup logic needed. */
#ifdef TX_THREAD_SMP_WAKEUP_LOGIC
/* Include customer-specific wakeup code. */
#include "tx_thread_smp_core_wakeup.h"
#else
#ifdef TX_THREAD_SMP_DEFAULT_WAKEUP_LOGIC
/* Default wakeup code. */
#define TX_THREAD_SMP_WAKEUP_LOGIC
#define TX_THREAD_SMP_WAKEUP(i) _tx_thread_smp_core_preempt(i)
#endif
#endif
/* Ensure that the in-line resume/suspend define is not allowed. */
#ifdef TX_INLINE_THREAD_RESUME_SUSPEND
#undef TX_INLINE_THREAD_RESUME_SUSPEND
#endif
/* Overide inline keyword. */
#define INLINE_DECLARE __inline
/************* End ThreadX SMP constants. *************/
/* 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;
typedef long LONG;
typedef unsigned long ULONG;
typedef short SHORT;
typedef unsigned short USHORT;
typedef uint64_t ULONG64;
/* 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;
extern UINT mutex_priority_change_extension_selection;
extern UINT priority_change_extension_selection;
#ifdef TX_REGRESSION_TEST
/* Define extension macros for automated coverage tests. */
#define TX_PORT_SPECIFIC_MEMORY_SYNCHRONIZATION other_core_status = other_core_status + _tx_thread_system_state[0]; \
_tx_thread_system_state[0] = 0;
#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); \
if (mutex_priority_change_extension_selection == 2) \
original_priority = new_priority; \
if (mutex_priority_change_extension_selection == 3) \
original_pt_thread = thread_ptr; \
if (mutex_priority_change_extension_selection == 4) \
{ \
execute_ptr = thread_ptr; \
_tx_thread_preemption__threshold_scheduled = TX_NULL; \
} \
suspend_lowest_priority(); \
}
#define TX_THREAD_PRIORITY_CHANGE_EXTENSION if (priority_change_extension_selection != ((TEST_FLAG) 0)) \
{ \
if (priority_change_extension_selection == 1) \
thread_ptr -> tx_thread_smp_core_mapped = TX_THREAD_SMP_MAX_CORES; \
else if (priority_change_extension_selection == 2) \
{ \
original_priority = new_priority; \
_tx_thread_execute_ptr[0] = TX_NULL; \
} \
else if (priority_change_extension_selection == 3) \
{ \
original_pt_thread = thread_ptr; \
} \
else \
{ \
_tx_thread_preemption__threshold_scheduled = TX_NULL; \
} \
priority_change_extension_selection = 0; \
}
#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(); \
{ \
UINT k; \
for (k = 1; k < TX_THREAD_SMP_MAX_CORES; k++) \
{ \
_tx_thread_system_state[k] = 0; \
} \
}
/* 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_mutex_access; \
UINT tx_thread_linux_int_disabled_flag; \
UINT tx_thread_linux_deferred_preempt; \
UINT tx_thread_linux_virtual_core;
#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 Linux mutex data structure. */
typedef struct
{
pthread_mutex_t tx_linux_mutex;
pthread_t tx_linux_mutex_owner;
ULONG tx_linux_mutex_nested_count;
} TX_LINUX_MUTEX;
/* Define Linux-specific critical section APIs. */
void _tx_linux_mutex_obtain(TX_LINUX_MUTEX *mutex);
void _tx_linux_mutex_release(TX_LINUX_MUTEX *mutex);
void _tx_linux_mutex_release_all(TX_LINUX_MUTEX *mutex);
typedef struct TX_THREAD_STRUCT TX_THREAD;
/* Define post completion processing for tx_thread_delete, so that the Linux thread resources are properly removed. */
void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_interrupt_save);
#define TX_THREAD_DELETE_PORT_COMPLETION(thread_ptr) _tx_thread_delete_port_completion(thread_ptr, tx_interrupt_save);
/* Define post completion processing for tx_thread_reset, so that the Linux thread resources are properly removed. */
void _tx_thread_reset_port_completion(TX_THREAD *thread_ptr, UINT tx_interrupt_save);
#define TX_THREAD_RESET_PORT_COMPLETION(thread_ptr) _tx_thread_reset_port_completion(thread_ptr, tx_interrupt_save);
/************* Define ThreadX SMP data types and function prototypes. *************/
struct TX_THREAD_STRUCT;
/* Define the ThreadX SMP protection structure. */
typedef struct TX_THREAD_SMP_PROTECT_STRUCT
{
ULONG tx_thread_smp_protect_in_force;
struct TX_THREAD_STRUCT *tx_thread_smp_protect_thread;
ULONG tx_thread_smp_protect_core;
ULONG tx_thread_smp_protect_count;
pthread_t tx_thread_smp_protect_linux_thread_id;
} TX_THREAD_SMP_PROTECT;
/* Define the virtual core structure for ThreadX SMP Linux. This is where we keep the mapping of the core to
the actual thread running. All ISRs are assumed to be running on core 0 for Linux. */
typedef struct TX_THREAD_SMP_CORE_MAPPING_STRUCT
{
pthread_t tx_thread_smp_core_mapping_linux_thread_id;
struct TX_THREAD_STRUCT *tx_thread_smp_core_mapping_thread;
} TX_THREAD_SMP_CORE_MAPPING;
/* Define ThreadX SMP low-level assembly routines. */
struct TX_THREAD_STRUCT * _tx_thread_smp_current_thread_get(void);
UINT _tx_thread_smp_protect(void);
void _tx_thread_smp_unprotect(UINT interrupt_save);
ULONG _tx_thread_smp_current_state_get(void);
ULONG _tx_thread_smp_time_get(void);
/* Determine if SMP Debug is selected. If so, the function prototype is setup. Otherwise, the debug call is
simply mapped to whitespace. */
#ifdef TX_THREAD_SMP_DEBUG_ENABLE
void _tx_thread_smp_debug_entry_insert(ULONG id, ULONG suspend, VOID *thread_ptr);
#else
#define _tx_thread_smp_debug_entry_insert(a, b, c)
#endif
/* Define the get core ID macro. */
#define TX_SMP_CORE_ID _tx_thread_smp_core_get()
/* 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 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. */
#define TX_INTERRUPT_SAVE_AREA unsigned int tx_interrupt_save;
#define TX_DISABLE tx_interrupt_save = _tx_thread_smp_protect();
#define TX_RESTORE _tx_thread_smp_unprotect(tx_interrupt_save);
/************* End ThreadX SMP data type and function prototype definitions. *************/
#define tx_linux_sem_post(p) sem_post(p)
#define tx_linux_sem_wait(p) sem_wait(p)
#define tx_linux_sem_timedwait(p, t) sem_timedwait(p, t)
/* 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. All rights reserved. * ThreadX SMP/Linux/gcc Version 6.1 *";
#else
extern CHAR _tx_version_id[];
#endif
/* Define externals for the Linux port of ThreadX. */
extern TX_LINUX_MUTEX _tx_linux_mutex;
extern sem_t _tx_linux_scheduler_semaphore;
extern pthread_t _tx_linux_scheduler_id;
extern ULONG _tx_linux_global_int_disabled_flag;
extern struct timespec _tx_linux_time_stamp;
extern ULONG _tx_linux_system_error;
extern TX_THREAD_SMP_CORE_MAPPING _tx_linux_virtual_cores[TX_THREAD_SMP_MAX_CORES];
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();
void _tx_linux_thread_sleep(long ns);
#ifndef TX_LINUX_MEMORY_SIZE
#define TX_LINUX_MEMORY_SIZE 100000
#endif
#ifndef TX_TIMER_TICKS_PER_SECOND
#define TX_TIMER_TICKS_PER_SECOND 100UL
#endif
#ifndef TX_LINUX_THREAD_STACK_SIZE
#define TX_LINUX_THREAD_STACK_SIZE 65536
#endif
/* Define priorities of pthreads. */
#define TX_LINUX_PRIORITY_SCHEDULE (3)
#define TX_LINUX_PRIORITY_ISR (2)
#define TX_LINUX_PRIORITY_USER_THREAD (1)
#endif

View File

@@ -0,0 +1,155 @@
Microsoft's Azure RTOS ThreadX SMP for Linux
Using the GNU GCC Tools
1. Building the ThreadX SMP 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 SMP core
library. This will build the ThreadX SMP run-time environment in the
"example_build" directory.
make tx.a
you should now observe the compilation of the ThreadX SMP 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 SMP 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 SMP for Linux is implemented using POSIX pthreads. Each application
thread in ThreadX SMP actually runs as a Linux pthread. The determination of
which application thread to run is made by the ThreadX SMP scheduler, which
itself is a Linux pthread. The ThreadX SMP scheduler is the highest priority
thread in the system.
Interrupts in ThreadX_SMP Linux are also simulated by pthreads. A good example
is the ThreadX SMP system timer interrupt, which can be found in
tx_initialize_low_level.c.
ThreadX SMP for linux utilizes the API pthread_setschedparam() which requires
the ThreadX SMP application running with privilege. The following command is used
to run a ThreadX SMP application:
./sample_threadx
5. Improving Performance
The distribution version of ThreadX SMP is built without any compiler
optimizations. This makes it easy to debug because you can trace or set
breakpoints inside of ThreadX SMP 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 SMP basic API error checking by compiling your application code with the
symbol TX_DISABLE_ERROR_CHECKING defined.
6. Interrupt Handling
ThreadX SMP 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 SMP context save for interrupt preparation. */
_tx_thread_context_save();
/* Call the real ISR routine */
_sample_linux_interrupt_isr();
/* Call ThreadX SMP 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:
09-30-2020 Initial ThreadX SMP 6.1 version for Linux using GNU GCC tools.
Copyright(c) 1996-2020 Microsoft Corporation
https://azure.com/rtos

View File

@@ -0,0 +1,464 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_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>
/* Define various Linux objects used by the ThreadX port. */
TX_LINUX_MUTEX _tx_linux_mutex;
sem_t _tx_linux_scheduler_semaphore;
pthread_t _tx_linux_scheduler_id;
ULONG _tx_linux_global_int_disabled_flag;
struct timespec _tx_linux_time_stamp;
ULONG _tx_linux_system_error;
TX_THREAD_SMP_CORE_MAPPING _tx_linux_virtual_cores[TX_THREAD_SMP_MAX_CORES];
extern UINT _tx_thread_preempt_disable;
extern TX_THREAD *_tx_thread_current_ptr[TX_THREAD_SMP_MAX_CORES];
extern TX_THREAD *_tx_thread_execute_ptr[TX_THREAD_SMP_MAX_CORES];
extern ULONG _tx_thread_system_state[TX_THREAD_SMP_MAX_CORES];
extern TX_THREAD_SMP_PROTECT _tx_thread_smp_protection;
/* 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;
static sem_t _tx_linux_sleep_sema;
__thread int _tx_linux_threadx_thread = 0;
/* 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
/* Define the maximum size of the Linux debug array. */
#ifndef TX_LINUX_DEBUG_EVENT_SIZE
#define TX_LINUX_DEBUG_EVENT_SIZE 400
#endif
/* 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;
pthread_t tx_linux_debug_entry_running_id;
UINT tx_linux_debug_entry_core;
struct timespec tx_linux_debug_entry_timestamp;
char *tx_linux_debug_entry_file;
unsigned long tx_linux_debug_entry_line;
TX_LINUX_MUTEX tx_linux_debug_entry_mutex;
TX_THREAD_SMP_PROTECT tx_linux_debug_protection;
unsigned long tx_linux_debug_entry_int_disabled_flag;
UINT tx_linux_debug_entry_preempt_disable;
ULONG tx_linux_debug_entry_system_state[TX_THREAD_SMP_MAX_CORES];
TX_THREAD *tx_linux_debug_entry_current_thread[TX_THREAD_SMP_MAX_CORES];
pthread_t tx_linux_debug_entry_current_thread_id[TX_THREAD_SMP_MAX_CORES];
TX_THREAD *tx_linux_debug_entry_execute_thread[TX_THREAD_SMP_MAX_CORES];
pthread_t tx_linux_debug_entry_execute_thread_id[TX_THREAD_SMP_MAX_CORES];
} TX_LINUX_DEBUG_ENTRY;
/* 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)
{
UINT i;
/* Get the time stamp. */
clock_gettime(CLOCK_REALTIME, &_tx_linux_time_stamp);
/* Setup the debug 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_core = _tx_thread_smp_core_get();
_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_protection = _tx_thread_smp_protection;
_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_mutex = _tx_linux_mutex;
_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_running_id = pthread_self();
for (i = 0; i < TX_THREAD_SMP_MAX_CORES; i++)
{
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_system_state[i] = _tx_thread_system_state[i];
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_current_thread[i] = _tx_thread_current_ptr[i];
if (_tx_thread_current_ptr[i])
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_current_thread_id[i] = _tx_thread_current_ptr[i] -> tx_thread_linux_thread_id;
else
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_current_thread_id[i] = 0;
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_execute_thread[i] = _tx_thread_execute_ptr[i];
if (_tx_thread_execute_ptr[i])
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_execute_thread_id[i] = _tx_thread_execute_ptr[i] -> tx_thread_linux_thread_id;
else
_tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_execute_thread_id[i] = 0;
}
/* 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;
}
}
#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 SMP/Linux/GCC */
/* 6.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 */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_initialize_low_level(VOID)
{
UINT i;
struct sched_param sp;
pthread_mutexattr_t attr;
#ifdef TX_LINUX_MULTI_CORE
cpu_set_t mask;
/* Limit this ThreadX simulation on Linux to a single core. */
CPU_ZERO(&mask);
CPU_SET(0, &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);
/* Pickup the unique Id of the current thread, which will also be the Id of the scheduler. */
_tx_linux_scheduler_id = pthread_self();
/* 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 mutex. 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_ERRORCHECK);
pthread_mutex_init(&_tx_linux_mutex.tx_linux_mutex, &attr);
sem_init(&_tx_linux_scheduler_semaphore, 0, 0);
/* Loop to clear the virtual core array, which is how we map threads to cores. */
for (i = 0; i < TX_THREAD_SMP_MAX_CORES; i++)
{
/* Clear this mapping entry. */
_tx_linux_virtual_cores[i].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_linux_virtual_cores[i].tx_thread_smp_core_mapping_linux_thread_id = 0;
}
/* 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, &_tx_linux_timer_id))
{
/* 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_sec;
long timer_periodic_nsec;
int err;
/* Calculate periodic timer. */
timer_periodic_sec = 1 / TX_TIMER_TICKS_PER_SECOND;
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 the ThreadX system timer interrupt processing. */
_tx_timer_interrupt();
/* Call ThreadX context restore for interrupt completion. */
_tx_thread_context_restore();
}
}
/* 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(&_tx_linux_thread_timer_wait);
else
tx_linux_sem_post(&_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_obtain(&_tx_linux_mutex);
pthread_kill(thread_id, SUSPEND_SIG);
_tx_linux_mutex_release(&_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_obtain(&_tx_linux_mutex);
pthread_kill(thread_id, RESUME_SIG);
_tx_linux_mutex_release(&_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);
sem_init(&_tx_linux_sleep_sema, 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);
}
void _tx_linux_thread_sleep(long ns)
{
struct timespec ts;
int err;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_nsec += ns;
if (ts.tv_nsec > 1000000000)
{
ts.tv_nsec -= 1000000000;
ts.tv_sec++;
}
do
{
if (sem_timedwait(&_tx_linux_sleep_sema, &ts) == 0)
{
break;
}
err = errno;
} while (err != ETIMEDOUT);
}

View File

@@ -0,0 +1,176 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_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 SMP/Linux/GCC */
/* 6.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_obtain */
/* sem_trywait */
/* tx_linux_sem_post */
/* tx_linux_sem_wait */
/* _tx_linux_thread_resume */
/* _tx_linux_mutex_release_all */
/* */
/* CALLED BY */
/* */
/* ISRs Interrupt Service Routines */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_context_restore(VOID)
{
TX_THREAD *current_thread;
/* The critical section is already in force at this point. */
/* Debug entry. */
_tx_linux_debug_entry_insert("CONTEXT_RESTORE", __FILE__, __LINE__);
/* For Linux, ISRs are always mapped to core 0. */
/* Decrement the nested interrupt count. */
_tx_thread_system_state[0]--;
/* Pickup current thread. */
current_thread = _tx_thread_current_ptr[0];
/* Determine if this is the first nested interrupt and if a ThreadX
application thread was running at the time. */
if ((!_tx_thread_system_state[0]) && (current_thread))
{
/* Yes, this is the first and last interrupt processed. */
/* Check to see if preemption is required. */
if ((_tx_thread_preempt_disable == 0) && (current_thread != _tx_thread_execute_ptr[0]))
{
/* 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. */
current_thread -> tx_thread_linux_suspension_type = 1;
/* Save the remaining time-slice and disable it. */
if (_tx_timer_time_slice[0])
{
current_thread -> tx_thread_time_slice = _tx_timer_time_slice[0];
_tx_timer_time_slice[0] = 0;
}
/* Clear the current thread pointer. */
_tx_thread_current_ptr[0] = TX_NULL;
/* Clear this mapping entry. */
_tx_linux_virtual_cores[0].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_linux_virtual_cores[0].tx_thread_smp_core_mapping_linux_thread_id = 0;
/* Indicate that this thread is now ready for scheduling again by another core. */
current_thread -> tx_thread_smp_core_control = 1;
/* Make sure semaphore is 0. */
while(!sem_trywait(&_tx_linux_scheduler_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_scheduler_semaphore);
if(_tx_thread_execute_ptr[0])
{
if(_tx_thread_execute_ptr[0] -> tx_thread_linux_suspension_type == 2)
{
/* Unlock linux mutex. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* Wait until TX_THREAD start running. */
tx_linux_sem_wait(&_tx_linux_isr_semaphore);
_tx_linux_mutex_obtain(&_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(current_thread -> tx_thread_linux_thread_id);
}
}
/* Unlock linux mutex. */
_tx_thread_smp_unprotect(TX_INT_ENABLE);
}

View File

@@ -0,0 +1,128 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_save SMP/Linux/GCC */
/* 6.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_obtain */
/* _tx_linux_thread_suspend */
/* */
/* CALLED BY */
/* */
/* ISRs */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_context_save(VOID)
{
TX_THREAD *thread_ptr;
UINT interrupt_posture;
/* Loop to perform retries on thread preemption. */
while(1)
{
/* Lock mutex to ensure other threads are not playing with
the core ThreadX data structures. */
interrupt_posture = _tx_thread_smp_protect();
/* Check for a system error condition. */
if (interrupt_posture != TX_FALSE)
{
/* This should not happen... increment the system error counter. */
_tx_linux_system_error++;
}
/* Debug entry. */
_tx_linux_debug_entry_insert("CONTEXT_SAVE", __FILE__, __LINE__);
/* All ISRs are assumed to be serviced on core 0. */
/* Pickup the current thread pointer. */
thread_ptr = _tx_thread_current_ptr[0];
/* If an application thread is running, suspend it to simulate preemption. */
if ((thread_ptr) && (_tx_thread_system_state[0] == 0))
{
/* Yes, this is the first interrupt and an application thread is running...
suspend it! */
_tx_linux_thread_suspend(thread_ptr -> tx_thread_linux_thread_id);
/* Debug entry. */
_tx_linux_debug_entry_insert("CONTEXT_SAVE-suspend_thread", __FILE__, __LINE__);
}
/* Increment the nested interrupt condition. */
_tx_thread_system_state[0]++;
/* Do not release the protection for ISRs, since in SMP mode other threads might be scheduled on
interrupted virtual core 0, which will confuse ThreadX. */
/* Get out of the loop. */
break;
}
}

View File

@@ -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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_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 SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for changing the interrupt lockout */
/* posture of the system. */
/* */
/* INPUT */
/* */
/* new_posture New interrupt lockout posture */
/* */
/* OUTPUT */
/* */
/* old_posture Old interrupt lockout posture */
/* */
/* CALLS */
/* */
/* _tx_linux_mutex_obtain */
/* pthread_self */
/* pthread_getschedparam */
/* _tx_linux_mutex_release_all */
/* pthread_exit */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_interrupt_control(UINT new_posture)
{
UINT old_posture;
TX_THREAD *thread_ptr;
pthread_t thread_id;
int exit_code = 0;
UINT core;
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
#ifdef TX_LINUX_DEBUG_ENABLE
/* Determine if this is a disable or enable request. */
if (new_posture == TX_INT_ENABLE)
{
/* Enable. */
_tx_linux_debug_entry_insert("RESTORE", __FILE__, __LINE__);
}
else
{
/* Disable. */
_tx_linux_debug_entry_insert("DISABLE", __FILE__, __LINE__);
}
#endif
/* Pickup the id of the current thread. */
thread_id = pthread_self();
/* Get the currently running virtual core. */
core = _tx_thread_smp_core_get();
/* Pickup the current thread pointer. */
thread_ptr = _tx_thread_current_ptr[core];
/* 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_release_all(&_tx_linux_mutex);
pthread_exit((void *)&exit_code);
}
/* Determine the current interrupt lockout condition. */
if (_tx_linux_mutex.tx_linux_mutex_nested_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[core])
{
/* 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_release_all(&_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. */
thread_ptr -> tx_thread_linux_int_disabled_flag = TX_FALSE;
/* Determine if the critical section is locked. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
}
else if (new_posture == TX_INT_DISABLE)
{
/* Set the disabled flag. */
thread_ptr -> tx_thread_linux_int_disabled_flag = TX_TRUE;
}
}
/* Return the previous interrupt disable posture. */
return(old_posture);
}

View File

@@ -0,0 +1,519 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_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_isr_semaphore;
extern UINT _tx_linux_timer_waiting;
extern pthread_t _tx_linux_timer_id;
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule SMP/Linux/GCC */
/* 6.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_obtain */
/* _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 */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_schedule(VOID)
{
UINT core;
TX_THREAD *current_thread;
TX_THREAD *execute_thread;
struct timespec ts;
UCHAR preemt_retry = TX_FALSE;
/* Loop forever. */
while(1)
{
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Check for a system error condition. */
if (_tx_linux_global_int_disabled_flag != TX_FALSE)
{
/* This should not happen... increment the system error counter. */
_tx_linux_system_error++;
}
/* Debug entry. */
_tx_linux_debug_entry_insert("SCHEDULE-wake_up", __FILE__, __LINE__);
/* Loop through each virtual core to look for an idle core. */
for (core = 0; core < TX_THREAD_SMP_MAX_CORES; core++)
{
/* Pickup the current thread pointer for this core. */
current_thread = _tx_thread_current_ptr[core];
/* Determine if the thread's deferred preemption flag is set. */
if ((current_thread) && (current_thread -> tx_thread_linux_deferred_preempt))
{
if (_tx_thread_preempt_disable)
{
/* Preemption disabled. Retry. */
preemt_retry = TX_TRUE;
break;
}
if (current_thread -> tx_thread_state != TX_TERMINATED)
{
/* Suspend the thread to simulate preemption. Note that the thread is suspended BEFORE the protection get
flag is checked to ensure there is not a race condition between this thread and the update of that flag. */
_tx_linux_thread_suspend(current_thread -> tx_thread_linux_thread_id);
/* Clear the preemption flag. */
current_thread -> tx_thread_linux_deferred_preempt = TX_FALSE;
/* Indicate that this thread was suspended asynchronously. */
current_thread -> tx_thread_linux_suspension_type = 1;
/* Save the remaining time-slice and disable it. */
if (_tx_timer_time_slice[core])
{
current_thread -> tx_thread_time_slice = _tx_timer_time_slice[core];
_tx_timer_time_slice[core] = 0;
}
}
/* Clear the current thread pointer. */
_tx_thread_current_ptr[core] = TX_NULL;
/* Clear this mapping entry. */
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_linux_thread_id = 0;
/* Indicate that this thread is now ready for scheduling again by another core. */
current_thread -> tx_thread_smp_core_control = 1;
/* Debug entry. */
_tx_linux_debug_entry_insert("SCHEDULE-core_preempt_complete", __FILE__, __LINE__);
}
/* Determine if this core is idle. */
if (_tx_thread_current_ptr[core] == TX_NULL)
{
/* Yes, this core is idle, determine if there is a thread that can be scheduled for it. */
/* Pickup the execute thread pointer. */
execute_thread = _tx_thread_execute_ptr[core];
/* Is there a thread that is ready to execute on this core? */
if ((execute_thread) && (execute_thread -> tx_thread_smp_core_control))
{
/* 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[core] = execute_thread;
/* Remember the virtual core in the thread control block. */
execute_thread -> tx_thread_linux_virtual_core = core;
/* Setup the virtual core mapping structure. */
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_thread = execute_thread;
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_linux_thread_id = execute_thread -> tx_thread_linux_thread_id;
/* Clear the execution control flag. */
execute_thread -> tx_thread_smp_core_control = 0;
/* Increment the run count for this thread. */
execute_thread -> tx_thread_run_count++;
/* Setup time-slice, if present. */
_tx_timer_time_slice[core] = execute_thread -> tx_thread_time_slice;
/* Determine how the thread was last suspended. */
if (execute_thread -> tx_thread_linux_suspension_type == 1)
{
/* Clear the suspension type. */
execute_thread -> tx_thread_linux_suspension_type = 0;
/* 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(execute_thread -> tx_thread_linux_thread_id);
}
else if (execute_thread -> tx_thread_linux_suspension_type == 2)
{
/* Clear the suspension type. */
execute_thread -> tx_thread_linux_suspension_type = 0;
/* Debug entry. */
_tx_linux_debug_entry_insert("SCHEDULE-release_sem", __FILE__, __LINE__);
/* Make sure semaphore is 0. */
while(!sem_trywait(&execute_thread -> tx_thread_linux_thread_run_semaphore));
/* Let the thread run again by releasing its run semaphore. */
tx_linux_sem_post(&execute_thread -> 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_scheduler_semaphore);
/* Wake up timer ISR. */
tx_linux_sem_post(&_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_scheduler_semaphore);
_tx_linux_thread_resume(_tx_linux_timer_id);
}
}
else
{
/* System error, increment the counter. */
_tx_linux_system_error++;
}
}
}
}
if (preemt_retry)
{
/* Unlock linux mutex. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* Let user thread run to reset _tx_thread_preempt_disable. */
_tx_linux_thread_sleep(1);
preemt_retry = TX_FALSE;
continue;
}
/* Debug entry. */
_tx_linux_debug_entry_insert("SCHEDULE-self_suspend_sem", __FILE__, __LINE__);
/* Unlock linux mutex. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* Now suspend the main thread so the application thread can run. */
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_nsec += 2000000;
if (ts.tv_nsec >= 1000000000)
{
ts.tv_nsec -= 1000000000;
ts.tv_sec++;
}
tx_linux_sem_timedwait(&_tx_linux_scheduler_semaphore, &ts);
clock_gettime(CLOCK_REALTIME, &ts);
}
}
/* Define the ThreadX Linux mutex get, release, and release all functions. */
void _tx_linux_mutex_obtain(TX_LINUX_MUTEX *mutex)
{
TX_THREAD *thread_ptr;
pthread_t current_thread_id;
UINT i;
/* Pickup the current thread ID. */
current_thread_id = pthread_self();
/* Is the protection owned? */
if (mutex -> tx_linux_mutex_owner == current_thread_id)
{
/* Simply increment the nested counter. */
mutex -> tx_linux_mutex_nested_count++;
}
else
{
/* Loop to find a thread matching this ID. */
i = 0;
do
{
/* Pickup the thread pointer. */
thread_ptr = _tx_thread_current_ptr[i];
/* Is this thread obtaining the mutex? */
if ((thread_ptr) && (thread_ptr -> tx_thread_linux_thread_id == current_thread_id))
{
/* We have found the thread, get out of the loop. */
break;
}
/* Look at next core. */
i++;
} while (i < TX_THREAD_SMP_MAX_CORES);
/* Determine if we found a thread. */
if (i >= TX_THREAD_SMP_MAX_CORES)
{
/* Set the thread pointer to NULL to indicate a thread was not found. */
thread_ptr = TX_NULL;
}
/* If a thread was found, indicate the thread is attempting to access the mutex. */
if (thread_ptr)
{
/* Yes, current ThreadX thread attempting to get the mutex - set the flag. */
thread_ptr -> tx_thread_linux_mutex_access = TX_TRUE;
}
/* Get the Linux mutex. */
pthread_mutex_lock(&mutex -> tx_linux_mutex);
/* At this point we have the mutex. */
/* Clear the mutex access flag for the thread. */
if (thread_ptr)
{
/* Yes, clear the current ThreadX thread attempting to get the mutex. */
thread_ptr -> tx_thread_linux_mutex_access = TX_FALSE;
}
/* Increment the nesting counter. */
mutex -> tx_linux_mutex_nested_count = 1;
/* Remember the owner. */
mutex -> tx_linux_mutex_owner = pthread_self();
}
}
void _tx_linux_mutex_release(TX_LINUX_MUTEX *mutex)
{
pthread_t current_thread_id;
/* Pickup the current thread ID. */
current_thread_id = pthread_self();
/* Ensure the caller is the mutex owner. */
if (mutex -> tx_linux_mutex_owner == current_thread_id)
{
/* Determine if there is protection. */
if (mutex -> tx_linux_mutex_nested_count)
{
/* Decrement the nesting counter. */
mutex -> tx_linux_mutex_nested_count--;
/* Determine if the critical section is now being released. */
if (mutex -> tx_linux_mutex_nested_count == 0)
{
/* Yes, it is being released clear the owner. */
mutex -> tx_linux_mutex_owner = 0;
/* Finally, release the mutex. */
if (pthread_mutex_unlock(&mutex -> tx_linux_mutex) != 0)
{
/* Increment the system error counter. */
_tx_linux_system_error++;
}
/* Just in case, make sure there the mutex is not owned. */
while (pthread_mutex_unlock(&mutex -> tx_linux_mutex) == 0)
{
/* Increment the system error counter. */
_tx_linux_system_error++;
}
/* Relinquish to other ready threads. */
_tx_linux_thread_sleep(1000);
}
}
}
else
{
/* Increment the system error counter. */
_tx_linux_system_error++;
}
}
void _tx_linux_mutex_release_all(TX_LINUX_MUTEX *mutex)
{
/* Ensure the caller is the mutex owner. */
if (mutex -> tx_linux_mutex_owner == pthread_self())
{
/* Determine if there is protection. */
if (mutex -> tx_linux_mutex_nested_count)
{
/* Clear the nesting counter. */
mutex -> tx_linux_mutex_nested_count = 0;
/* Yes, it is being release clear the owner. */
mutex -> tx_linux_mutex_owner = 0;
/* Finally, release the mutex. */
if (pthread_mutex_unlock(&mutex -> tx_linux_mutex) != 0)
{
/* Increment the system error counter. */
_tx_linux_system_error++;
}
/* Just in case, make sure there the mutex is not owned. */
while (pthread_mutex_unlock(&mutex -> tx_linux_mutex) == 0)
{
/* Increment the system error counter. */
_tx_linux_system_error++;
}
}
}
else
{
/* Increment the system error counter. */
_tx_linux_system_error++;
}
}
void _tx_thread_delete_port_completion(TX_THREAD *thread_ptr, UINT tx_interrupt_save)
{
INT linux_status;
sem_t *threadrunsemaphore;
pthread_t thread_id;
thread_id = thread_ptr -> tx_thread_linux_thread_id;
threadrunsemaphore = &(thread_ptr -> tx_thread_linux_thread_run_semaphore);
_tx_thread_smp_unprotect(tx_interrupt_save);
do
{
linux_status = pthread_cancel(thread_id);
if(linux_status != EAGAIN)
{
break;
}
_tx_linux_thread_resume(thread_id);
tx_linux_sem_post(threadrunsemaphore);
_tx_linux_thread_sleep(1000000);
} while (1);
pthread_join(thread_id, NULL);
sem_destroy(threadrunsemaphore);
tx_interrupt_save = _tx_thread_smp_protect();
}
void _tx_thread_reset_port_completion(TX_THREAD *thread_ptr, UINT tx_interrupt_save)
{
INT linux_status;
sem_t *threadrunsemaphore;
pthread_t thread_id;
thread_id = thread_ptr -> tx_thread_linux_thread_id;
threadrunsemaphore = &(thread_ptr -> tx_thread_linux_thread_run_semaphore);
_tx_thread_smp_unprotect(tx_interrupt_save);
do
{
linux_status = pthread_cancel(thread_id);
if(linux_status != EAGAIN)
{
break;
}
_tx_linux_thread_resume(thread_id);
tx_linux_sem_post(threadrunsemaphore);
_tx_linux_thread_sleep(1000000);
} while (1);
pthread_join(thread_id, NULL);
sem_destroy(threadrunsemaphore);
tx_interrupt_save = _tx_thread_smp_protect();
}

View File

@@ -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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_core_get SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets the currently running core number and returns it.*/
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* Core ID */
/* */
/* CALLS */
/* */
/* pthread_self Get Linux thread ID */
/* _tx_linux_mutex_obtain */
/* _tx_linux_mutex_release */
/* */
/* CALLED BY */
/* */
/* ThreadX Source */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_smp_core_get(void)
{
UINT core;
UINT i;
pthread_t thread_id;
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Default to core 0 for ISRs and initialization. */
core = 0;
/* Pickup the currently executing thread ID. */
thread_id = pthread_self();
/* Loop through mapping table to find the core running this thread ID. */
for (i = 0; i < TX_THREAD_SMP_MAX_CORES; i++)
{
/* Does this core match? */
if (_tx_linux_virtual_cores[i].tx_thread_smp_core_mapping_linux_thread_id == thread_id)
{
/* Yes, we have a match. */
core = i;
/* Get out of loop. */
break;
}
}
/* Unlock linux mutex. */
_tx_linux_mutex_release(&_tx_linux_mutex);
/* Return the core ID. */
return(core);
}

View File

@@ -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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_core_preempt SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function preempts the specified core in situations where the */
/* thread corresponding to this core is no longer ready or when the */
/* core must be used for a higher-priority thread. If the specified is */
/* the current core, this processing is skipped since the will give up */
/* control subsequently on its own. */
/* */
/* INPUT */
/* */
/* core The core to preempt */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* ReleaseSemaphore Let scheduler run to preempt */
/* thread on core */
/* _tx_win32_debug_entry_insert Make debug log entry */
/* */
/* CALLED BY */
/* */
/* ThreadX Source */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
void _tx_thread_smp_core_preempt(UINT core)
{
TX_THREAD *preempt_thread;
/* Protection is in force at this point. */
/* Pickup the thread pointer on the selected core. */
preempt_thread = _tx_thread_current_ptr[core];
/* Determine if there is a thread to preempt. */
if (preempt_thread)
{
/* Yes, set the deferred preemption flag for this thread. This preemption will be
completed in the scheduler. */
preempt_thread -> tx_thread_linux_deferred_preempt = TX_TRUE;
/* Debug entry. */
_tx_linux_debug_entry_insert("CORE_PREEMPT_deferred", __FILE__, __LINE__);
/* Release the semaphore that the main scheduling thread is waiting
on. Note that the main scheduling algorithm will take care of
preempting the thread on this core. */
tx_linux_sem_post(&_tx_linux_scheduler_semaphore);
}
}

View File

@@ -0,0 +1,119 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_current_state_get SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is gets the current state of the calling core. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* pthread_self Get Linux thread ID */
/* _tx_linux_mutex_obtain */
/* _tx_linux_mutex_release */
/* */
/* CALLED BY */
/* */
/* ThreadX Components */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
ULONG _tx_thread_smp_current_state_get(void)
{
UINT core;
UINT i;
ULONG current_state;
pthread_t thread_id;
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Default to core 0 for ISRs and initialization. */
core = 0;
/* Pickup the currently executing thread ID. */
thread_id = pthread_self();
/* Loop through mapping table to find the core running this thread ID. */
for (i = 0; i < TX_THREAD_SMP_MAX_CORES; i++)
{
/* Does this core match? */
if (_tx_linux_virtual_cores[i].tx_thread_smp_core_mapping_linux_thread_id == thread_id)
{
/* Yes, we have a match. */
core = i;
/* Get out of loop. */
break;
}
}
/* Pickup the current state. */
current_state = _tx_thread_system_state[core];
/* Unlock linux mutex. */
_tx_linux_mutex_release(&_tx_linux_mutex);
/* Now return the state for the core. */
return(current_state);
}

View File

@@ -0,0 +1,116 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_current_thread_get SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is gets the current thread of the calling core. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* Current Thread Pointer Pointer to the current thread */
/* */
/* CALLS */
/* */
/* pthread_self Get Linux thread ID */
/* _tx_linux_mutex_obtain */
/* _tx_linux_mutex_release */
/* */
/* CALLED BY */
/* */
/* ThreadX Components */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
TX_THREAD *_tx_thread_smp_current_thread_get(void)
{
UINT core;
UINT i;
pthread_t thread_id;
TX_THREAD *current_thread;
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Default to core 0 for ISRs and initialization. */
core = 0;
/* Pickup the currently executing thread ID. */
thread_id = pthread_self();
/* Loop through mapping table to find the core running this thread ID. */
for (i = 0; i < TX_THREAD_SMP_MAX_CORES; i++)
{
/* Does this core match? */
if (_tx_linux_virtual_cores[i].tx_thread_smp_core_mapping_linux_thread_id == thread_id)
{
/* Yes, we have a match. */
core = i;
/* Get out of loop. */
break;
}
}
/* Pickup current thread. */
current_thread = _tx_thread_current_ptr[core];
/* Unlock linux mutex. */
_tx_linux_mutex_release(&_tx_linux_mutex);
/* Now return the current thread for the core. */
return(current_thread);
}

View File

@@ -0,0 +1,79 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_initialize_wait SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is the place where additional cores wait until */
/* initialization is complete before they enter the thread scheduling */
/* loop. */
/* */
/* Note: Since Linux uses virtual cores, there is nothing to do here. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Hardware */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
void _tx_thread_smp_initialize_wait(void)
{
}

View File

@@ -0,0 +1,79 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_low_level_initialize SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function performs low-level initialization of the booting */
/* core. */
/* */
/* Note: Since Linux uses virtual cores, there is nothing to do here. */
/* */
/* INPUT */
/* */
/* number_of_cores Number of cores */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* _tx_initialize_high_level ThreadX high-level init */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
void _tx_thread_smp_low_level_initialize(UINT number_of_cores)
{
}

View File

@@ -0,0 +1,255 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_protect SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets protection for running inside the ThreadX */
/* source. This is acomplished by a combination of a test-and-set */
/* flag and periodically disabling interrupts. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* Previous Status Register */
/* */
/* CALLS */
/* */
/* pthread_self Get Linux thread ID */
/* GetThreadPriority Get current thread priority */
/* _tx_thread_smp_core_get Get the current core ID */
/* */
/* CALLED BY */
/* */
/* ThreadX Source */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
UINT _tx_thread_smp_protect(void)
{
pthread_t current_thread_id;
int exit_code = 0;
struct sched_param sp;
UINT core;
UINT interrupt_posture;
TX_THREAD *current_thread;
UINT current_state;
/* Loop to attempt to get the protection. */
do
{
/* First, get the critical section. */
do
{
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Pickup the current thread ID. */
current_thread_id = pthread_self();
/* Pickup the current core. */
core = _tx_thread_smp_core_get();
/* Pickup the current thread pointer. */
current_thread = _tx_thread_current_ptr[core];
/* Determine if this is a thread (THREAD_PRIORITY_LOWEST) and it does not
match the current thread pointer. */
if ((_tx_linux_threadx_thread) &&
((!current_thread) || (current_thread -> tx_thread_linux_thread_id != current_thread_id)))
{
/* This indicates the Linux thread was actually terminated by ThreadX is only
being allowed to run in order to cleanup its resources. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* Exit this thread. */
pthread_exit((void *)&exit_code);
}
/* Determine if this is not actually a thread. */
if (!_tx_linux_threadx_thread)
break;
/* Now check for terminated or completed state... and preempt disable is not set! */
if ((current_thread) && (_tx_thread_preempt_disable == 0))
{
/* Pickup current state. */
current_state = current_thread -> tx_thread_state;
/* Now check for terminated or completed state. */
if ((current_state == TX_TERMINATED) || (current_state == TX_COMPLETED))
{
/* Clear the preemption flag. */
current_thread -> tx_thread_linux_deferred_preempt = TX_FALSE;
/* Indicate that this thread was suspended asynchronously. */
current_thread -> tx_thread_linux_suspension_type = 1;
/* Save the remaining time-slice and disable it. */
if (_tx_timer_time_slice[core])
{
current_thread -> tx_thread_time_slice = _tx_timer_time_slice[core];
_tx_timer_time_slice[core] = 0;
}
/* Clear the current thread pointer. */
_tx_thread_current_ptr[core] = TX_NULL;
/* Clear this mapping entry. */
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_linux_thread_id = 0;
/* Indicate that this thread is now ready for scheduling again by another core. */
current_thread -> tx_thread_smp_core_control = 1;
/* Debug entry. */
_tx_linux_debug_entry_insert("SCHEDULE-thread_terminate_preempt_complete", __FILE__, __LINE__);
/* Release the scheduler's semaphore to immediately try again. */
tx_linux_sem_post(&_tx_linux_scheduler_semaphore);
/* This indicates the Linux thread was actually terminated by ThreadX is only
being allowed to run in order to cleanup its resources. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* Exit this thread. */
pthread_exit((void *)&exit_code);
}
}
/* Determine if the deferred preempt flag is set. */
if ((current_thread) && (current_thread -> tx_thread_linux_deferred_preempt))
{
/* Release the scheduler's semaphore to immediately try again. */
tx_linux_sem_post(&_tx_linux_scheduler_semaphore);
/* Release the protection that is nested. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* Sleep just to let other threads run. */
_tx_linux_thread_sleep(1000000);
}
else
{
/* Get out of the protection loop. */
break;
}
} while (1);
/* Setup the returned interrupt posture. */
interrupt_posture = _tx_linux_global_int_disabled_flag;
/* Determine if the protection is already active for this core. */
if (_tx_thread_smp_protection.tx_thread_smp_protect_core == core)
{
/* Yes, we have the protection already. */
/* Increment the protection count. */
_tx_thread_smp_protection.tx_thread_smp_protect_count++;
/* Set the global interrupt disable value. */
_tx_linux_global_int_disabled_flag = TX_TRUE;
/* Debug entry. */
_tx_linux_debug_entry_insert("PROTECT-obtained-nested", __FILE__, __LINE__);
/* Get out of the retry loop. */
break;
}
/* Determine if the protection is available. */
else if (_tx_thread_smp_protection.tx_thread_smp_protect_core == 0xFFFFFFFF)
{
/* At this point we have the protection. Setup the protection structure. */
_tx_thread_smp_protection.tx_thread_smp_protect_in_force = TX_TRUE;
_tx_thread_smp_protection.tx_thread_smp_protect_thread = current_thread;
_tx_thread_smp_protection.tx_thread_smp_protect_core = core;
_tx_thread_smp_protection.tx_thread_smp_protect_count = 1;
_tx_thread_smp_protection.tx_thread_smp_protect_linux_thread_id = current_thread_id;
/* Set the global interrupt disable value. */
_tx_linux_global_int_disabled_flag = TX_TRUE;
/* Debug entry. */
_tx_linux_debug_entry_insert("PROTECT-obtained", __FILE__, __LINE__);
/* Get out of the retry loop. */
break;
}
else
{
/* Protection is owned by another core. */
/* Release the protection and start over. */
_tx_linux_mutex_release(&_tx_linux_mutex);
}
} while (1);
/* Set the global interrupt disable value. */
_tx_linux_global_int_disabled_flag = TX_TRUE;
/* Return the interrupt posture. */
return(interrupt_posture);
}

View File

@@ -0,0 +1,82 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_time_get SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function gets the global time value that is used for debug */
/* information and event tracing. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* 32-bit time stamp */
/* */
/* CALLS */
/* */
/* */
/* CALLED BY */
/* */
/* ThreadX Source */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
ULONG _tx_thread_smp_time_get(void)
{
/* Get the time stamp. */
clock_gettime(CLOCK_REALTIME, &_tx_linux_time_stamp);
/* Return 32-bit time. */
return(((ULONG) (_tx_linux_time_stamp.tv_nsec)));
}

View File

@@ -0,0 +1,140 @@
/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the 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
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_thread.h"
#include "tx_timer.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_smp_unprotect SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function releases previously obtained protection. The supplied */
/* previous interrupt posture is restored. */
/* */
/* INPUT */
/* */
/* Previous interrupt posture */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* pthread_self */
/* */
/* CALLED BY */
/* */
/* ThreadX Source */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
void _tx_thread_smp_unprotect(UINT new_interrupt_posture)
{
UINT core;
pthread_t current_thread_id;
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Pickup the current thread ID. */
current_thread_id = pthread_self();
/* Pickup the current core. */
core = _tx_thread_smp_core_get();
/* Determine if this core owns the protection. */
if (_tx_thread_smp_protection.tx_thread_smp_protect_core == core)
{
/* Yes, this core owns the protection. */
/* Decrement the protection count. */
_tx_thread_smp_protection.tx_thread_smp_protect_count--;
/* Is the protection still in force? */
if (_tx_thread_smp_protection.tx_thread_smp_protect_count == 0)
{
/* Restore the global interrupt disable value. */
_tx_linux_global_int_disabled_flag = new_interrupt_posture;
/* Determine if the preemption disable flag is set. */
if (_tx_thread_preempt_disable == 0)
{
/* Release the protection. */
/* Indicate the protection is no longer in force. */
_tx_thread_smp_protection.tx_thread_smp_protect_in_force = TX_FALSE;
_tx_thread_smp_protection.tx_thread_smp_protect_thread = TX_NULL;
_tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF;
_tx_thread_smp_protection.tx_thread_smp_protect_linux_thread_id = 0;
/* Debug entry. */
_tx_linux_debug_entry_insert("UNPROTECT-keep", __FILE__, __LINE__);
}
else
{
/* Debug entry. */
_tx_linux_debug_entry_insert("UNPROTECT-released", __FILE__, __LINE__);
}
}
else
{
/* Debug entry. */
_tx_linux_debug_entry_insert("UNPROTECT-nested", __FILE__, __LINE__);
}
/* Only release the critical section. */
_tx_linux_mutex_release(&_tx_linux_mutex);
}
/* Release the critical section. */
_tx_linux_mutex_release(&_tx_linux_mutex);
}

View File

@@ -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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_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 SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function builds a stack frame on the supplied thread's stack. */
/* The stack frame results in a fake interrupt return to the supplied */
/* function pointer. */
/* */
/* INPUT */
/* */
/* thread_ptr Pointer to thread control blk */
/* function_ptr Pointer to return function */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* 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 */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
{
struct sched_param sp;
pthread_attr_t attrs;
/* 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. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, TX_LINUX_THREAD_STACK_SIZE);
if(pthread_create(&thread_ptr -> tx_thread_linux_thread_id, &attrs, _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 = 2;
/* Clear the disabled count that will keep track of the
tx_interrupt_control nesting. */
thread_ptr -> tx_thread_linux_mutex_access = TX_FALSE;
/* 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;
/* Indicate that this thread is now ready for scheduling again by another core. */
thread_ptr -> tx_thread_smp_core_control = 1;
}
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(&_tx_linux_scheduler_semaphore);
/* Call ThreadX thread entry point. */
_tx_thread_shell_entry();
return EXIT_SUCCESS;
}

View File

@@ -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 */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_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 SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is target processor specific. It is used to transfer */
/* control from a thread back to the 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_obtain */
/* pthread_self */
/* pthread_getschedparam */
/* pthread_equal */
/* _tx_linux_mutex_release_all */
/* pthread_exit */
/* tx_linux_sem_post */
/* sem_trywait */
/* tx_linux_sem_wait */
/* */
/* CALLED BY */
/* */
/* ThreadX components */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_thread_system_return(VOID)
{
TX_THREAD *temp_thread_ptr;
sem_t *temp_run_semaphore;
UINT temp_thread_state;
pthread_t thread_id;
int exit_code = 0;
UINT core;
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Pickup current core. */
core = _tx_thread_smp_core_get();
/* Debug entry. */
_tx_linux_debug_entry_insert("SYSTEM_RETURN", __FILE__, __LINE__);
/* 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[core];
/* 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_release_all(&_tx_linux_mutex);
pthread_exit((void *)&exit_code);
}
/* Determine if the time-slice is active. */
if (_tx_timer_time_slice[core])
{
/* 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[core];
_tx_timer_time_slice[core] = 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 = 2;
/* Set the current thread pointer to NULL. */
_tx_thread_current_ptr[core] = TX_NULL;
/* Clear this mapping entry. */
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_thread = TX_NULL;
_tx_linux_virtual_cores[core].tx_thread_smp_core_mapping_linux_thread_id = 0;
/* Debug entry. */
_tx_linux_debug_entry_insert("SYSTEM_RETURN-release_sem", __FILE__, __LINE__);
/* Determine if there is a system error. */
if (temp_thread_ptr != _tx_thread_smp_protection.tx_thread_smp_protect_thread)
{
/* This should not happen... increment the system error counter. */
_tx_linux_system_error++;
}
/* Clear the protection structure. */
_tx_thread_smp_protection.tx_thread_smp_protect_count = 0;
_tx_thread_smp_protection.tx_thread_smp_protect_core = 0xFFFFFFFF;
_tx_thread_smp_protection.tx_thread_smp_protect_thread = TX_NULL;
_tx_thread_smp_protection.tx_thread_smp_protect_in_force = TX_FALSE;
_tx_thread_smp_protection.tx_thread_smp_protect_linux_thread_id = 0;
/* Indicate that this thread is now ready for scheduling again by another core. */
temp_thread_ptr -> tx_thread_smp_core_control = 1;
/* Clear the interrupt disable flag. */
_tx_linux_global_int_disabled_flag = TX_FALSE;
/* Clear the preempt disable flag. */
_tx_thread_preempt_disable = 0;
/* Make sure semaphore is 0. */
while(!sem_trywait(&_tx_linux_scheduler_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_scheduler_semaphore);
/* Unlock Linux mutex. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
/* 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(&_tx_linux_scheduler_semaphore);
/* Lock Linux mutex. */
_tx_linux_mutex_obtain(&_tx_linux_mutex);
/* Debug entry. */
_tx_linux_debug_entry_insert("SYSTEM_RETURN-wake_up", __FILE__, __LINE__);
/* Determine if the thread was terminated. */
/* Pickup current core. */
core = _tx_thread_smp_core_get();
/* Pickup the current thread pointer. */
temp_thread_ptr = _tx_thread_current_ptr[core];
/* 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_release_all(&_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. */
/* Debug entry. */
_tx_linux_debug_entry_insert("SYSTEM_RETURN-finish", __FILE__, __LINE__);
/* Unlock Linux mutex. */
_tx_linux_mutex_release_all(&_tx_linux_mutex);
}

View File

@@ -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 */
/** */
/** Timer */
/** */
/**************************************************************************/
/**************************************************************************/
#define TX_SOURCE_CODE
#define TX_THREAD_SMP_SOURCE_CODE
/* Include necessary system files. */
#include "tx_api.h"
#include "tx_timer.h"
#include "tx_thread.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_interrupt SMP/Linux/GCC */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function processes the hardware timer interrupt. This */
/* processing includes incrementing the system clock and checking for */
/* time slice and/or timer expiration. If either is found, the */
/* interrupt context save/restore functions are called along with the */
/* expiration functions. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* _tx_linux_debug_entry_insert */
/* _tx_timer_expiration_process */
/* _tx_thread_time_slice */
/* */
/* CALLED BY */
/* */
/* interrupt vector */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* */
/**************************************************************************/
VOID _tx_timer_interrupt(VOID)
{
UINT saved_posture;
/* Get the protection. */
saved_posture = _tx_thread_smp_protect();
/* Increment the system active counter. */
_tx_timer_interrupt_active++;
/* Debug entry. */
_tx_linux_debug_entry_insert("TIMER INTERRUPT", __FILE__, __LINE__);
/* Increment the system clock. */
_tx_timer_system_clock++;
/* 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)
{
/* Did a timer expire? */
if (_tx_timer_expired)
{
/* Process timer expiration. */
_tx_timer_expiration_process();
}
}
/* Call time-slice processing to process time-slice for all threads on each core. */
_tx_thread_time_slice();
/* Increment the system active counter. */
_tx_timer_interrupt_active++;
/* Release the protection. */
_tx_thread_smp_unprotect(saved_posture);
}