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,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);
}