Преглед изворни кода

feat(freertos): Added FreeRTOS POSIX/Linux Simulator

* Added port layer from the FreeRTOS POSIX port, added
  additional port code for ESP-IDF.
* Created another hello world example using that POSIX
  port in tools/test_apps.
* Removed old linux app
Jakob Hasse пре 3 година
родитељ
комит
bfbbd9d790
28 измењених фајлова са 1380 додато и 168 уклоњено
  1. 9 8
      .gitlab/ci/host-test.yml
  2. 37 0
      components/freertos/CMakeLists.txt
  3. 125 26
      components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro.h
  4. 98 0
      components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h
  5. 59 0
      components/freertos/FreeRTOS-Kernel/portable/linux/include/spinlock.h
  6. 564 0
      components/freertos/FreeRTOS-Kernel/portable/linux/port.c
  7. 164 0
      components/freertos/FreeRTOS-Kernel/portable/linux/port_idf.c
  8. 109 0
      components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.c
  9. 51 0
      components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.h
  10. 2 1
      components/freertos/Kconfig
  11. 27 3
      components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h
  12. 4 3
      docs/en/api-guides/linux-host-testing.rst
  13. 0 5
      examples/build_system/.build-test-rules.yml
  14. 0 10
      examples/build_system/cmake/linux_host_app/CMakeLists.txt
  15. 0 38
      examples/build_system/cmake/linux_host_app/README.md
  16. 0 1
      examples/build_system/cmake/linux_host_app/main/CMakeLists.txt
  17. 0 30
      examples/build_system/cmake/linux_host_app/main/linux_host_app.cpp
  18. 0 3
      examples/build_system/cmake/linux_host_app/sdkconfig.defaults
  19. 0 1
      tools/ci/check_copyright_ignore.txt
  20. 9 4
      tools/mocks/freertos/CMakeLists.txt
  21. 19 10
      tools/mocks/freertos/Kconfig
  22. 0 25
      tools/mocks/freertos/include/FreeRTOSConfig.h
  23. 8 0
      tools/test_apps/.build-test-rules.yml
  24. 7 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/CMakeLists.txt
  25. 45 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/README.md
  26. 4 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt
  27. 24 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c
  28. 15 0
      tools/test_apps/linux_compatible/hello_world_linux_compatible/pytest_hello_world_linux_compatible.py

+ 9 - 8
.gitlab/ci/host-test.yml

@@ -380,6 +380,15 @@ test_esp_event:
     - idf.py build
     - idf.py build
     - build/test_esp_event_host.elf
     - build/test_esp_event_host.elf
 
 
+test_hello_world_linux_compatible_example:
+  extends: .host_test_template
+  script:
+    - cd ${IDF_PATH}/tools/test_apps/linux_compatible/hello_world_linux_compatible
+    - idf.py --preview set-target linux
+    - idf.py build
+    - timeout 15 build/hello_world.elf > test.log
+    - grep "Hello world!" test.log
+
 test_esp_timer_cxx:
 test_esp_timer_cxx:
   extends: .host_test_template
   extends: .host_test_template
   script:
   script:
@@ -429,14 +438,6 @@ test_system_cxx:
     - idf.py build
     - idf.py build
     - build/test_system_cxx_host.elf
     - build/test_system_cxx_host.elf
 
 
-test_linux_example:
-  extends: .host_test_template
-  script:
-    - cd ${IDF_PATH}/examples/build_system/cmake/linux_host_app
-    - idf.py build
-    - timeout 5 ./build/linux_host_app.elf >test.log || true
-    - grep "Restarting" test.log
-
 test_partition_api_host:
 test_partition_api_host:
   extends: .host_test_template
   extends: .host_test_template
   script:
   script:

+ 37 - 0
components/freertos/CMakeLists.txt

@@ -6,6 +6,43 @@ endif()
 
 
 idf_build_get_property(target IDF_TARGET)
 idf_build_get_property(target IDF_TARGET)
 
 
+if(${target} STREQUAL "linux")
+    set(kernel_dir "FreeRTOS-Kernel")
+    set(srcs
+        "${kernel_dir}/portable/linux/port.c"
+        "${kernel_dir}/portable/linux/port_idf.c"
+        "${kernel_dir}/portable/linux/utils/wait_for_event.c"
+        "${kernel_dir}/list.c"
+        "${kernel_dir}/queue.c"
+        "${kernel_dir}/tasks.c"
+        "${kernel_dir}/timers.c"
+        )
+
+    set(include_dirs
+        ${kernel_dir}/include
+        ${kernel_dir}/portable/linux/include  # For arch-specific FreeRTOSConfig_arch.h in portable/<arch>/include
+        ${kernel_dir}/portable/linux/include/freertos
+        "esp_additions/include/freertos" # For config via #include "FreeRTOSConfig.h"
+        "esp_additions/include" # For #include "freertos/task_snapshot.h" and #include "freertos/FreeRTOSConfig.h"
+        )
+
+    set(private_include_dirs
+        ${kernel_dir}/portable/linux
+        ${kernel_dir}/portable/priv_include
+        ${kernel_dir}/include/freertos
+        .
+        )
+
+    idf_component_register(SRCS "${srcs}"
+                        INCLUDE_DIRS ${include_dirs}
+                        PRIV_INCLUDE_DIRS  ${private_include_dirs})
+
+    target_compile_definitions(${COMPONENT_LIB} PUBLIC "projCOVERAGE_TEST=0")
+    target_link_libraries(${COMPONENT_LIB} PUBLIC pthread)
+
+    return()
+endif()
+
 if(CONFIG_FREERTOS_SMP)
 if(CONFIG_FREERTOS_SMP)
     set(ldfragments linker_smp.lf)
     set(ldfragments linker_smp.lf)
     if(CONFIG_IDF_TARGET_ARCH_XTENSA)
     if(CONFIG_IDF_TARGET_ARCH_XTENSA)

+ 125 - 26
components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro.h

@@ -1,42 +1,141 @@
 /*
 /*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ * FreeRTOS Kernel V10.4.6
+ * Copyright 2020 Cambridge Consultants Ltd.
  *
  *
- * SPDX-License-Identifier: Apache-2.0
+ * SPDX-FileCopyrightText: 2020 Cambridge Consultants Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
  */
  */
 
 
-#pragma once
 
 
-#include "esp_attr.h"
-#include <stdint.h>
+#ifndef PORTMACRO_H
+#define PORTMACRO_H
+
+#include <limits.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define portBYTE_ALIGNMENT			16
-#define portTICK_TYPE_IS_ATOMIC		1
+/*-----------------------------------------------------------
+ * Port specific definitions.
+ *
+ * The settings in this file configure FreeRTOS correctly for the
+ * given hardware and compiler.
+ *
+ * These settings should not be altered.
+ *-----------------------------------------------------------
+ */
 
 
 /* Type definitions. */
 /* Type definitions. */
