FreeRTOS / FreeRTOS-Kernel

FreeRTOS kernel files only, submoduled into https://github.com/FreeRTOS/FreeRTOS and various other repos.
https://www.FreeRTOS.org
MIT License
2.8k stars 1.13k forks source link

[BUG] taskEVENT_LIST_ITEM_VALUE_IN_USE breaks xEventGroupWaitBits behaviour #218

Closed denizzzka closed 4 years ago

denizzzka commented 4 years ago

I create event group with one bit:

auto group = xEventGroupCreate();
xEventGroupSetBits(group, 0x01);

Then I want to block another task until receive this message by calling: xEventGroupWaitBits(group, 0x01, pdFALSE, pdFALSE, portMAX_DELAY /* 0xFFFFFFFF */);

Unexpectedly this call immediately returns 0 instead to wait for event.

I walked step by step over code and seen that call inside of xEventGroupWaitBits body

        /* The task blocked to wait for its required bits to be set - at this
         * point either the required bits were set or the block time expired.  If
         * the required bits were set they will have been stored in the task's
         * event list item, and they should now be retrieved then cleared. */
        uxReturn = uxTaskResetEventItemValue(); // <<<< actually returns 0x80000001 instead of 0x00

        if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
        {
            taskENTER_CRITICAL();
            {
                /* The task timed out, just return the current event bit value. */
                uxReturn = pxEventBits->uxEventBits; // <<<< here is obtained right 0x0 value

Looks like it fetches result value from list with taskEVENT_LIST_ITEM_VALUE_IN_USE value and isn't wipes off it. And then it passes into wrong code branch.

Target

Expected behavior Infinity waiting

Additional context For this calls I use DPP generated bindings of FreeRTOS headers for Dlang.

RichardBarry commented 4 years ago

Thanks for taking the time to post this issue, although I'm not sure I understand the bug you are reporting. In your code you create an event group and then set bit 1 before then calling xEventGroupWaitBits() to wait for bit 0 to be set. As bit 0 is already set I would expect xEventGroupWaitBits() to return immediately - which is what you said happens. That would then seem to be the expected behaviour. What am I missing?

denizzzka commented 4 years ago

Thanks for taking the time to post this issue, although I'm not sure I understand the bug you are reporting. In your code you create an event group and then set bit 1 before then calling xEventGroupWaitBits()

Yes, but before or after - it depends on luck because set and wait called inside of two different tasks.

to wait for bit 0 to be set.

Yes

As bit 0 is already set I would expect xEventGroupWaitBits() to return immediately - which is what you said happens.

Yes.

That would then seem to be the expected behaviour. What am I missing?

wait returning value is 0. Zero indicates that time out expired, as I understand. (I am newbie FreeRTOS user)

Non-inifinity waitings returns bits setted inside of event group and then I sucessfully check them to detect what is happen. For example:

        auto r = os.xEventGroupWaitBits(
           group,
           BITS_MASK,
           clearOnExit,
           os.pdFALSE, // xWaitForAllBits
           tmout.toTicks // xTicksToWait
        );

        return r & BITS_MASK;
denizzzka commented 4 years ago

Expected behavior Infinity waiting

Oh, I meant "waiting for 1 bit is set and then want to be able to check it"

RichardBarry commented 4 years ago

I have the following program:

EventBits_t group, returned_value;

void vTask1( void * p )
{
    group = xEventGroupCreate();
    xEventGroupSetBits(group, 0x01);

    for( ;; )
    {
        returned_value = xEventGroupWaitBits(group, 0x01, pdFALSE, pdFALSE, portMAX_DELAY /* 0xFFFFFFFF */);
        configASSERT( returned_value == 0x01 );
        returned_value = xEventGroupWaitBits(group, 0x01, pdFALSE, pdFALSE, 10 );
        configASSERT( returned_value == 0x01 );
        returned_value = xEventGroupWaitBits(group, 0x01, pdTRUE, pdFALSE, 10 );
        configASSERT( returned_value == 0x01 );
    }
}

On the first iteration of the loop all three calls to xEventGroupWaitBits() return immediately and return the expected value. The third call to xEventGroupWaitBits() has the "clear on exit" value set to true, so on the second iteration of the loop the bit isn't set and xEventGroupWaitBits() blocks for ever.

Can you please post a similarly small sequence of code that demonstrates the bug. Thanks.

denizzzka commented 4 years ago

Your snippet also causes this error! (I slightly modified it - added includes, main and debug output)

#include <FreeRTOS.h>
#include <event_groups.h>

EventBits_t group, returned_value;

void vTask1( void * p )
{
    group = xEventGroupCreate();
    xEventGroupSetBits(group, 0x01);

    for(int i = 0;; i++)
    {
        returned_value = xEventGroupWaitBits(group, 0x01, pdFALSE, pdFALSE, portMAX_DELAY /* 0xFFFFFFFF */);
                printf("i=%d %d\n", i, returned_value);
        configASSERT( returned_value == 0x01 ); // fails here on i == 1
        returned_value = xEventGroupWaitBits(group, 0x01, pdFALSE, pdFALSE, 10 );
        configASSERT( returned_value == 0x01 );
        returned_value = xEventGroupWaitBits(group, 0x01, pdTRUE, pdFALSE, 10 );
        configASSERT( returned_value == 0x01 );
    }
}

int main()
{
    vTask1(NULL);
}
$ qemu-system-arm -machine mps2-an511 -nographic -rtc clock=vm -icount shift=2 -semihosting -kernel firmware.elf
i=0 1
i=1 0
assertion "(null)" failed: file "../frtstest.c", line 15

debugger says same: on second loop iteration uxTaskResetEventItemValue call inside of xEventGroupWaitBits returns 0x80000001 and this leads to returning zero.

I have no ideas other than checking compiler options:

[1090/1110] clang -Ifirmware.elf.p -I. -I.. -Xclang -fcolor-diagnostics -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -g -target thumbv7m-unknown-none-eabi -fshort-enums -D_LIBUNWIND_IS_BAREMETAL -D_LIBUNWIND_HAS_NO_THREADS -DSTM32F1 -MD -MQ firmware.elf.p/subprojects_freertos_list.c.o -MF firmware.elf.p/subprojects_freertos_list.c.o.d -o firmware.elf.p/subprojects_freertos_list.c.o -c ../subprojects/freertos/list.c
denizzzka commented 4 years ago

Sources version: 375b08529593e97c7cf29d405fa3af9b98d0cd8a (tag: V10.4.1-kernel-only)

denizzzka commented 4 years ago

Config: https://gist.github.com/denizzzka/5c324517c93e52e256fef2cc5ebba7ce

RichardBarry commented 4 years ago

I am not able to replicate the behaviour you report. Using your code and QEMU command line the first time around the loop I get 0 and 1, as you do. The first call to xEventGroupWaitBits() the second time around the loop never exits because it has an infinite block time - so I don't get any more output. I am using the latest version of FreeRTOS but don't think anything has changed in the event group implementation for some time. Are you using an unmodified version of FreeRTOS? I recommend you get a clean version. Another possibility is that you are getting some data corruption somewhere so check your linker script and start up code too.

denizzzka commented 4 years ago

Are you using an unmodified version of FreeRTOS? I recommend you get a clean version.

Yes, unmodified. Ok, I wiped out freertos sources and fetched current ~master. Issue is still here.

Another possibility is that you are getting some data corruption somewhere so check your linker script and start up code too.

According debugger, group value 0x01 is placed into storage with 0x80000000 addition. I think that is matter may be in the compiler, for example, maybe gcc can cut values while fetching from list into short by some reason and 0x80 prefix is gone?

I use clang compiler:

Debian clang version 11.0.0-++20200928060632+eb83b551d3e-1~exp1~20200928161254.109
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /home/denizzz/bin

Also I grep sources and isn't find where is taskEVENT_LIST_ITEM_VALUE_IN_USE should be removed.

denizzzka commented 4 years ago

Linker script: https://gist.github.com/denizzzka/a657c2d76c7dce19ea12ceb6f6a55110

denizzzka commented 4 years ago

reduced:

    group = xEventGroupCreate();
    xEventGroupSetBits(group, 0x01);

    returned_value = xEventGroupWaitBits(group, 0x01, pdTRUE, pdFALSE, 10 );
    configASSERT( returned_value == 0x01 );

    returned_value = xEventGroupWaitBits(group, 0x01, pdFALSE, pdFALSE, portMAX_DELAY /* 0xFFFFFFFF */);
    configASSERT( returned_value == 0x01 ); // fails here, not fails if first `xEventGroupWaitBits` is removed
denizzzka commented 4 years ago

taskEVENT_LIST_ITEM_VALUE_IN_USE really has nothing to do with it. Waiting ends before of deal with uxTaskResetEventItemValue.

@RichardBarry can you tell me, what portmacro.h you used for qemu-system-arm -machine mps2-an511 hardware? I use GCC/ARM_CM3, maybe this is not correct?

denizzzka commented 4 years ago

Problem found: portYIELD() is not yields. Probably not correct CPU type or something like that. In any case, this is not what is declared in the header of this bug report.

Thanks!

denizzzka commented 3 years ago

For googlers: this is exactly what I running into: https://www.freertos.org/FreeRTOS_Support_Forum_Archive/February_2018/freertos_xEventGroupWaitBits_unexpected_behavior_cd13225cj.html