Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
portable/GCC/Posix: add new port for Posix (Linux) applications
This is similar to the Windows port, allowing FreeRTOS kernel applications to run as regular applications on Posix (Linux) systems. You can use this in a 32-bit or 64-bit application (although there are dynamic memory allocation trace points that do not support 64-bit addresses). Many of the same caveats of running an RTOS on a non-real-time system apply, but this is still very useful for easy debugging/testing applications in a simulated environment. In particular, it allows easy use of tools such as valgrind. You can call standard library functions from tasks but care must be taken with any that internally take mutexes or block. This includes malloc()/free() and many stdio functions (e.g., printf()). Replacement malloc(), free(), realloc(), and calloc() functions are provided which are safe. printf() needs to be called with a FreeRTOS mutex help (or called from only a single task). Each task is run in its own pthread, which makes debugging with standard tools (such as GDB) easier backtraces for individual tasks are available. Threads for non-running tasks are blocked in sigwait(). The stack for each task (thread) is allocated when the thread is created, and the stack provided during task creation is not used. This is so the stack has guard pages, to help with detecting stack overflows. Task switch is done by resuming the thread for the next task by sending it the resume signal (SIGUSR1) and then suspending 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. The additional data needed per-thread is stored at the top on the task's stack. When a running task is being deleted, its thread is marked it as dying so when we switch away from it it exits instead of suspending. This ensures that even if the idle task doesn't run, threads are deleted which allows for more threads to be created (if many tasks are being created and deleted in rapid succession). To further aid debugging, SIGINT (^C) is not blocked inside critical sections. This allows it to be used break into GDB while in a critical section. This means that care must be taken with any custom SIGINT handlers as these are like NMIs. This is somewhat inspired by an existing port by William Davy (https://www.freertos.org/FreeRTOS-simulator-for-Linux.html) but it takes a number of different approaches to make it switch tasks reliableand there's little similarly with the original implementation. - Critical sections block scheduling/"interrupts" by blocking signals using pthread_sigmask(). This is more expensive than attempting to use flags but works reliably and is analogous to the interrupt enable/disable on real hardware. - Care is take to ensure that the SIGALRM handler (for the timer tick) is runnable only on the pthread for the running task. This makes tasks switches more straight-forward and reliable as we can suspend the thread while in the signal handler. - Task switches save/restore the critical nesting on the stack. - Only uses a single (SIGUSR1) signal which is ignored and thus GDB's default signal handling options won't trap/print on this signal. - Extra per-thread data is stored on the task's stack, making it accessible in O(1) instead of performing a O(n) lookup of the array. - Uses the task create/delete hooks in a similar way to the Windows port, rather than overloading trace points.
- Loading branch information