Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POSIX Simulator: Handle pthreads not created by FreeRTOS differently #1223

Merged
merged 5 commits into from
Jan 25, 2025

Conversation

johnboiles
Copy link
Contributor

@johnboiles johnboiles commented Jan 17, 2025

Avoid calling pthread_sigmask on pthreads not created by FreeRTOS. Also avoids waiting forever on vPortEndScheduler if that's called from a non-FreeRTOS thread.

Description

This PR modifies the behavior of the FreeRTOS POSIX simulator. The tick handler (via sigaction) might happen on any thread in the current process. This can cause hangs with non-FreeRTOS threads (because they can get hung when prvSuspendSelf is called on them.

Test Steps

Run this program against the main branch, notice that it hangs on shutdown.

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <thread>
#include <iostream>
#include <unistd.h>

void appMainTask(void *parameters) {
    while (true) {}
    vTaskDelete(NULL);
}

bool mainLoop() {
    static bool shouldRun = true;
    if (std::cin.peek() != EOF) {
        char input;
        std::cin >> input;
        if (input == 'q') {
            shouldRun = false;
        }
    }
    return shouldRun;
}

auto main(int argc, char *argv[]) -> int {
    // Start the FreeRTOS scheduler
    std::thread schedulerThread([]() {
        xTaskCreate(appMainTask, "app_main", 10000, NULL, 1, NULL);
        vTaskStartScheduler();
        printf("Scheduler thread done\n");
    });

    while (mainLoop()) {
        // Limit to ~60fps so we don't murder battery unnecessarily
        usleep(1000000.0 / 60.0);
    }

    vTaskEndScheduler();
    schedulerThread.join();

    return 0;
}

Now run it again with this change and notice that it shuts down cleanly.

Checklist:

  • I have tested my changes. No regression in existing tests.
  • I have modified and/or added unit-tests to cover the code changes in this Pull Request.

I still need to read up on the test suite. Looking for directional feedback first.

@johnboiles johnboiles requested a review from a team as a code owner January 17, 2025 22:23
@johnboiles johnboiles changed the title Avoid calling pthread_sigmask on pthreads not created by FreeRTOS Posix Simulator: Handle pthreads not created by FreeRTOS differently Jan 17, 2025
@johnboiles johnboiles force-pushed the posix-dont-break-external-threads branch from 6f630dc to aa8fcad Compare January 17, 2025 23:28
Copy link

codecov bot commented Jan 18, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.61%. Comparing base (31dd1e3) to head (aa8fcad).
Report is 8 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1223      +/-   ##
==========================================
- Coverage   91.64%   91.61%   -0.03%     
==========================================
  Files           6        6              
  Lines        3254     3257       +3     
  Branches      903      901       -2     
==========================================
+ Hits         2982     2984       +2     
  Misses        132      132              
- Partials      140      141       +1     
Flag Coverage Δ
unittests 91.61% <ø> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@johnboiles johnboiles changed the title Posix Simulator: Handle pthreads not created by FreeRTOS differently POSIX Simulator: Handle pthreads not created by FreeRTOS differently Jan 18, 2025
@aggarg
Copy link
Member

aggarg commented Jan 21, 2025

The aim of the POSIX port is to aid development of FreeRTOS applications. Why would you want to create native pthreads in a FreeRTOS application?

@johnboiles
Copy link
Contributor Author

johnboiles commented Jan 21, 2025

A simulator program may need other threads to simulate peripheral hardware. For example I need another thread to run my virtual display window that simulates my hardware display. My main FreeRTOS application does not need to know about my display simulator.

On some platforms (I'm experimenting with iOS) the system frameworks create several threads at startup so there are already other threads existing when user code is run. Running my FreeRTOS code on iOS is useful to me as it allows me to easily prototype peripherals like touch screens and HDMI output without bringing up the target hardware (which we haven't received yet).

The current FreeRTOS implementation eventually causes all other threads to lock up.

@hoxi
Copy link

hoxi commented Jan 21, 2025

We’re also using separate (non-FreeRTOS) pthreads to simulate various interrupt sources, and this change aligns well with a pull request we plan to submit. In our case, the interrupt pthreads call different FreeRTOS ISR APIs to inject data into the FreeRTOS application. For this to work, we’ve added an additional port mutex layer to prevent ISR APIs from being executed while FreeRTOS is in a critical section. It would be great to see this patch merged in some form so that we can rebase our planned pull request onto it.

archigup
archigup previously approved these changes Jan 23, 2025
Copy link
Member

@jasonpcarroll jasonpcarroll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great change, and its clear that other users find it valuable as well. Thank you! I just had some minor comments regarding early returns - mainly just to make static analyzers happy since MISRA C will flag it.

portable/ThirdParty/GCC/Posix/port.c Outdated Show resolved Hide resolved
portable/ThirdParty/GCC/Posix/port.c Outdated Show resolved Hide resolved
portable/ThirdParty/GCC/Posix/port.c Outdated Show resolved Hide resolved
@jasonpcarroll
Copy link
Member

Hmm a check is failing but it doesn't seem related to your change... I will look into it.

@archigup archigup merged commit 2b35979 into FreeRTOS:main Jan 25, 2025
16 of 17 checks passed
@jasonpcarroll
Copy link
Member

For now, we will merge this as there is no action needed on this PR. Thanks @johnboiles!

@johnboiles johnboiles deleted the posix-dont-break-external-threads branch January 25, 2025 01:16
@johnboiles
Copy link
Contributor Author

Thanks for getting this in there!

aggarg added a commit to aggarg/FreeRTOS-Kernel that referenced this pull request Jan 25, 2025
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
@denravonska
Copy link

denravonska commented Jan 29, 2025

Are leak checks a port of the CI? After switching to main we started noticing memory leaks in our tests and I'm trying to figure out if it's due to this PR or if we're shutting down incorrectly.

Direct leak of 1 byte(s) in 1 object(s) allocated from:
    #0 0x7ffff78fd891 in malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x5555557ab096 in prvMarkAsFreeRTOSThread ../third-party/freertos/repo/portable/ThirdParty/GCC/Posix/port.c:155
    #2 0x7ffff6aa32cd  (/usr/lib/libc.so.6+0x942cd) (BuildId: aed3a2b0cf4e6cc12296052529af22f6a450a75a)

Edit: Seems to only happen in one of our test suites so I think it's something on our end.
Edit: It was on my end. Interestingly, killing all threads via vTaskEndScheduler then killing the thread again via a C++ destructor will show up as a memory leak.

@aggarg
Copy link
Member

aggarg commented Jan 29, 2025

Thank you for sharing! Which tool are you using for finding these leaks?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants