Endless loop in 10.4.6 with -Os flag

We are working in a project where we are currently using FreeRTOS 10.4.3 with compiler gcc-arm-none-eabi-10.3-2021.10 building for an NRF52840, in this project we build with the optimization flag -Os and seems to work fine with FreeRTOS 10.4.3.

We tried to upgrade to FreeRTOS 10.4.6 but ran into problems, our application would hang when we built it with -Os but would work when building without optimization. After some debugging we narrowed down the problem to the function prvAddTaskToReadyList() which in turn calls the macro listINSERT_END. This is one of the changes made between 10.4.3 and 10.4.6, the function vListInsertEnd() was replaced with macro listINSERT_END. Currently it is not clear exactly why it is looping endlessly here but we did try as a test to replace the macro listINSERT_END with the function vListInsertEnd() and then it works again (with flag -Os). The looping seems to occur in a while loop that checks if list is empty in function xTaskResumeAll() in tasks.c

Has anyone seen anything similar or has an idea what might be causing this issue?

Any help would be appreciated.

Thanks,
Tomas

Although I can’t confirm the exact problem you’ve encountered it’s possible that GCC with -Os might produce broken code in rare cases. Related to that I had to apply a few workarounds in my application code when migrating to GCC11 with -Os recently where I think I should file a GCC problem report :thinking:
But I’m not aware of such issues with GCC10 (and FreeRTOS 10.4.4 in my case).
While we’are at it, I’ve to admit that I’m not the biggest fan of using macros all over the code. Also because it forcefully blows up code size in the hope of speeding up code execution where not needed/desired/helpful. For instance I’ve to maintain a legacy product where not much code space is left. Hence it’s very sensitive to this kind of changes noticeably affecting code size.
I’d prefer having the choice which kind of optimization is used. Compiler optimizers (at least GCC) can be pretty good controlled also with regard to code inlining.

@rtel Can we use something like this (I’ve added locally while ago when migrating to 10.4.4) ?
Even though I’ve kept it separate it could be better and more readable to use a single config item like configTASK_FORCE_CODE_INLINING… don’t know.

in FreeRTOSConfig.h

// optimize for size (0) vs. speed (1) - see task.c
#ifndef configTASK_INLINED_LIST_REMOVE
#define configTASK_INLINED_LIST_REMOVE      1
#endif
#ifndef configTASK_INLINED_LIST_INSERT_END
#define configTASK_INLINED_LIST_INSERT_END  1
#endif

in task.c

/* optimize for size vs. speed - see list.h */
#if defined( configTASK_INLINED_LIST_REMOVE ) && ( configTASK_INLINED_LIST_REMOVE == 0 )
    #undef  listREMOVE_ITEM
    #define listREMOVE_ITEM (void)uxListRemove
#endif

#if defined( configTASK_INLINED_LIST_INSERT_END ) && ( configTASK_INLINED_LIST_INSERT_END == 0 )
    #undef  listINSERT_END
    #define listINSERT_END  vListInsertEnd
#endif

Fortunately the legacy functions are still there and the added macros are just duplicated code (parts).

I’d also prepare a PR for this, of course.

Hi Tomas -

have you checked for the usual suspecfs, eg stack overflows? Different optimizations will affect the runtime behavior, so you may be seeing a different problem than you think.

Hello,

I did some preliminary testing using your changes and it seems to work for us.

Hi, we are running FreeRTOS on a Nios-II and are blocked from upgrading due to this issue as well. We use GCC 10 and compile using -O2. I’ve been stuck on trying to debug this issue for quite some time, and now I finally got it to work by disabling optimization for the FreeRTOS code.

This is a very serious issue! How can you break support for optimization in one of the most widely used compilers and not even notice it? At least in my experience, things that break when optimization is turned on usually point to undefined behavior in the code.

As long as nobody has waded through the code and determined what really happens, your assumption that FreeRTOS “broke” something is premature. It may have been a c&p application error that hasn’t manifested yet, a dormant GCC optimization bug or whatever.