-#define portCHAR		uint8_t
-#define portFLOAT		float
-#define portDOUBLE		double
-#define portLONG		int32_t
-#define portSHORT		int16_t
-#define portSTACK_TYPE	uint8_t
-#define portBASE_TYPE	int
-// interrupt module will mask interrupt with priority less than threshold
-#define RVHAL_EXCM_LEVEL    4
-
-typedef portSTACK_TYPE			StackType_t;
-typedef portBASE_TYPE			BaseType_t;
-typedef unsigned portBASE_TYPE	UBaseType_t;
-typedef uint32_t TickType_t;
-#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
-
-typedef int portMUX_TYPE;
-
-#define portTICK_PERIOD_MS			( ( TickType_t ) 1 )
+#define portCHAR        char
+#define portFLOAT       float
+#define portDOUBLE      double
+#define portLONG        long
+#define portSHORT       short
+#define portSTACK_TYPE  unsigned long
+#define portBASE_TYPE   long
+#define portPOINTER_SIZE_TYPE intptr_t
+
+typedef portSTACK_TYPE StackType_t;
+typedef long BaseType_t;
+typedef unsigned long UBaseType_t;
+
+typedef unsigned long TickType_t;
+#define portMAX_DELAY ( TickType_t ) ULONG_MAX
+
+#define portTICK_TYPE_IS_ATOMIC 1
+
+/*-----------------------------------------------------------*/
+
+/* Architecture specifics. */
+#define portSTACK_GROWTH            ( -1 )
+#define portHAS_STACK_OVERFLOW_CHECKING ( 1 )
+#define portTICK_PERIOD_MS          ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
+#define portTICK_RATE_MICROSECONDS  ( ( TickType_t ) 1000000 / configTICK_RATE_HZ )
+#define portBYTE_ALIGNMENT          8
+/*-----------------------------------------------------------*/
+
+/* Scheduler utilities. */
+extern void vPortYield( void );
+
+#define portYIELD() vPortYield()
+
+#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) vPortYield()
+#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
+/*-----------------------------------------------------------*/
+
+/* Critical section management. */
+extern void vPortDisableInterrupts( void );
+extern void vPortEnableInterrupts( void );
+#define portSET_INTERRUPT_MASK()        ( vPortDisableInterrupts() )
+#define portCLEAR_INTERRUPT_MASK()      ( vPortEnableInterrupts() )
+
+extern portBASE_TYPE xPortSetInterruptMask( void );
+extern void vPortClearInterruptMask( portBASE_TYPE xMask );
+
+extern void vPortEnterCritical( void );
+extern void vPortExitCritical( void );
+#define portSET_INTERRUPT_MASK_FROM_ISR()       xPortSetInterruptMask()
+#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)    vPortClearInterruptMask(x)
+#define portDISABLE_INTERRUPTS()                portSET_INTERRUPT_MASK()
+#define portENABLE_INTERRUPTS()                 portCLEAR_INTERRUPT_MASK()
+#define portENTER_CRITICAL(mux)                 {(void)mux;  vPortEnterCritical();}
+#define portEXIT_CRITICAL(mux)                  {(void)mux;  vPortExitCritical();}
+#define portENTER_CRITICAL_ISR(mux)             portENTER_CRITICAL(mux)
+#define portEXIT_CRITICAL_ISR(mux)              portEXIT_CRITICAL(mux)
+
+/*-----------------------------------------------------------*/
+
+extern void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield );
+extern void vPortCancelThread( void *pxTaskToDelete );
+#define portPRE_TASK_DELETE_HOOK( pvTaskToDelete, pxPendYield ) vPortThreadDying( ( pvTaskToDelete ), ( pxPendYield ) )
+#define portCLEAN_UP_TCB( pxTCB )   vPortCancelThread( pxTCB )
+/*-----------------------------------------------------------*/
+
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+/*-----------------------------------------------------------*/
+
+/*
+ * Tasks run in their own pthreads and context switches between them
+ * are always a full memory barrier. ISRs are emulated as signals
+ * which also imply a full memory barrier.
+ *
+ * Thus, only a compilier barrier is needed to prevent the compiler
+ * reordering.
+ */
+#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
+
+extern unsigned long ulPortGetRunTime( void );
+#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() /* no-op */
+#define portGET_RUN_TIME_COUNTER_VALUE()         ulPortGetRunTime()
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif
+
+// We need additional definitions for ESP-IDF code
+#include "portmacro_idf.h"
+
+#endif /* PORTMACRO_H */

+ 98 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h

@@ -0,0 +1,98 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This is the "IDF-part" of the POSIX portmacro.
+ * We need additional definitions for code in ESP-IDF which is kept here to separate the original
+ * FreeRTOS POSIX port code from the additional IDF POSIX port code.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include "sdkconfig.h"
+#include "esp_attr.h"
+#include "spinlock.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// TODO: IDF-5983 From esp_task.h, should later be used from there
+// or be refactored in IDF (e.g. move esp_task.h to freertos)
+// See also configMINIMAL_STACK_SIZE for more information.
+#define CONFIG_ESP_MAIN_TASK_STACK_SIZE ( ( unsigned short ) (0x4000 + 40) / sizeof(portSTACK_TYPE) ) // should be in Kconfig again
+#define CONFIG_ESP_MAIN_TASK_AFFINITY   0
+
+#define ESP_TASK_PRIO_MAX (configMAX_PRIORITIES)
+#define ESP_TASK_PRIO_MIN (0)
+#define ESP_TASK_MAIN_PRIO            (ESP_TASK_PRIO_MIN + 1)
+#define ESP_TASK_MAIN_STACK           (CONFIG_ESP_MAIN_TASK_STACK_SIZE)
+#define ESP_TASK_MAIN_CORE            CONFIG_ESP_MAIN_TASK_AFFINITY
+
+// interrupt module will mask interrupt with priority less than threshold
+#define RVHAL_EXCM_LEVEL    4
+
+typedef spinlock_t portMUX_TYPE;
+
+/**< Spinlock initializer */
+#define portMUX_INITIALIZER_UNLOCKED {                      \
+            .owner = portMUX_FREE_VAL,                      \
+            .count = 0,                                     \
+        }
+#define portMUX_FREE_VAL                    SPINLOCK_FREE           /**< Spinlock is free. [refactor-todo] check if this is still required */
+
+void vPortYieldFromISR(void);
+void vPortYieldOtherCore(BaseType_t coreid);
+
+#define portMUX_INITIALIZE(mux)             spinlock_initialize(mux)    /*< Initialize a spinlock to its unlocked state */
+
+/**
+ * @brief Get the current core's ID
+ *
+ * @note dummy function for freertos simulator, always returns 0.
+ @ return BaseType_t 0
+ */
+static inline BaseType_t IRAM_ATTR xPortGetCoreID(void)
+{
+    return (BaseType_t) 0;
+}
+
+static inline bool portVALID_TCB_MEM(const void *ptr)
+{
+    return true;
+}
+
+static inline bool portVALID_STACK_MEM(const void *ptr)
+{
+    return true;
+}
+
+#define pvPortMallocTcbMem(size)        pvPortMalloc(size)
+#define pvPortMallocStackMem(size)      pvPortMalloc(size)
+
+BaseType_t xPortCheckIfInISR(void);
+
+/**
+ * @brief Checks if the current core is in an ISR context
+ *
+ * - ISR context consist of Low/Mid priority ISR, or time tick ISR
+ * - High priority ISRs aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
+ *
+ * @note [refactor-todo] Check if this should be inlined
+ * @return
+ *  - pdTRUE if in ISR
+ *  - pdFALSE otherwise
+ */
+static inline BaseType_t xPortInIsrContext(void)
+{
+    //Just call the FreeRTOS port interface version
+    return xPortCheckIfInISR();
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 59 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/include/spinlock.h

@@ -0,0 +1,59 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This file provides only very simple stubs to build IDF-based FreeRTOSes which use spinlocks on Linux.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SPINLOCK_FREE          0xB33FFFFF
+#define SPINLOCK_WAIT_FOREVER  (-1)
+#define SPINLOCK_NO_WAIT        0
+#define SPINLOCK_INITIALIZER   {.owner = SPINLOCK_FREE,.count = 0}
+#define CORE_ID_REGVAL_XOR_SWAP (0xCDCD ^ 0xABAB)
+
+/**
+ * @brief Spinlock object
+ * Owner:
+ *  - Set to 0 if uninitialized
+ *  - Set to portMUX_FREE_VAL when free
+ *  - Set to CORE_ID_REGVAL_PRO or CORE_ID_REGVAL_AP when locked
+ *  - Any other value indicates corruption
+ * Count:
+ *  - 0 if unlocked
+ *  - Recursive count if locked
+ *
+ * @note Not a true spinlock as single core RISC-V does not have atomic compare and set instruction
+ * @note Keep portMUX_INITIALIZER_UNLOCKED in sync with this struct
+ */
+typedef struct {
+    uint32_t owner;
+    uint32_t count;
+}spinlock_t;
+
+static inline void __attribute__((always_inline)) spinlock_initialize(spinlock_t *lock)
+{
+}
+
+static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *lock, int32_t timeout)
+{
+    return true;
+}
+
+static inline void __attribute__((always_inline)) spinlock_release(spinlock_t *lock)
+{
+}
+
+#ifdef __cplusplus
+}
+#endif

