microsoft / vscode-embedded-tools

Official issue tracking repository for Microsoft's Embedded Tools VS Code extension.
MIT License
43 stars 3 forks source link

Calling Certain Thread Functions in TheadX Breaks RTOS Viewer #33

Open Anthony1441 opened 1 year ago

Anthony1441 commented 1 year ago

Type: Bug Report

Description In AzureRTOS, when calling either tx_thread_priority_change or tx_thread_sleep the RTOS Viewer stops being able to get thread information, instead showing "An error occurred while loading details. Make sure the debugger is paused then try again" until the system is restarted, at which point it is again able to see thread information.

In tx_thread_priority_change the specific line that causes the issue is: thread_ptr -> tx_thread_state = TX_PRIORITY_CHANGE; I am consistently able to see information in the view before, but not after running this line.

In tx_thread_sleep the bug is inconsistent, sometimes resulting in an error but sometimes working as intended. After this point until I restart only the "Byte Tool" view is working as intended.

To Reproduce

Expected behavior The RTOS Viewer continues to display information after a priority change or sleep.

Note: launch.json has been modified to hide the cwd and executable. launch.json.txt

benmcmorran commented 1 year ago

Thanks for the report. It looks like internally the extension is being too restrictive with the set of allowed values for tx_thread_state. I'm currently working on a fix, which should be available on our public pre-release channel in a few days.

benmcmorran commented 1 year ago

This issue is fixed in pre-release version 0.5.230202001 of the Embedded Tools. You can switch to the pre-release version (which updates nightly) in the VS Code Marketplace.

image

Anthony1441 commented 1 year ago

This issue is fixed in pre-release version 0.5.230202001 of the Embedded Tools. You can switch to the pre-release version (which updates nightly) in the VS Code Marketplace.

image

Thank you! That did resolve the issue for the specific line, however, there still seems to be a similar issue later on in the priority change function.

The call order of a priority change is: tx_thread_priority_change -> _tx_thread_priority_change -> _tx_thread_system_preempt_check -> _tx_thread_system_return.

The behavior I'm seeing is when _tx_thread_system_return is called inside of the priority change call, another thread (of now higher priority due to the priority change) is now allowed to run, and when control is handed back to the first thread (who's priority was just changed) I get the same error prior to returning from the _tx_thread_system_preempt_check call.

During the time that the second thread is running I am able to view that it is running and see information correctly.

I tested changing the priority of the first thread to a higher priority (as to ensure it continued running when system preempt is called) and the viewer works as intended, so it appears to be an issue related to switching threads.

benmcmorran commented 1 year ago

Thanks for following up. I wasn't switching threads when I originally reproduced the issue, so I'll give that a shot now.

benmcmorran commented 1 year ago

I'm still not able to reproduce this issue. I tried writing a simple ThreadX application that starts two threads at different priorities. The first thread immediately lowers its own priority, and then the second thread sleeps to yield control back to the first thread. Even with a breakpoint set on the last line of _tx_thread_system_preempt_check, I never saw the RTOS view show any errors. Is there something I'm missing in this setup?

RTOS debugging session

#include "tx_api.h"

#define STACK_SIZE 1024
TX_THREAD thread_1, thread_2;
TX_BYTE_POOL byte_pool;
UCHAR memory_area[STACK_SIZE * 3];

void thread_1_entry(ULONG thread_input) {
    // Lower thread 1's priority to 3 to allow thread 2 to run.
    UINT oldPri;
    tx_thread_priority_change(&thread_1, 3, &oldPri);

    while (1) {
        tx_thread_sleep(10);
    }
}

void thread_2_entry(ULONG thread_input) {
    while (1) {
        tx_thread_sleep(10);
    }
}

int main() {
    tx_kernel_enter();
}

void tx_application_define(void *first_unused_memory) {
    tx_byte_pool_create(&byte_pool, "byte pool", memory_area, STACK_SIZE * 3);

    // Thread 1 has priority 1 and thread 2 has priority 2.
    CHAR *pointer = TX_NULL;
    tx_byte_allocate(&byte_pool, (VOID **) &pointer, STACK_SIZE, TX_NO_WAIT);
    tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, pointer,
        STACK_SIZE, 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
    tx_byte_allocate(&byte_pool, (VOID **) &pointer, STACK_SIZE, TX_NO_WAIT);
    tx_thread_create(&thread_2, "thread 2", thread_2_entry, 0, pointer,
        STACK_SIZE, 2, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
}
Anthony1441 commented 1 year ago

Ah I've found the issue, the thread that is switched to upon priority change is waiting for event flags to be set, and in the line below the error occurs when the thread state is changed, similar to when the priority was changed:

In _tx_event_flags_get thread_ptr -> tx_thread_state = TX_EVENT_FLAG;

benmcmorran commented 1 year ago

Thanks! The extension internally does some additional poking around if the thread state is a value like TX_EVENT_FLAG, TX_MUTEX, etc. to try and get details about the RTOS object the thread is blocked on. I'm guessing that sometimes ThreadX puts the thread is in an intermediate state where tx_thread_state has changed but ThreadX's internal data structures aren't ready yet. I'll try to repro again and let you know once I have a fix or if I have any additional questions.