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: Clear SIGRESUME (SIGUSR1) when exiting xPortStartScheduler #1224

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

johnboiles
Copy link
Contributor

@johnboiles johnboiles commented Jan 18, 2025

Clear SIGRESUME (SIGUSR1) when exiting xPortStartScheduler

Description

When attempting to stop the scheduler via vTaskEndScheduler, an unhandled SIGUSR1 (aka SIGRESUME) happens when restoring the scheduler thread's signals with pthread_sigmask. This crashes the program.

I'm not sure why this is happening since sigwait is supposed to consume the pending signals. It's possible there's something platform-specific about this. I'm testing on macOS. If the behavior is different on other platforms however, it probably can't hurt to double check. What's particularly interesting is if I modify this code like this:

    while( xSchedulerEnd != pdTRUE )
    {
        int result = sigwait( &xSignals, &iSignal );
        printf("Signal received %d result=%d\n", iSignal, result);

        sigset_t set;
        sigpending( &set );
        if( sigismember( &set, SIG_RESUME ) )
        {
            int result = sigwait( &xSignals, &iSignal );
            printf("Signal received %d result=%d\n", iSignal, result);
        }
    }

I then get this:

Signal received 0 result=0
Signal received 30 result=0

Which means sigwait the first time is returning an invalid signal 0 but also a return code suggesting that it succeeded! Strange!

Test Steps

Testing with this example (full code: freertos-pr1224.zip ):

#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

extern "C" {
    void vAssertCalled(const char *file, int line) {
        fprintf(stderr, "Assertion failed in file %s:%d\n", file, line);
        abort();
    }
}

int main() {
    TaskHandle_t task;
    xTaskCreate(
        [](void *param) {
        printf("FreeRTOS scheduler started\n");
        vTaskDelay(pdMS_TO_TICKS(1000));
        printf("Task Done, ending scheduler\n");
        vTaskEndScheduler();
        assert(false && "After scheduler ended (SHOULD NOT GET HERE)");
    }, "start", 10000, nullptr, 1, &task);
    printf("Starting FreeRTOS scheduler\n");
    vTaskStartScheduler();
    printf("FreeRTOS scheduler exited\n");
    vTaskDelete(task);
}

Without this fix, I see in lldb:

Process 9032 stopped
* thread #1, name = 'Scheduler', queue = 'com.apple.main-thread', stop reason = signal SIGUSR1
    frame #0: 0x00000001815d6620 libsystem_kernel.dylib`__pthread_sigmask + 8
libsystem_kernel.dylib`__pthread_sigmask:
->  0x1815d6620 <+8>:  b.lo   0x1815d6640    ; <+40>
    0x1815d6624 <+12>: pacibsp
    0x1815d6628 <+16>: stp    x29, x30, [sp, #-0x10]!
    0x1815d662c <+20>: mov    x29, sp
Target 0: (freertos_posix_example) stopped.
(lldb) bt
* thread #1, name = 'Scheduler', queue = 'com.apple.main-thread', stop reason = signal SIGUSR1
  * frame #0: 0x00000001815d6620 libsystem_kernel.dylib`__pthread_sigmask + 8
    frame #1: 0x000000018160f680 libsystem_pthread.dylib`pthread_sigmask + 16
    frame #2: 0x000000010000f028 freertos_posix_example`xPortStartScheduler at port.c:322:14
    frame #3: 0x000000010000902c freertos_posix_example`vTaskStartScheduler at tasks.c:3761:18
    frame #4: 0x0000000100003ce8 freertos_posix_example`main at main.cpp:25:5
    frame #5: 0x0000000181290274 dyld`start + 2840
(lldb) f 2
frame #2: 0x000000010000f028 freertos_posix_example`xPortStartScheduler at port.c:322:14
   319 	    #endif /* __APPLE__*/
   320
   321 	    /* Restore original signal mask. */
-> 322 	    ( void ) pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
   323
   324 	    prvDestroyThreadKey();
   325

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.

@johnboiles johnboiles changed the title Clear SIGRESUME (SIGUSR1) when exiting xPortStartScheduler POSIX Simulator: Clear SIGRESUME (SIGUSR1) when exiting xPortStartScheduler Jan 18, 2025
@johnboiles
Copy link
Contributor Author

I'll undo this change in my local fork of FreeRTOS and see if I still have issues. It might be that this was solved by #1223

@johnboiles
Copy link
Contributor Author

I still have this issue, though I don't fully understand why sigwait isn't clearing that signal. There may be a more root-cause-y solution to this, but this is all I've been able to figure out.

@johnboiles johnboiles marked this pull request as ready for review January 29, 2025 21:12
@johnboiles johnboiles requested a review from a team as a code owner January 29, 2025 21:12
@johnboiles johnboiles force-pushed the clear-pending-signals branch from 85c76ce to 94263d2 Compare January 29, 2025 21:42
@aggarg
Copy link
Member

aggarg commented Jan 30, 2025

As you already mentioned, this seems like a hack. Do I need a mac to repro it or is it reproducible on Linux?

@johnboiles
Copy link
Contributor Author

@aggarg I haven't gotten to trying on Linux yet but I can give it a shot. I'm reproducing in macOS with LLDB. I wonder if LLDB could be triggering this strange behavior somehow.

@aggarg
Copy link
Member

aggarg commented Jan 31, 2025

Can you try running without the debugger?

@kar-rahul-aws
Copy link
Member

I tried to reproduce the issue on Ubuntu 20.04 , but running it with or without the debugger, the issue is not reproduced.

Code used

#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

void task_function(void *param) {
    ( void ) param;
    printf("FreeRTOS scheduler started\n");
    vTaskDelay(pdMS_TO_TICKS(1000));
    printf("Task Done, ending scheduler\n");
    vTaskEndScheduler();
    assert(0 && "After scheduler ended (SHOULD NOT GET HERE)");
}

int main_test() {
    TaskHandle_t task;
    xTaskCreate( task_function, "start", 10000, NULL, 1, &task );
    printf("Starting FreeRTOS scheduler\n");
    vTaskStartScheduler();
    printf("FreeRTOS scheduler exited\n");
    vTaskDelete(task);
    return 0;
}

Results after running without debugger

Starting FreeRTOS scheduler
FreeRTOS scheduler started
Task Done, ending scheduler
FreeRTOS scheduler exited

Results after running with debugger

Starting FreeRTOS scheduler
FreeRTOS scheduler started
Task Done, ending scheduler
FreeRTOS scheduler exited
[1] + Done                       "/usr/bin/gdb" --interpreter=mi --tty=${DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-ogdc4hd5.xao" 1>"/tmp/Microsoft-MIEngine-Out-e1s1jg33.5yj"

I also tried your change in xPortStartScheduler which resulted in an invalid signal on MacOS, but the same code returns a valid signal in Ubuntu , and runs only once.

    while( xSchedulerEnd != pdTRUE )
    {
        int result = sigwait( &xSignals, &iSignal );
        printf("Signal received %d result=%d\n", iSignal, result);

        sigset_t set;
        sigpending( &set );
        if( sigismember( &set, SIG_RESUME ) )
        {
            int result = sigwait( &xSignals, &iSignal );
            printf("Signal received %d result=%d\n", iSignal, result);
        }
    }

Result on Ubuntu:

Starting FreeRTOS scheduler
FreeRTOS scheduler started
Task Done, ending scheduler
Signal received 10 result=0
FreeRTOS scheduler exited

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.

3 participants