+ 564 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/port.c

@@ -0,0 +1,564 @@
+/*
+ * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/*
+ * FreeRTOS Kernel V10.4.3
+ * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/*-----------------------------------------------------------
+ * Implementation of functions defined in portable.h for the Posix port.
+ *
+ * Each task has a pthread which eases use of standard debuggers
+ * (allowing backtraces of tasks etc). Threads for tasks that are not
+ * running are blocked in sigwait().
+ *
+ * Task switch is done by resuming the thread for the next task by
+ * signaling the condition variable and then waiting on a condition variable
+ * with the current thread.
+ *
+ * The timer interrupt uses SIGALRM and care is taken to ensure that
+ * the signal handler runs only on the thread for the current task.
+ *
+ * Use of part of the standard C library requires care as some
+ * functions can take pthread mutexes internally which can result in
+ * deadlocks as the FreeRTOS kernel can switch tasks while they're
+ * holding a pthread mutex.
+ *
+ * stdio (printf() and friends) should be called from a single task
+ * only or serialized with a FreeRTOS primitive such as a binary
+ * semaphore or mutex.
+ *----------------------------------------------------------*/
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <time.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "utils/wait_for_event.h"
+/*-----------------------------------------------------------*/
+
+#define SIG_RESUME SIGUSR1
+
+typedef struct THREAD
+{
+    pthread_t pthread;
+    TaskFunction_t pxCode;
+    void *pvParams;
+    BaseType_t xDying;
+    struct event *ev;
+} Thread_t;
+
+/*
+ * The additional per-thread data is stored at the beginning of the
+ * task's stack.
+ */
+static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask)
+{
+StackType_t *pxTopOfStack = *(StackType_t **)xTask;
+
+    return (Thread_t *)(pxTopOfStack + 1);
+}
+
+/*-----------------------------------------------------------*/
+
+static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
+static sigset_t xAllSignals;
+static sigset_t xSchedulerOriginalSignalMask;
+static pthread_t hMainThread = ( pthread_t )NULL;
+static volatile portBASE_TYPE uxCriticalNesting;
+/*-----------------------------------------------------------*/
+
+static portBASE_TYPE xSchedulerEnd = pdFALSE;
+/*-----------------------------------------------------------*/
+
+static void prvSetupSignalsAndSchedulerPolicy( void );
+static void prvSetupTimerInterrupt( void );
+static void *prvWaitForStart( void * pvParams );
+static void prvSwitchThread( Thread_t * xThreadToResume,
+                             Thread_t *xThreadToSuspend );
+static void prvSuspendSelf( Thread_t * thread);
+static void prvResumeThread( Thread_t * xThreadId );
+static void vPortSystemTickHandler( int sig );
+static void vPortStartFirstTask( void );
+/*-----------------------------------------------------------*/
+
+static void prvFatalError( const char *pcCall, int iErrno )
+{
+    fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
+    abort();
+}
+
+/*
+ * See header file for description.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack,
+                                       portSTACK_TYPE *pxEndOfStack,
+                                       TaskFunction_t pxCode, void *pvParameters )
+{
+Thread_t *thread;
+pthread_attr_t xThreadAttributes;
+size_t ulStackSize;
+int iRet;
+
+    (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
+
+    /*
+     * Store the additional thread data at the start of the stack.
+     */
+    thread = (Thread_t *)(pxTopOfStack + 1) - 1;
+    pxTopOfStack = (portSTACK_TYPE *)thread - 1;
+    ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack);
+
+    thread->pxCode = pxCode;
+    thread->pvParams = pvParameters;
+    thread->xDying = pdFALSE;
+
+    pthread_attr_init( &xThreadAttributes );
+    pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize );
+
+    thread->ev = event_create();
+
+    vPortEnterCritical();
+
+    iRet = pthread_create( &thread->pthread, &xThreadAttributes,
+                           prvWaitForStart, thread );
+    if ( iRet )
+    {
+        prvFatalError( "pthread_create", iRet );
+    }
+
+    vPortExitCritical();
+
+    return pxTopOfStack;
+}
+/*-----------------------------------------------------------*/
+
+void vPortStartFirstTask( void )
+{
+Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    /* Start the first task. */
+    prvResumeThread( pxFirstThread );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * See header file for description.
+ */
+portBASE_TYPE xPortStartScheduler( void )
+{
+int iSignal;
+sigset_t xSignals;
+
+    hMainThread = pthread_self();
+
+    /* Start the timer that generates the tick ISR(SIGALRM).
+       Interrupts are disabled here already. */
+    prvSetupTimerInterrupt();
+
+    /* Start the first task. */
+    vPortStartFirstTask();
+
+    /* Wait until signaled by vPortEndScheduler(). */
+    sigemptyset( &xSignals );
+    sigaddset( &xSignals, SIG_RESUME );
+
+    while ( !xSchedulerEnd )
+    {
+        sigwait( &xSignals, &iSignal );
+    }
+
+    /* Cancel the Idle task and free its resources */
+#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
+    vPortCancelThread( xTaskGetIdleTaskHandle() );
+#endif
+
+#if ( configUSE_TIMERS == 1 )
+    /* Cancel the Timer task and free its resources */
+    vPortCancelThread( xTimerGetTimerDaemonTaskHandle() );
+#endif /* configUSE_TIMERS */
+
+    /* Restore original signal mask. */
+    (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask,  NULL );
+
+    return 0;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEndScheduler( void )
+{
+struct itimerval itimer;
+struct sigaction sigtick;
+Thread_t *xCurrentThread;
+
+    /* Stop the timer and ignore any pending SIGALRMs that would end
+     * up running on the main thread when it is resumed. */
+    itimer.it_value.tv_sec = 0;
+    itimer.it_value.tv_usec = 0;
+
+    itimer.it_interval.tv_sec = 0;
+    itimer.it_interval.tv_usec = 0;
+    (void)setitimer( ITIMER_REAL, &itimer, NULL );
+
+    sigtick.sa_flags = 0;
+    sigtick.sa_handler = SIG_IGN;
+    sigemptyset( &sigtick.sa_mask );
+    sigaction( SIGALRM, &sigtick, NULL );
+
+    /* Signal the scheduler to exit its loop. */
+    xSchedulerEnd = pdTRUE;
+    (void)pthread_kill( hMainThread, SIG_RESUME );
+
+    xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+    prvSuspendSelf(xCurrentThread);
+}
+/*-----------------------------------------------------------*/
+
+void vPortEnterCritical( void )
+{
+    if ( uxCriticalNesting == 0 )
+    {
+        vPortDisableInterrupts();
+    }
+    uxCriticalNesting++;
+}
+/*-----------------------------------------------------------*/
+
+void vPortExitCritical( void )
+{
+    uxCriticalNesting--;
+
+    /* If we have reached 0 then re-enable the interrupts. */
+    if( uxCriticalNesting == 0 )
+    {
+        vPortEnableInterrupts();
+    }
+}
+/*-----------------------------------------------------------*/
+
+void vPortYieldFromISR( void )
+{
+Thread_t *xThreadToSuspend;
+Thread_t *xThreadToResume;
+
+    xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    vTaskSwitchContext();
+
+    xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    prvSwitchThread( xThreadToResume, xThreadToSuspend );
+}
+/*-----------------------------------------------------------*/
+
+void vPortYield( void )
+{
+    vPortEnterCritical();
+
+    vPortYieldFromISR();
+
+    vPortExitCritical();
+}
+/*-----------------------------------------------------------*/
+
+void vPortDisableInterrupts( void )
+{
+    pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
+}
+/*-----------------------------------------------------------*/
+
+void vPortEnableInterrupts( void )
+{
+    pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xPortSetInterruptMask( void )
+{
+    /* Interrupts are always disabled inside ISRs (signals
+       handlers). */
+    return pdTRUE;
+}
+/*-----------------------------------------------------------*/
+
+void vPortClearInterruptMask( portBASE_TYPE xMask )
+{
+}
+/*-----------------------------------------------------------*/
+
+static uint64_t prvGetTimeNs(void)
+{
+struct timespec t;
+
+    clock_gettime(CLOCK_MONOTONIC, &t);
+
+    return t.tv_sec * 1000000000ull + t.tv_nsec;
+}
+
+static uint64_t prvStartTimeNs;
+/* commented as part of the code below in vPortSystemTickHandler,
+ * to adjust timing according to full demo requirements */
+/* static uint64_t prvTickCount; */
+
+/*
+ * Setup the systick timer to generate the tick interrupts at the required
+ * frequency.
+ */
+void prvSetupTimerInterrupt( void )
+{
+struct itimerval itimer;
+int iRet;
+
+    /* Initialise the structure with the current timer information. */
+    iRet = getitimer( ITIMER_REAL, &itimer );
+    if ( iRet )
+    {
+        prvFatalError( "getitimer", errno );
+    }
+
+    /* Set the interval between timer events. */
+    itimer.it_interval.tv_sec = 0;
+    itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS;
+
+    /* Set the current count-down. */
+    itimer.it_value.tv_sec = 0;
+    itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS;
+
+    /* Set-up the timer interrupt. */
+    iRet = setitimer( ITIMER_REAL, &itimer, NULL );
+    if ( iRet )
+    {
+        prvFatalError( "setitimer", errno );
+    }
+
+    prvStartTimeNs = prvGetTimeNs();
+}
+/*-----------------------------------------------------------*/
+
+static void vPortSystemTickHandler( int sig )
+{
+Thread_t *pxThreadToSuspend;
+Thread_t *pxThreadToResume;
+/* uint64_t xExpectedTicks; */
+
+    uxCriticalNesting++; /* Signals are blocked in this signal handler. */
+
+#if ( configUSE_PREEMPTION == 1 )
+    pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+#endif
+
+    /* Tick Increment, accounting for any lost signals or drift in
+     * the timer. */
+/*
+ *      Comment code to adjust timing according to full demo requirements
+ *      xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs)
+ *        / (portTICK_RATE_MICROSECONDS * 1000);
+ * do { */
+        xTaskIncrementTick();
+/*        prvTickCount++;
+ *    } while (prvTickCount < xExpectedTicks);
+*/
+
+#if ( configUSE_PREEMPTION == 1 )
+    /* Select Next Task. */
+    vTaskSwitchContext();
+
+    pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
+
+    prvSwitchThread(pxThreadToResume, pxThreadToSuspend);
+#endif
+
+    uxCriticalNesting--;
+}
+/*-----------------------------------------------------------*/
+
+void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield )
+{
+Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete );
+
+    pxThread->xDying = pdTRUE;
+}
+
+void vPortCancelThread( void *pxTaskToDelete )
+{
+Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
+
+    /*
+     * The thread has already been suspended so it can be safely cancelled.
+     */
+    pthread_cancel( pxThreadToCancel->pthread );
+    pthread_join( pxThreadToCancel->pthread, NULL );
+    event_delete( pxThreadToCancel->ev );
+}
+/*-----------------------------------------------------------*/
+
+static void *prvWaitForStart( void * pvParams )
+{
+Thread_t *pxThread = pvParams;
+
+    prvSuspendSelf(pxThread);
+
+    /* Resumed for the first time, unblocks all signals. */
+    uxCriticalNesting = 0;
+    vPortEnableInterrupts();
+
+    /* Call the task's entry point. */
+    pxThread->pxCode( pxThread->pvParams );
+
+    /* A function that implements a task must not exit or attempt to return to
+    * its caller as there is nothing to return to. If a task wants to exit it
+    * should instead call vTaskDelete( NULL ). Artificially force an assert()
+    * to be triggered if configASSERT() is defined, so application writers can
+        * catch the error. */
+    configASSERT( pdFALSE );
+
+    return NULL;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSwitchThread( Thread_t *pxThreadToResume,
+                             Thread_t *pxThreadToSuspend )
+{
+BaseType_t uxSavedCriticalNesting;
+
+    if ( pxThreadToSuspend != pxThreadToResume )
+    {
+        /*
+         * Switch tasks.
+         *
+         * The critical section nesting is per-task, so save it on the
+         * stack of the current (suspending thread), restoring it when
+         * we switch back to this task.
+         */
+        uxSavedCriticalNesting = uxCriticalNesting;
+
+        prvResumeThread( pxThreadToResume );
+        if ( pxThreadToSuspend->xDying )
+        {
+            pthread_exit( NULL );
+        }
+        prvSuspendSelf( pxThreadToSuspend );
+
+        uxCriticalNesting = uxSavedCriticalNesting;
+    }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSuspendSelf( Thread_t *thread )
+{
+    /*
+     * Suspend this thread by waiting for a pthread_cond_signal event.
+     *
+     * A suspended thread must not handle signals (interrupts) so
+     * all signals must be blocked by calling this from:
+     *
+     * - Inside a critical section (vPortEnterCritical() /
+     *   vPortExitCritical()).
+     *
+     * - From a signal handler that has all signals masked.
+     *
+     * - A thread with all signals blocked with pthread_sigmask().
+        */
+    event_wait(thread->ev);
+}
+
+/*-----------------------------------------------------------*/
+
+static void prvResumeThread( Thread_t *xThreadId )
+{
+    if ( pthread_self() != xThreadId->pthread )
+    {
+        event_signal(xThreadId->ev);
+    }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSetupSignalsAndSchedulerPolicy( void )
+{
+struct sigaction sigresume, sigtick;
+int iRet;
+
+    hMainThread = pthread_self();
+
+    /* Initialise common signal masks. */
+    sigfillset( &xAllSignals );
+    /* Don't block SIGINT so this can be used to break into GDB while
+     * in a critical section. */
+    sigdelset( &xAllSignals, SIGINT );
+
+    /*
+     * Block all signals in this thread so all new threads
+     * inherits this mask.
+     *
+     * When a thread is resumed for the first time, all signals
+     * will be unblocked.
+     */
+    (void)pthread_sigmask( SIG_SETMASK, &xAllSignals,
+                           &xSchedulerOriginalSignalMask );
+
+    /* SIG_RESUME is only used with sigwait() so doesn't need a
+       handler. */
+    sigresume.sa_flags = 0;
+    sigresume.sa_handler = SIG_IGN;
+    sigfillset( &sigresume.sa_mask );
+
+    sigtick.sa_flags = 0;
+    sigtick.sa_handler = vPortSystemTickHandler;
+    sigfillset( &sigtick.sa_mask );
+
+    iRet = sigaction( SIG_RESUME, &sigresume, NULL );
+    if ( iRet )
+    {
+        prvFatalError( "sigaction", errno );
+    }
+
+    iRet = sigaction( SIGALRM, &sigtick, NULL );
+    if ( iRet )
+    {
+        prvFatalError( "sigaction", errno );
+    }
+}
+/*-----------------------------------------------------------*/
+
+unsigned long ulPortGetRunTime( void )
+{
+struct tms xTimes;
+
+    times( &xTimes );
+
+    return ( unsigned long ) xTimes.tms_utime;
+}
+/*-----------------------------------------------------------*/

+ 164 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/port_idf.c

@@ -0,0 +1,164 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/*
+ * This file contains most of the code located in the demo application in the
+ * upstream FreeRTOS repository. It is put here so that IDF applications can
+ * seamlessly switch between Linux and chip targets without the need to provide
+ * or implement additional functionality if the target is the Linux target.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "utils/wait_for_event.h"
+#include "esp_log.h"
+
+static const char *TAG = "port";
+
+static volatile UBaseType_t uxInterruptNesting = 0;
+
+/* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can
+ * use a callback function to optionally provide the memory required by the idle
+ * and timer tasks.  This is the stack that will be used by the timer task.  It is
+ * declared here, as a global, so it can be checked by a test that is implemented
+ * in a different file. */
+StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
+
+BaseType_t xPortCheckIfInISR(void)
+{
+    return uxInterruptNesting;
+}
+
+void app_main(void);
+
+static void main_task(void* args)
+{
+    app_main();
+    vTaskDelete(NULL);
+}
+
+int main(int argc, const char **argv)
+{
+    // This makes sure that stdio is flushed after each '\n' so that idf.py monitor
+    // reads the program output on time.
+    setvbuf(stdout, NULL, _IOLBF, 0);
+
+    usleep(1000);
+    portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
+                                                ESP_TASK_MAIN_STACK, NULL,
+                                                ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
+    assert(res == pdTRUE);
+    (void)res;
+
+    ESP_LOGI(TAG, "Starting scheduler.");
+    vTaskStartScheduler();
+
+    // This line should never be reached
+    assert(false);
+}
+
+void esp_vApplicationIdleHook(void)
+{
+    /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
+     * to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
+     * task.  It is essential that code added to this hook function never attempts
+     * to block in any way (for example, call xQueueReceive() with a block time
+     * specified, or call vTaskDelay()).  If application tasks make use of the
+     * vTaskDelete() API function to delete themselves then it is also important
+     * that vApplicationIdleHook() is permitted to return to its calling function,
+     * because it is the responsibility of the idle task to clean up memory
+     * allocated by the kernel to any task that has since deleted itself. */
+
+
+    usleep( 15000 );
+}
+
+void esp_vApplicationTickHook( void ) { }
+
+#if  (  configUSE_TICK_HOOK > 0 )
+void vApplicationTickHook( void )
+{
+    esp_vApplicationTickHook();
+}
+#endif
+
+void vPortYieldOtherCore( BaseType_t coreid ) { } // trying to skip for now
+
+/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
+ * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
+ * used by the Idle task. */
+void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
+                                    StackType_t ** ppxIdleTaskStackBuffer,
+                                    uint32_t * pulIdleTaskStackSize )
+{
+/* If the buffers to be provided to the Idle task are declared inside this
+ * function then they must be declared static - otherwise they will be allocated on
+ * the stack and so not exists after this function exits. */
+    static StaticTask_t xIdleTaskTCB;
+    static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
+
+    /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
+     * state will be stored. */
+    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
+
+    /* Pass out the array that will be used as the Idle task's stack. */
+    *ppxIdleTaskStackBuffer = uxIdleTaskStack;
+
+    /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
+     * Note that, as the array is necessarily of type StackType_t,
+     * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+    *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
+}
+/*-----------------------------------------------------------*/
+
+/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
+ * application must provide an implementation of vApplicationGetTimerTaskMemory()
+ * to provide the memory that is used by the Timer service task. */
+void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
+                                     StackType_t ** ppxTimerTaskStackBuffer,
+                                     uint32_t * pulTimerTaskStackSize )
+{
+/* If the buffers to be provided to the Timer task are declared inside this
+ * function then they must be declared static - otherwise they will be allocated on
+ * the stack and so not exists after this function exits. */
+    static StaticTask_t xTimerTaskTCB;
+
+    /* Pass out a pointer to the StaticTask_t structure in which the Timer
+     * task's state will be stored. */
+    *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
+
+    /* Pass out the array that will be used as the Timer task's stack. */
+    *ppxTimerTaskStackBuffer = uxTimerTaskStack;
+
+    /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
+     * Note that, as the array is necessarily of type StackType_t,
+     * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
+    *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
+}
+
+void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
+{
+#define ERR_STR1 "***ERROR*** A stack overflow in task "
+#define ERR_STR2 " has been detected."
+    const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2};
+
+    char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = {0};
+
+    char *dest = buf;
+    for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
+        dest = strcat(dest, str[i]);
+    }
+	printf("%s\n", buf);
+    abort();
+}

+ 109 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.c

@@ -0,0 +1,109 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Amazon.com, Inc. or its affiliates
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "wait_for_event.h"
+
+struct event
+{
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    bool event_triggered;
+};
+
+struct event * event_create()
+{
+    struct event * ev = malloc( sizeof( struct event ) );
+
+    ev->event_triggered = false;
+    pthread_mutex_init( &ev->mutex, NULL );
+    pthread_cond_init( &ev->cond, NULL );
+    return ev;
+}
+
+void event_delete( struct event * ev )
+{
+    pthread_mutex_destroy( &ev->mutex );
+    pthread_cond_destroy( &ev->cond );
+    free( ev );
+}
+
+bool event_wait( struct event * ev )
+{
+    pthread_mutex_lock( &ev->mutex );
+
+    while( ev->event_triggered == false )
+    {
+        pthread_cond_wait( &ev->cond, &ev->mutex );
+    }
+
+    ev->event_triggered = false;
+    pthread_mutex_unlock( &ev->mutex );
+    return true;
+}
+bool event_wait_timed( struct event * ev,
+                       time_t ms )
+{
+    struct timespec ts;
+    int ret = 0;
+
+    clock_gettime( CLOCK_REALTIME, &ts );
+    ts.tv_sec += ms / 1000;
+    ts.tv_nsec += ((ms % 1000) * 1000000);
+    pthread_mutex_lock( &ev->mutex );
+
+    while( (ev->event_triggered == false) && (ret == 0) )
+    {
+        ret = pthread_cond_timedwait( &ev->cond, &ev->mutex, &ts );
+
+        if( ( ret == -1 ) && ( errno == ETIMEDOUT ) )
+        {
+            return false;
+        }
+    }
+
+    ev->event_triggered = false;
+    pthread_mutex_unlock( &ev->mutex );
+    return true;
+}
+
+void event_signal( struct event * ev )
+{
+    pthread_mutex_lock( &ev->mutex );
+    ev->event_triggered = true;
+    pthread_cond_signal( &ev->cond );
+    pthread_mutex_unlock( &ev->mutex );
+}

+ 51 - 0
components/freertos/FreeRTOS-Kernel/portable/linux/utils/wait_for_event.h

@@ -0,0 +1,51 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Amazon.com, Inc. or its affiliates
+ *
+ * SPDX-License-Identifier: MIT
+ */
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+#ifndef _WAIT_FOR_EVENT_H_
+#define _WAIT_FOR_EVENT_H_
+
+#include <stdbool.h>
+#include <time.h>
+
+struct event;
+
+struct event * event_create();
+void event_delete( struct event * );
+bool event_wait( struct event * ev );
+bool event_wait_timed( struct event * ev,
+                       time_t ms );
+void event_signal( struct event * ev );
+
+
+
+#endif /* ifndef _WAIT_FOR_EVENT_H_ */

+ 2 - 1
components/freertos/Kconfig

@@ -21,7 +21,7 @@ menu "FreeRTOS"
         config FREERTOS_UNICORE
         config FREERTOS_UNICORE
             # Todo: Replace with CONFIG_NUM_CORES (IDF-4986)
             # Todo: Replace with CONFIG_NUM_CORES (IDF-4986)
             bool "Run FreeRTOS only on first core"
             bool "Run FreeRTOS only on first core"
-            default "y" if IDF_TARGET_ESP32S2
+            default "y" if IDF_TARGET_ESP32S2 || IDF_TARGET_LINUX
             select ESP_SYSTEM_SINGLE_CORE_MODE
             select ESP_SYSTEM_SINGLE_CORE_MODE
             help
             help
                 This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want
                 This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want
@@ -169,6 +169,7 @@ menu "FreeRTOS"
         config FREERTOS_TIMER_TASK_STACK_DEPTH
         config FREERTOS_TIMER_TASK_STACK_DEPTH
             int "configTIMER_TASK_STACK_DEPTH"
             int "configTIMER_TASK_STACK_DEPTH"
             range 1536 32768
             range 1536 32768
+            default 2053 if IDF_TARGET_LINUX
             default 2048
             default 2048
             help
             help
                 Set the timer task's stack size (see configTIMER_TASK_STACK_DEPTH documentation for more details).
                 Set the timer task's stack size (see configTIMER_TASK_STACK_DEPTH documentation for more details).

+ 27 - 3
components/freertos/esp_additions/include/freertos/FreeRTOSConfig.h

@@ -102,8 +102,17 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #endif //configUSE_TICKLESS_IDLE
 #endif //configUSE_TICKLESS_IDLE
 #define configCPU_CLOCK_HZ                              (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * 1000000)
 #define configCPU_CLOCK_HZ                              (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * 1000000)
 #define configTICK_RATE_HZ                              CONFIG_FREERTOS_HZ
 #define configTICK_RATE_HZ                              CONFIG_FREERTOS_HZ
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define configMAX_PRIORITIES                            ( 7 ) // Default in upstream simulator
+/* The stack allocated by FreeRTOS will be passed passed to a pthread.
+   pthread has a minimal stack size which currently is 16KB.
+   The rest is for additional structures of the POSIX/Linux port.
+   This is a magic number since PTHREAD_STACK_MIN seems to not be a constant. */
+#define configMINIMAL_STACK_SIZE                        ( ( unsigned short ) (0x4000 + 40) / sizeof(portSTACK_TYPE) )
+#else
 #define configMAX_PRIORITIES                            ( 25 )  //This has impact on speed of search for highest priority
 #define configMAX_PRIORITIES                            ( 25 )  //This has impact on speed of search for highest priority
 #define configMINIMAL_STACK_SIZE                        ( 768 + configSTACK_OVERHEAD_TOTAL )
 #define configMINIMAL_STACK_SIZE                        ( 768 + configSTACK_OVERHEAD_TOTAL )
+#endif
 #define configUSE_TIME_SLICING                          1
 #define configUSE_TIME_SLICING                          1
 #define configUSE_16_BIT_TICKS                          0
 #define configUSE_16_BIT_TICKS                          0
 #define configIDLE_SHOULD_YIELD                         0
 #define configIDLE_SHOULD_YIELD                         0
@@ -123,9 +132,12 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 
 
 #define configMAX_TASK_NAME_LEN                         CONFIG_FREERTOS_MAX_TASK_NAME_LEN
 #define configMAX_TASK_NAME_LEN                         CONFIG_FREERTOS_MAX_TASK_NAME_LEN
 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS         CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS         CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
-#ifndef CONFIG_IDF_TARGET_LINUX
 #define configSTACK_DEPTH_TYPE                          uint32_t
 #define configSTACK_DEPTH_TYPE                          uint32_t
+#ifndef CONFIG_IDF_TARGET_LINUX
 #define configUSE_NEWLIB_REENTRANT                      1
 #define configUSE_NEWLIB_REENTRANT                      1
+#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H       1
+#else
+#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H       0 // Default in upstream simulator
 #endif
 #endif
 #if CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY
 #if CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY
 #define configENABLE_BACKWARD_COMPATIBILITY             1
 #define configENABLE_BACKWARD_COMPATIBILITY             1
@@ -133,15 +145,18 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #define configENABLE_BACKWARD_COMPATIBILITY             0
 #define configENABLE_BACKWARD_COMPATIBILITY             0
 #endif
 #endif
 #define configASSERT(a)                                 assert(a)
 #define configASSERT(a)                                 assert(a)
-#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H       1
 
 
 // ----------------------- Memory  -------------------------
 // ----------------------- Memory  -------------------------
 
 
 #define configSUPPORT_STATIC_ALLOCATION                 1
 #define configSUPPORT_STATIC_ALLOCATION                 1
 #define configSUPPORT_DYNAMIC_ALLOCATION                1
 #define configSUPPORT_DYNAMIC_ALLOCATION                1
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define configTOTAL_HEAP_SIZE                           ( ( size_t ) ( 65 * 1024 ) ) // Default in upstream simulator
+#else
 //We define the heap to span all of the non-statically-allocated shared RAM. ToDo: Make sure there
 //We define the heap to span all of the non-statically-allocated shared RAM. ToDo: Make sure there
 //is some space left for the app and main cpu when running outside of a thread.
 //is some space left for the app and main cpu when running outside of a thread.
 #define configTOTAL_HEAP_SIZE                           (&_heap_end - &_heap_start)//( ( size_t ) (64 * 1024) )
 #define configTOTAL_HEAP_SIZE                           (&_heap_end - &_heap_start)//( ( size_t ) (64 * 1024) )
+#endif
 #define configAPPLICATION_ALLOCATED_HEAP                1
 #define configAPPLICATION_ALLOCATED_HEAP                1
 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP       0
 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP       0
 
 
@@ -163,9 +178,13 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
 #ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
 #define configGENERATE_RUN_TIME_STATS                   1   /* Used by vTaskGetRunTimeStats() */
 #define configGENERATE_RUN_TIME_STATS                   1   /* Used by vTaskGetRunTimeStats() */
 #endif
 #endif
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define configUSE_TRACE_FACILITY                        1
+#else
 #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
 #ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
 #define configUSE_TRACE_FACILITY                        1   /* Used by uxTaskGetSystemState(), and other trace facility functions */
 #define configUSE_TRACE_FACILITY                        1   /* Used by uxTaskGetSystemState(), and other trace facility functions */
 #endif
 #endif
+#endif
 #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
 #ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
 #define configUSE_STATS_FORMATTING_FUNCTIONS            1   /* Used by vTaskList() */
 #define configUSE_STATS_FORMATTING_FUNCTIONS            1   /* Used by vTaskList() */
 #endif
 #endif
@@ -194,7 +213,6 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #define INCLUDE_uxTaskPriorityGet                       1
 #define INCLUDE_uxTaskPriorityGet                       1
 #define INCLUDE_vTaskDelete                             1
 #define INCLUDE_vTaskDelete                             1
 #define INCLUDE_vTaskSuspend                            1
 #define INCLUDE_vTaskSuspend                            1
-#define INCLUDE_xTaskDelayUntil                         1
 #define INCLUDE_vTaskDelay                              1
 #define INCLUDE_vTaskDelay                              1
 #define INCLUDE_xTaskGetIdleTaskHandle                  1
 #define INCLUDE_xTaskGetIdleTaskHandle                  1
 #define INCLUDE_xTaskAbortDelay                         1
 #define INCLUDE_xTaskAbortDelay                         1
@@ -206,7 +224,13 @@ This file get's pulled into assembly sources. Therefore, some includes need to b
 #define INCLUDE_xTaskResumeFromISR                      1
 #define INCLUDE_xTaskResumeFromISR                      1
 #define INCLUDE_xTimerPendFunctionCall                  1
 #define INCLUDE_xTimerPendFunctionCall                  1
 #define INCLUDE_xTaskGetSchedulerState                  1
 #define INCLUDE_xTaskGetSchedulerState                  1
+#ifdef CONFIG_IDF_TARGET_LINUX
+#define INCLUDE_xTaskGetCurrentTaskHandle               0 // not defined in POSIX simulator
+#define INCLUDE_vTaskDelayUntil                         1
+#else
+#define INCLUDE_xTaskDelayUntil                         1
 #define INCLUDE_xTaskGetCurrentTaskHandle               1
 #define INCLUDE_xTaskGetCurrentTaskHandle               1
+#endif
 //Unlisted
 //Unlisted
 #define INCLUDE_pxTaskGetStackStart                     1
 #define INCLUDE_pxTaskGetStackStart                     1
 
 

+ 4 - 3
docs/en/api-guides/linux-host-testing.rst

@@ -36,10 +36,11 @@ The current focus of the Linux host tests is on creating isolated unit tests of
 
 
 A complete implementation of IDF to run on Linux does not exist currently.
 A complete implementation of IDF to run on Linux does not exist currently.
 
 
-There are currently two examples for running IDF-built code on Linux host: 
+Examples for running IDF-built code on Linux host include (non-exhaustive list): 
 
 
-- An example :example_file:`hello-world application <build_system/cmake/linux_host_app/README.md>` 
-- A :component_file:`unit test for NVS <nvs_flash/host_test/nvs_page_test/README.md>`.
+- :component_file:`unit test for the NVS Page class <nvs_flash/host_test/nvs_page_test/README.md>`.
+- :component_file:`unit test for esp_event <esp_event/host_test/esp_event_unit_test/main/esp_event_test.cpp>`.
+- :component_file:`unit test for mqtt <mqtt/host_test/README.md>`.
 
 
 Inside the component which should be tested, there is a separate directory ``host_test``, besides the "traditional" ``test`` directory or the ``test_apps`` directory. It has one or more subdirectories::
 Inside the component which should be tested, there is a separate directory ``host_test``, besides the "traditional" ``test`` directory or the ``test_apps`` directory. It has one or more subdirectories::
 
 

+ 0 - 5
examples/build_system/.build-test-rules.yml

@@ -6,11 +6,6 @@ examples/build_system/cmake/import_lib:
       temporary: true
       temporary: true
       reason: lack of runners
       reason: lack of runners
 
 
-examples/build_system/cmake/linux_host_app:
-  enable:
-    - if: IDF_TARGET == "linux"
-      reason: only test on linux
-
 examples/build_system/cmake/plugins:
 examples/build_system/cmake/plugins:
   disable_test:
   disable_test:
     - if: IDF_TARGET not in ["esp32", "esp32c3"]
     - if: IDF_TARGET not in ["esp32", "esp32c3"]

+ 0 - 10
examples/build_system/cmake/linux_host_app/CMakeLists.txt

@@ -1,10 +0,0 @@
-cmake_minimum_required(VERSION 3.16)
-
-include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-set(COMPONENTS main)
-
-# Freertos is included via common components, however, currently only the mock component is compatible with linux
-# target.
-list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
-
-project(linux_host_app)

+ 0 - 38
examples/build_system/cmake/linux_host_app/README.md

@@ -1,38 +0,0 @@
-| Supported Targets | Linux |
-| ----------------- | ----- |
-
-This hello-world example builds a simple hello-world application for Linux.
-The compiler used is the Linux-gcc.
-
-There are two major differences to an IDF application built for an ESP chip compared to an application build for Linux:
-
-1. The entry-point on Linux is `int main(int argc, char **argv)`, instead of `void app_main(void)` on an ESP chip.
-   In this example for Linux, the `void app_main(void)` function is still included to make the connection to the IDF entry point clearer.
-   However, it is simply called by `int main(int argc, char **argv)`.
-   Refer to the source file [linux_host_app.cpp](main/linux_host_app.cpp) to see how it is used.
-
-2. The project-level [CMakeLists.txt](CMakeLists.txt) for Linux is different from that of a normal IDF application for an ESP chip.
-   On Linux, there is an additional line `set(COMPONENTS main)`, which clears the common requirements (default dependencies usually included in all IDF applications).
-   This is currently necessary as the Linux-host feature is still under development.
-   Otherwise, a lot of hardware-dependent code would be pulled in.
-
-# Requirements
-Currently, Ruby is required for the mock override of FreeRTOS.
-
-# Build
-Source the IDF environment as usual, then set the Linux target:
-```bash
-idf.py --preview set-target linux
-```
-sdkconfig.defaults sets the Linux target by default, so this not strictly necessary.
-
-Once this is done, build the application:
-```bash
-idf.py build
-```
-Since this application runs on host, the flashing step is unnecessary.
-
-# Run
-```bash
-`build/linux_host_app.elf`
-```

+ 0 - 1
examples/build_system/cmake/linux_host_app/main/CMakeLists.txt

@@ -1 +0,0 @@
-idf_component_register(SRCS "linux_host_app.cpp")

+ 0 - 30
examples/build_system/cmake/linux_host_app/main/linux_host_app.cpp

@@ -1,30 +0,0 @@
-/* Hello World Example
-
-   This example code is in the Public Domain (or CC0 licensed, at your option.)
-
-   Unless required by applicable law or agreed to in writing, this
-   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-   CONDITIONS OF ANY KIND, either express or implied.
-*/
-
-#include "stdio.h"
-#include <unistd.h>
-
-void app_main() {
-    while(1) {
-        printf("Hello, Host!\n");
-
-        for (int i = 10; i >= 0; i--) {
-            printf("Restarting in %d seconds...\n", i);
-            sleep(1);
-        }
-    }
-}
-
-int main(int argc, char **argv)
-{
-    setbuf(stdout, NULL);
-    app_main();
-
-    return 0;
-}

+ 0 - 3
examples/build_system/cmake/linux_host_app/sdkconfig.defaults

@@ -1,3 +0,0 @@
-CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
-CONFIG_IDF_TARGET="linux"
-CONFIG_COMPILER_CXX_EXCEPTIONS=y

+ 0 - 1
tools/ci/check_copyright_ignore.txt

@@ -1582,7 +1582,6 @@ examples/build_system/cmake/import_prebuilt/main/main.c
 examples/build_system/cmake/import_prebuilt/prebuilt/components/prebuilt/prebuilt.c
 examples/build_system/cmake/import_prebuilt/prebuilt/components/prebuilt/prebuilt.c
 examples/build_system/cmake/import_prebuilt/prebuilt/components/prebuilt/prebuilt.h
 examples/build_system/cmake/import_prebuilt/prebuilt/components/prebuilt/prebuilt.h
 examples/build_system/cmake/import_prebuilt/prebuilt/main/main.c
 examples/build_system/cmake/import_prebuilt/prebuilt/main/main.c
-examples/build_system/cmake/linux_host_app/main/linux_host_app.cpp
 examples/build_system/cmake/multi_config/main/func.h
 examples/build_system/cmake/multi_config/main/func.h
 examples/build_system/cmake/multi_config/main/func_dev.c
 examples/build_system/cmake/multi_config/main/func_dev.c
 examples/build_system/cmake/multi_config/main/func_prod.c
 examples/build_system/cmake/multi_config/main/func_prod.c

+ 9 - 4
tools/mocks/freertos/CMakeLists.txt

@@ -4,13 +4,15 @@ message(STATUS "building FREERTOS MOCKS (only task, event-groups and queue)")
 
 
 idf_component_get_property(original_freertos_dir freertos COMPONENT_OVERRIDEN_DIR)
 idf_component_get_property(original_freertos_dir freertos COMPONENT_OVERRIDEN_DIR)
 
 
+set(kernel_dir "${original_freertos_dir}/FreeRTOS-Kernel")
+
 set(include_dirs
 set(include_dirs
-    "include"
-    "${original_freertos_dir}/FreeRTOS-Kernel/include"
+    "${kernel_dir}/include"
     "${original_freertos_dir}/esp_additions/include"
     "${original_freertos_dir}/esp_additions/include"
     "${original_freertos_dir}/esp_additions/include/freertos"
     "${original_freertos_dir}/esp_additions/include/freertos"
-    "${original_freertos_dir}/FreeRTOS-Kernel/include/freertos" # this is due to the way includes are generated in CMock
-    "${original_freertos_dir}/FreeRTOS-Kernel/portable/linux/include")
+    "${kernel_dir}/portable/linux/include" # For FreeRTOSConfig_arch.h
+    "${kernel_dir}/include/freertos" # this is due to the way includes are generated in CMock (without freertos prefix)
+)
 
 
 idf_component_mock(INCLUDE_DIRS ${include_dirs}
 idf_component_mock(INCLUDE_DIRS ${include_dirs}
     REQUIRES esp_common
     REQUIRES esp_common
@@ -18,3 +20,6 @@ idf_component_mock(INCLUDE_DIRS ${include_dirs}
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/task.h
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/task.h
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/event_groups.h
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/event_groups.h
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/queue.h)
     ${original_freertos_dir}/FreeRTOS-Kernel/include/freertos/queue.h)
+
+idf_component_get_property(freertos_lib freertos COMPONENT_LIB)
+target_compile_definitions(${freertos_lib} PUBLIC "projCOVERAGE_TEST=0")

+ 19 - 10
tools/mocks/freertos/Kconfig

@@ -1,13 +1,22 @@
 menu "FreeRTOS"
 menu "FreeRTOS"
-    config FREERTOS_MAX_TASK_NAME_LEN
-        int "Maximum task name length"
-        range 1 256
-        default 16
-        help
-            Changes the maximum task name length. Each task allocated will
-            include this many bytes for a task name. Using a shorter value
-            saves a small amount of RAM, a longer value allows more complex
-            names.
 
 
-            For most uses, the default of 16 is OK.
+    menu "Kernel"
+        config FREERTOS_HZ
+            int "configTICK_RATE_HZ"
+            range 1 1000
+            default 1000
+            help
+                Sets the FreeRTOS tick interrupt frequency in Hz (see configTICK_RATE_HZ documentation for more
+                details).
+
+        config FREERTOS_MAX_TASK_NAME_LEN
+            int "configMAX_TASK_NAME_LEN"
+            range 1 256
+            default 16
+            help
+                Sets the maximum number of characters for task names (see configMAX_TASK_NAME_LEN documentation for
+                more details).
+
+                Note: For most uses, the default of 16 characters is sufficient.
+    endmenu
 endmenu
 endmenu

+ 0 - 25
tools/mocks/freertos/include/FreeRTOSConfig.h

@@ -1,25 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#define STACK_OVERHEAD_CHECKER                          256
-#define STACK_OVERHEAD_OPTIMIZATION                     320
-#define STACK_OVERHEAD_APPTRACE                         1280
-#define STACK_OVERHEAD_WATCHPOINT                       60
-#define configSTACK_OVERHEAD_TOTAL (                              \
-                                    STACK_OVERHEAD_CHECKER +      \
-                                    STACK_OVERHEAD_OPTIMIZATION + \
-                                    STACK_OVERHEAD_APPTRACE +     \
-                                    STACK_OVERHEAD_WATCHPOINT     \
-                                                            )
-#define configMINIMAL_STACK_SIZE                        ( 768 + configSTACK_OVERHEAD_TOTAL )
-#define configMAX_PRIORITIES                            ( 25 )  //This has impact on speed of search for highest priority
-#define configUSE_PREEMPTION                            1
-#define configUSE_IDLE_HOOK                             CONFIG_FREERTOS_USE_IDLE_HOOK
-#define configUSE_TICK_HOOK                             CONFIG_FREERTOS_USE_TICK_HOOK
-#define configUSE_16_BIT_TICKS                          0
-#define configUSE_TRACE_FACILITY 1
-#define configSUPPORT_DYNAMIC_ALLOCATION                1
-#define configUSE_MUTEXES                               1
-#define configUSE_RECURSIVE_MUTEXES                     1

+ 8 - 0
tools/test_apps/.build-test-rules.yml

@@ -11,6 +11,14 @@ tools/test_apps/build_system/ldgen_test:
       temporary: true
       temporary: true
       reason: target esp32c2 is not supported yet
       reason: target esp32c2 is not supported yet
 
 
+tools/test_apps/linux_compatible/hello_world_linux_compatible:
+  enable:
+    - if: INCLUDE_DEFAULT == 1 or IDF_TARGET == "linux"
+  disable_test:
+    - if: IDF_TARGET not in ["esp32", "esp32c3"]
+      temporary: true
+      reason: pytest doesn't support linux target yet, hence, it's tested independenly in the host_tests stage
+
 tools/test_apps/peripherals/usb:
 tools/test_apps/peripherals/usb:
   enable:
   enable:
     - if: IDF_TARGET in ["esp32s2", "esp32s3"]
     - if: IDF_TARGET in ["esp32s2", "esp32s3"]

+ 7 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/CMakeLists.txt

@@ -0,0 +1,7 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(COMPONENTS main)
+project(hello_world)

+ 45 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/README.md

@@ -0,0 +1,45 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | Linux |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | ----- |
+
+# Hello World Example Compatible with POSIX-port
+
+This is a version of the "Hello World" example compatible with the linux target. Just by using `idf.py (--preview) set-target <target>`, it can be compiled for chip targets as well as for the [FreeRTOS POSIX/Linux simulator](https://www.freertos.org/FreeRTOS-simulator-for-Linux.html), i.e., for running it on Linux. The applications can then be run on the chosen target.
+
+## Requirements
+
+If you want to use this example on Linux, you need a Linux machine as host. The remaining requirements are the same requirements as for [Unit Testing on Linux (using cmock)](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/linux-host-testing.html#requirements), except you do not need Ruby.
+
+## How to use example
+
+### Configure the project
+
+No special configuration is required, we also do not recommend changing configuration when compiled for the POSIX/Linux simulator as this is still in preview. If you have to configure something, use the usual IDF menuconfig:
+```
+idf.py menuconfig
+```
+
+### Build and Flash
+
+You can compile this example for chip targets, e.g. ESP32 and then run it by using:
+```
+idf.py set-target esp32
+idf.py build
+idf.py -p <port> flash monitor
+```
+
+If you want to build this example for the linux target and run it, use the same commands except setting the linux target and omitting the flash command:
+```
+idf.py --preview set-target linux
+idf.by build
+idf.py monitor
+```
+The linux target is still in preview, hence the necessary `--preview` argument. Flashing can be omitted on Linux.
+
+
+## Example folder contents
+
+The files in this project have the same structure as the files in the [original Hello World application](../../../../examples/get-started/hello_world/).
+
+## Example Output
+
+The output is similar to the output of the [original Hello World application](../../../../examples/get-started/hello_world/), except that no chip information is printed and there won't be any bootloader output on the linux target.

+ 4 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/main/CMakeLists.txt

@@ -0,0 +1,4 @@
+idf_component_register(SRCS "hello_world_main.c"
+                    INCLUDE_DIRS "")
+
+target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

+ 24 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/main/hello_world_main.c

@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+void app_main(void)
+{
+    printf("Hello world!\n");
+
+    for (int i = 10; i >= 0; i--) {
+        printf("Restarting in %d seconds...\n", i);
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+    printf("Restarting now.\n");
+    fflush(stdout);
+    exit(0);
+}

+ 15 - 0
tools/test_apps/linux_compatible/hello_world_linux_compatible/pytest_hello_world_linux_compatible.py

@@ -0,0 +1,15 @@
+# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: CC0-1.0
+
+import pytest
+from pytest_embedded_idf.dut import IdfDut
+
+# Note that support for Linux target console applications hasn't been implemented for pytest-embedded yet
+# (https://github.com/espressif/pytest-embedded/issues/106)
+
+
+@pytest.mark.esp32
+@pytest.mark.esp32c3
+@pytest.mark.generic
+def test_hello_world_linux_compatible(dut: IdfDut) -> None:
+    dut.expect('Hello world!')