Skip to content

tests/event_wait_timeout: Fix for 8bit platforms#12776

Merged
kaspar030 merged 5 commits intoRIOT-OS:masterfrom
maribu:test_event_wait_timeout
May 5, 2020
Merged

tests/event_wait_timeout: Fix for 8bit platforms#12776
kaspar030 merged 5 commits intoRIOT-OS:masterfrom
maribu:test_event_wait_timeout

Conversation

@maribu
Copy link
Copy Markdown
Member

@maribu maribu commented Nov 21, 2019

Contribution description

  • Fix a potential issue with the use of a regular global variable for communication between thread and IRQ context
  • Fixed US_PER_MS and friends to be safely used when sizeof(unsigned) < sizeof(uint32_t). Citing the commit message:

The macros US_PER_MS and friends are assumed to be 32 bit unsigned integers by users. However, e.g. on AVR a 1000U is only 16 bit long. Thus, e.g. xtimer_usleep(100 * US_PER_MS) will wrap around and only sleep for ~34ms.

This commit ensures that they are treated as 32 bit unsigned integers on all
platforms.

Testing procedure

  • tests/event_wait_timeout should now work on ATmega

Issues/PRs references

Tick second item in #12651

@maribu maribu added Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR CI: run tests If set, CI server will run tests on hardware for the labeled PR labels Nov 21, 2019
@maribu maribu requested a review from aabadie November 21, 2019 22:49
@maribu
Copy link
Copy Markdown
Member Author

maribu commented Nov 21, 2019

This took me ages to understand why the xtimer which was more distant in the future was added in xtimer_t *timer_list_head before the xtimer that was sooner to fire.

@aabadie
Copy link
Copy Markdown
Contributor

aabadie commented Nov 22, 2019

I confirm this PR is fixing tests/event_wait_timeout on AVR (tested on atmega328p and atmega-mega2560).

There are other issues reported by Murdock with tests/xtimer_msg.

Maybe @smlng could also have a look since he already worked on fixing xtimer macros.

@aabadie aabadie added Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines labels Nov 22, 2019
@maribu maribu removed the CI: run tests If set, CI server will run tests on hardware for the labeled PR label Nov 22, 2019
Copy link
Copy Markdown
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

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

We're using "LU" everywhere else instead of casts to type.

* @brief The number of microseconds per second
*/
#define US_PER_SEC (1000000U)
#define US_PER_SEC ((uint32_t)1000000U)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we please use (1000000LU)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I tried that, but that yielded 100+ compilation errors as PRIu32 expects unsigned int, not unsinged long. Even though they are the same. But the cast clearly doesn't work, as other code is using US_PER_SEC in preprocessor #if statements. They don't work with types...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you keep the UL here but add the cast where needed in tests/xtimer_msg ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Let me first try to weasel around this by using U on systems with sizeof(unsinged) == sizeof(uint32_t)andLUon other systems. With usingLU` unconditionally, the number of compilation issues was huge...

Also: I think users can rightfully expect that PRIu32 should work with something like e.g. US_PER_SEC * 200. The only way to solve this (except for the casts to uint32_t) is to make the postfix dependent on the integer width.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

OK. The current approach at least works locally. Let's wait for Murdock to confirm.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

uff, but it is mega hacky and different to everywhere else in the code.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

... but also quite contained and practical...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Still fails (which I currently fail to understand). I need to think about this for some time. Maybe there is a cleaner solution that just didn't occur to me yet.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

OK. On ESP32 without an explicit #include <limits.h> is needed. (I was pretty sure that an #include <stdint.h> should have also provided UINT_MAX, but maybe I was wrong.)

@maribu
Copy link
Copy Markdown
Member Author

maribu commented Nov 22, 2019

OK. With the code now (hopefully!) compiling on all platforms, so that MS_PER_USEC * 100 would yield reliably an uint32_t on every platform, it is time to decide if we want this solution.

The only two other solutions I have in mind are:

  1. Use C casts to uint32_t. But that would break some other code that does things like #if MS_PER_USED * 50 < FOO, in which casts are not valid. And some MAC layer code actually does something like this, so this is not hypothetical.
  2. Always use LU as postfix. But e.g. xtimer_usleep() requires uint32_t. At least clang is very unhappy if you pass a long instead of an int; even when they happen to have the same representation and value range. And on 32 bit platforms uint32_t is defined as unsigned int, so this would also potentially bite us later.

@maribu
Copy link
Copy Markdown
Member Author

maribu commented Nov 26, 2019

@kaspar030: What is the verdict on this?

Summing up the approaches to fix the issue that were discussed so far, and their pros and cons:

  1. Consistently define US_PER_MS and friends as (1000LU)
    • 👍 Simple, readable
    • 👍 Yields 32 bit unsigned integers on all supported platforms (at least I believe so)
    • 👎 Compiler errors on printf() with PRIu32, as uint32_t is unsigned int and not unsigned long on 32 bit architectures
    • 👎 Potential compiler errors on calls to xtimer_usleep(42 * US_PER_MS), as unsigned long and uint32_t are formally not the same on 32 bit platforms. (At least I had clang complying about this at some point in time, but I don't remember the warning config.)
  2. Use a c style cast to uint32_t, e.g. #define US_PER_MS ((uint32_t)1000)
    • 👍 Reliably yields uint32_t on every platform, so printf("%" PRIu32, US_PER_MS) with PRIu32 and xtimer_usleep(42 * US_PER_MS) will just work
    • 👎 Cannot be used in pre-prosessor statements
    • 👎 Might not be usable for assignments of const variables / struct member (initializer not constant) on some compilers
    • 👎 Ugly
  3. Keep US_PER_MS and friends as they are, every uses needs to ensure that no integer width issue appear
    • 👍 no changes are needed
    • 👎👎👎 latent bugs all over the place
  4. Use postfix LU for non-32bit platforms, and U for 32-bit platforms
    • 👍 Reliably yield uint32_t on every supported platform, so printf("%" PRIu32, US_PER_MS) with PRIu32 and xtimer_usleep(42 * US_PER_MS) will just work
    • 👍 Can be used reliably in per-processor statements and as constant initializer even with prehistoric toolchains (looking at AVR and MSP430)
    • 👎 Ugly

@kaspar030
Copy link
Copy Markdown
Contributor

  • Compiler errors on printf() with PRIu32, as uint32_t is unsigned int and not unsigned long on 32 bit architectures

How many are there? Maybe fixing those is the best option?

Throughout the codebase, we've been using integer literals with type suffixes as needed.

  • -1 Potential compiler errors on calls to xtimer_usleep(42 * US_PER_MS), as unsigned long and uint32_t are formally not the same on 32 bit platforms. (At least I had clang complying about this at some point in time, but I don't remember the warning config.)

This shouldn't happen, as C has legal implicit type conversions, right?

@maribu
Copy link
Copy Markdown
Member Author

maribu commented Nov 26, 2019

This shouldn't happen, as C has legal implicit type conversions, right?

For unsigned this should be indeed be safe. It seems I had the issue with signed int and long. Citing cppreference on this:

  • if the target type can represent the value, the value is unchanged
  • otherwise, if the target type is signed, the behavior is implementation-defined (which may include raising a signal)

So in the current case uint32_t can represent the value of an unsigned long and it is not signed. So just using LU and getting rid of of PRIu32 should indeed work here.

@maribu
Copy link
Copy Markdown
Member Author

maribu commented Apr 23, 2020

I have to rebase in order to be able to fix issues in tests/ztimer_msg, which was not yet part of RIOT when this PR was created.

maribu added 2 commits April 23, 2020 21:16
The test currently uses static globals for communication without any protection.
This could lead optimizing C compilers to deduce that access to those are not
needed (e.g. with LTO enabled). Using C11 atomics is the easiest way to tell
the compiler that those accesses are used for communication between two
different threads of execution (here: between the ISR and the main thread).
The macros US_PER_MS and friends are assumed to be 32 bit unsigned integers
by users. However, e.g. on AVR a `1000U` is only 16 bit long. Thus, e.g.
`xtimer_usleep(100 * US_PER_MS)` will wrap around and only sleep for ~34ms.

This commit declares them as unsigned long, which is on all currently supported
platforms 32 bit wide.
@maribu maribu force-pushed the test_event_wait_timeout branch from 37a8bf2 to 9f75501 Compare April 23, 2020 19:18
@maribu
Copy link
Copy Markdown
Member Author

maribu commented Apr 23, 2020

All green now. Time to cross this issue of the list :-)

@maribu maribu added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels May 5, 2020
@maribu
Copy link
Copy Markdown
Member Author

maribu commented May 5, 2020

@kaspar030: You're comments are addressed and all is green.

Copy link
Copy Markdown
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

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

ACK.

@kaspar030 kaspar030 merged commit 8ffd34d into RIOT-OS:master May 5, 2020
@maribu maribu deleted the test_event_wait_timeout branch May 8, 2020 06:10
@maribu
Copy link
Copy Markdown
Member Author

maribu commented May 8, 2020

Thanks for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants