diff options
| author | PProvost <[email protected]> | 2020-05-11 08:55:07 -0600 |
|---|---|---|
| committer | PProvost <[email protected]> | 2020-05-11 08:55:07 -0600 |
| commit | 852421fda03a7722d7adb45b187235cd66fa264e (patch) | |
| tree | b117e1339a047347a3d7ebf3eeb1891168cc9b9b /ports/linux/gnu/src/tx_initialize_low_level_sample.c | |
Initial commit
Diffstat (limited to 'ports/linux/gnu/src/tx_initialize_low_level_sample.c')
| -rw-r--r-- | ports/linux/gnu/src/tx_initialize_low_level_sample.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/ports/linux/gnu/src/tx_initialize_low_level_sample.c b/ports/linux/gnu/src/tx_initialize_low_level_sample.c new file mode 100644 index 00000000..a4bc0c18 --- /dev/null +++ b/ports/linux/gnu/src/tx_initialize_low_level_sample.c @@ -0,0 +1,443 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define TX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <sys/sysinfo.h> + + +/* Define various Linux objects used by the ThreadX port. */ + +pthread_mutex_t _tx_linux_mutex; +sem_t _tx_linux_semaphore; +sem_t _tx_linux_semaphore_no_idle; +ULONG _tx_linux_global_int_disabled_flag; +struct timespec _tx_linux_time_stamp; +__thread int _tx_linux_threadx_thread = 0; + +/* Define signals for linux thread. */ +#define SUSPEND_SIG SIGUSR1 +#define RESUME_SIG SIGUSR2 + +static sigset_t _tx_linux_thread_wait_mask; +static __thread int _tx_linux_thread_suspended; +static sem_t _tx_linux_thread_timer_wait; +static sem_t _tx_linux_thread_other_wait; + +/* Define simulated timer interrupt. This is done inside a thread, which is + how other interrupts may be defined as well. See code below for an + example. */ + +pthread_t _tx_linux_timer_id; +sem_t _tx_linux_timer_semaphore; +sem_t _tx_linux_isr_semaphore; +void *_tx_linux_timer_interrupt(void *p); + + +#ifdef TX_LINUX_DEBUG_ENABLE + +extern ULONG _tx_thread_system_state; +extern UINT _tx_thread_preempt_disable; +extern TX_THREAD *_tx_thread_current_ptr; +extern TX_THREAD *_tx_thread_execute_ptr; + + +/* Define debug log in order to debug Linux issues with this port. */ + +typedef struct TX_LINUX_DEBUG_ENTRY_STRUCT +{ + char *tx_linux_debug_entry_action; + struct timespec tx_linux_debug_entry_timestamp; + char *tx_linux_debug_entry_file; + unsigned long tx_linux_debug_entry_line; + pthread_mutex_t tx_linux_debug_entry_mutex; + unsigned long tx_linux_debug_entry_int_disabled_flag; + ULONG tx_linux_debug_entry_system_state; + UINT tx_linux_debug_entry_preempt_disable; + TX_THREAD *tx_linux_debug_entry_current_thread; + TX_THREAD *tx_linux_debug_entry_execute_thread; +} TX_LINUX_DEBUG_ENTRY; + + +/* Define the maximum size of the Linux debug array. */ + +#ifndef TX_LINUX_DEBUG_EVENT_SIZE +#define TX_LINUX_DEBUG_EVENT_SIZE 400 +#endif + + +/* Define the circular array of Linux debug entries. */ + +TX_LINUX_DEBUG_ENTRY _tx_linux_debug_entry_array[TX_LINUX_DEBUG_EVENT_SIZE]; + + +/* Define the Linux debug index. */ + +unsigned long _tx_linux_debug_entry_index = 0; + + +/* Now define the debug entry function. */ +void _tx_linux_debug_entry_insert(char *action, char *file, unsigned long line) +{ + +pthread_mutex_t temp_copy; + + /* Save the current critical section value. */ + temp_copy = _tx_linux_mutex; + + /* Lock mutex. */ + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Get the time stamp. */ + clock_gettime(CLOCK_REALTIME, &_tx_linux_time_stamp); + + /* Setup the debub entry. */ + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_action = action; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_timestamp = _tx_linux_time_stamp; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_file = file; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_line = line; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_mutex = temp_copy; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_int_disabled_flag = _tx_linux_global_int_disabled_flag; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_system_state = _tx_thread_system_state; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_preempt_disable = _tx_thread_preempt_disable; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_current_thread = _tx_thread_current_ptr; + _tx_linux_debug_entry_array[_tx_linux_debug_entry_index].tx_linux_debug_entry_execute_thread = _tx_thread_execute_ptr; + + /* Now move to the next entry. */ + _tx_linux_debug_entry_index++; + + /* Determine if we need to wrap the list. */ + if (_tx_linux_debug_entry_index >= TX_LINUX_DEBUG_EVENT_SIZE) + { + + /* Yes, wrap the list! */ + _tx_linux_debug_entry_index = 0; + } + + /* Unlock mutex. */ + tx_linux_mutex_unlock(_tx_linux_mutex); +} + +#endif + + +/* Define the ThreadX timer interrupt handler. */ + +void _tx_timer_interrupt(void); + + +/* Define other external function references. */ + +VOID _tx_initialize_low_level(VOID); +VOID _tx_thread_context_save(VOID); +VOID _tx_thread_context_restore(VOID); + + +/* Define other external variable references. */ + +extern VOID *_tx_initialize_unused_memory; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level Linux/GNU */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* William E. Lamie, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* sched_setaffinity */ +/* getpid */ +/* _tx_linux_thread_init */ +/* pthread_setschedparam */ +/* pthread_mutexattr_init */ +/* pthread_mutex_init */ +/* _tx_linux_thread_suspend */ +/* sem_init */ +/* pthread_create */ +/* printf */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 William E. Lamie Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _tx_initialize_low_level(VOID) +{ +struct sched_param sp; +pthread_mutexattr_t attr; + +#ifdef TX_LINUX_MULTI_CORE +cpu_set_t mask; + + sched_getaffinity(getpid(), sizeof(mask), &mask); + if (CPU_COUNT(&mask) > 1) + { + + srand((ULONG)pthread_self()); + + /* Limit this ThreadX simulation on Linux to a single core. */ + CPU_ZERO(&mask); + CPU_SET(rand() % get_nprocs(), &mask); + if (sched_setaffinity(getpid(), sizeof(mask), &mask) != 0) + { + + /* Error restricting the process to one core. */ + printf("ThreadX Linux error restricting the process to one core!\n"); + while(1) + { + } + } + } +#endif + + /* Pickup the first available memory address. */ + + /* Save the first available memory address. */ + _tx_initialize_unused_memory = malloc(TX_LINUX_MEMORY_SIZE); + + /* Init Linux thread. */ + _tx_linux_thread_init(); + + /* Set priority and schedual of main thread. */ + sp.sched_priority = TX_LINUX_PRIORITY_SCHEDULE; + pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp); + + /* Create the system critical section. This is used by the + scheduler thread (which is the main thread) to block all + other stuff out. */ + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_tx_linux_mutex, &attr); + sem_init(&_tx_linux_semaphore, 0, 0); +#ifdef TX_LINUX_NO_IDLE_ENABLE + sem_init(&_tx_linux_semaphore_no_idle, 0, 0); +#endif /* TX_LINUX_NO_IDLE_ENABLE */ + + /* Initialize the global interrupt disabled flag. */ + _tx_linux_global_int_disabled_flag = TX_FALSE; + + /* Create semaphore for timer thread. */ + sem_init(&_tx_linux_timer_semaphore, 0, 0); + + /* Create semaphore for ISR thread. */ + sem_init(&_tx_linux_isr_semaphore, 0, 0); + + /* Setup periodic timer interrupt. */ + if(pthread_create(&_tx_linux_timer_id, NULL, _tx_linux_timer_interrupt, NULL)) + { + + /* Error creating the timer interrupt. */ + printf("ThreadX Linux error creating timer interrupt thread!\n"); + while(1) + { + } + } + + /* Otherwise, we have a good thread create. Now set the priority to + a level lower than the system thread but higher than the application + threads. */ + sp.sched_priority = TX_LINUX_PRIORITY_ISR; + pthread_setschedparam(_tx_linux_timer_id, SCHED_FIFO, &sp); + + /* Done, return to caller. */ +} + + +/* This routine is called after initialization is complete in order to start + all interrupt threads. Interrupt threads in addition to the timer may + be added to this routine as well. */ + +void _tx_initialize_start_interrupts(void) +{ + + /* Kick the timer thread off to generate the ThreadX periodic interrupt + source. */ + tx_linux_sem_post(&_tx_linux_timer_semaphore); +} + + +/* Define the ThreadX system timer interrupt. Other interrupts may be simulated + in a similar way. */ + +void *_tx_linux_timer_interrupt(void *p) +{ +struct timespec ts; +long timer_periodic_nsec; +int err; + + /* Calculate periodic timer. */ + timer_periodic_nsec = 1000000000 / TX_TIMER_TICKS_PER_SECOND; + nice(10); + + /* Wait startup semaphore. */ + tx_linux_sem_wait(&_tx_linux_timer_semaphore); + + while(1) + { + + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += timer_periodic_nsec; + if (ts.tv_nsec > 1000000000) + { + ts.tv_nsec -= 1000000000; + ts.tv_sec++; + } + do + { + if (sem_timedwait(&_tx_linux_timer_semaphore, &ts) == 0) + { + break; + } + err = errno; + } while (err != ETIMEDOUT); + + /* Call ThreadX context save for interrupt preparation. */ + _tx_thread_context_save(); + + /* Call trace ISR enter event insert. */ + _tx_trace_isr_enter_insert(0); + + /* Call the ThreadX system timer interrupt processing. */ + _tx_timer_interrupt(); + + /* Call trace ISR exit event insert. */ + _tx_trace_isr_exit_insert(0); + + /* Call ThreadX context restore for interrupt completion. */ + _tx_thread_context_restore(); + +#ifdef TX_LINUX_NO_IDLE_ENABLE + tx_linux_mutex_lock(_tx_linux_mutex); + + /* Make sure semaphore is 0. */ + while(!sem_trywait(&_tx_linux_semaphore_no_idle)); + + /* Wakeup the system thread by setting the system semaphore. */ + tx_linux_sem_post(&_tx_linux_semaphore_no_idle); + + tx_linux_mutex_unlock(_tx_linux_mutex); +#endif /* TX_LINUX_NO_IDLE_ENABLE */ + } +} + +/* Define functions for linux thread. */ +void _tx_linux_thread_resume_handler(int sig) +{ +} + +void _tx_linux_thread_suspend_handler(int sig) +{ + if(pthread_equal(pthread_self(), _tx_linux_timer_id)) + tx_linux_sem_post_nolock(&_tx_linux_thread_timer_wait); + else + tx_linux_sem_post_nolock(&_tx_linux_thread_other_wait); + + if(_tx_linux_thread_suspended) + return; + + _tx_linux_thread_suspended = 1; + sigsuspend(&_tx_linux_thread_wait_mask); + _tx_linux_thread_suspended = 0; +} + +void _tx_linux_thread_suspend(pthread_t thread_id) +{ + + /* Send signal. */ + tx_linux_mutex_lock(_tx_linux_mutex); + pthread_kill(thread_id, SUSPEND_SIG); + tx_linux_mutex_unlock(_tx_linux_mutex); + + /* Wait until signal is received. */ + if(pthread_equal(thread_id, _tx_linux_timer_id)) + tx_linux_sem_wait(&_tx_linux_thread_timer_wait); + else + tx_linux_sem_wait(&_tx_linux_thread_other_wait); +} + +void _tx_linux_thread_resume(pthread_t thread_id) +{ + + /* Send signal. */ + tx_linux_mutex_lock(_tx_linux_mutex); + pthread_kill(thread_id, RESUME_SIG); + tx_linux_mutex_unlock(_tx_linux_mutex); +} + +void _tx_linux_thread_init() +{ +struct sigaction sa; + + /* Create semaphore for linux thread. */ + sem_init(&_tx_linux_thread_timer_wait, 0, 0); + sem_init(&_tx_linux_thread_other_wait, 0, 0); + + sigfillset(&_tx_linux_thread_wait_mask); + sigdelset(&_tx_linux_thread_wait_mask, RESUME_SIG); + + sigfillset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = _tx_linux_thread_resume_handler; + sigaction(RESUME_SIG, &sa, NULL); + + sa.sa_handler = _tx_linux_thread_suspend_handler; + sigaction(SUSPEND_SIG, &sa, NULL); +} + + |