You are a user of two Open Source/PD products for which you do not pay a cent, but you expect to be entitled to the same quality of support you get from suppliers you pay royalties? Why? How would you react if your company had a free-of-charge packet in their portfolio, and some user would expect a fix for that package with the same aggressiveness?

If you want a quailty and timely solution, how about YOU rolling up your sleeves, wading through the assembly code, pinpointing the exact problem and feeding your insights back to this community? The only other choice you have is put money on the table (either hire a consultant to do it for you or buy into a premium contract such as LTS or through OpenRTOS). “Free” is free and business is business.

Sorry if this sounds a little rude, but I never cease to be amazed how some people appear to forget how Open Source works.

1 Like

This likely has something to do with GCC’s strict-aliasing, which is enabled by default on optimization levels 2 and above. For anyone else running into this issue, it seems that compiling the code with “-fno-strict-aliasing” seems to work fine for us.

1 Like

Thanks for reporting back. That’s the explanation why I didn’t have issues with GCC10 and -Os in my case regardless of using the macros or functions for the list operations.
I had to set-fro-strict-aliasing time ago due to an other reason.
But be warned, as mentioned I had problems with GCC11 and -Os where I tend to blame the GCC11 optimizer. At least I can’t see any UB in the critical piece of code.

We are currently testing -Os using arm-none-eabi-gcc version “(GNU Arm Embedded Toolchain 10-2020-q4-major) 10.2.1 20201103 (release)” and the tests all pass. If it is an aliasing problem, as would be indicated by the suggestion to use -fno-strict-aliasing, then you could also try setting configUSE_MINI_LIST_ITEM to 0 - although I think that option is only available in the git mainline at the moment. We introduced configUSE_MINI_LIST_ITEM in response to other forum posts about aliasing compiler warnings.

Just updated to arm-none-eabi-gcc version (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release) - which I believe is the latest available - but not been able to replicate this issue yet. Using the following compiler options:

-nostartfiles -ffreestanding -mthumb -mcpu=cortex-m3 -Wall -Wextra -g3 -Os -ffunction-sections -fdata-sections

The very latest is GCC 11.2.1 available here.
You’re right that the latest but now deprecated GNU toolchain is 10.3.1.
BTW interestingly I found that omitting -ffunction-sections with -Os produces smaller Cortex-M3 binaries (for me) :thinking: That’s the case since GCC7 at least when I started working with FreeRTOS.
@rtel Do you think the patch proposed before (config to select using macro vs. functions) is worth to created a PR ?

This is the PR that made the change. As can be seen from the check-in comments - the primary purpose was to speed up high frequency code paths, especially the tick interrupt. The other changes are I think selective too - which is why the original functions were not removed.

I’m somewhat reluctant to add code that remaps calls depending on configuration items because it makes the source code less usable (for example, when debugging) - although in reality that is done in several places already to ensure we maintain backward compatibility. In the office we are pondering a FreeRTOS version 11 that would remove that legacy and start clean again.

In this case - what is the difference in the binary size when you build with macros Vs function calls?

The difference for the size constrained app was about 350 bytes with GCC10 -Os and LTO.
You’ see normally it’s almost a no brainer :wink: But in this particular case I’ve to take care.
Well, on the other hand also the PR struggles to rip a few CPU cycles…
However, I’m not yet at the ultimate limit and I could also rip some less important functionality. In fact it’s just a settled boot loader where I could remove some diagnostic functionality now.
BUT as mentioned I’d vote to let the application builder control optimizations like code inlining. It might be useful and works well for some applications on certain platforms but it might not for others having other constraints (and smaller I-caches :wink: )
You can’t really know. Also in terms of debugging macros are also sub-optimal.
I afraid it sounds like a rant now … that’s not my intention !
I surely know how hard it is to create a software platform capable to cover a wide range of use cases and HW platforms. I highly appreciate your work and especially your effort providing a very stable API.
Forget about my PR proposal (I’m also not very happy with it) and good luck with FreeRTOS 11 :+1:

Thanks everyone for your input, really appreciate it.

We did a quick test using -fno-strict-aliasing when building the FreeRTOS components and our application seems to work, at least it doesn’t hang right away (the code size seems to increase just slightly, we need to look a bit more into any effects on performance).