Re: git: 6926e2699ae5 - main - arm: Add support for using VFP in kernel [new: bad floating point data with multi-threading, not a crash]
- Reply: Mark Millard : "Re: git: 6926e2699ae5 - main - arm: Add support for using VFP in kernel [new: bad floating point data with multi-threading, not a crash]"
- In reply to: Mark Millard : "Re: git: 6926e2699ae5 - main - arm: Add support for using VFP in kernel [added new: Called fill_fpregs while the kernel is using the VFP]"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 16 Feb 2023 23:31:13 UTC
I start this message as independent of the prior crash reports:
this is not a crash report. It is a messed-up floating point
data report instead.
I have a simple C++ program that creates 2 independent threads,
each working on just local variables, where it appears that
after a while one thread ends up with a floating point value
from the other thread.
The two threads each just have loops incrementing a unsigned
long long and a double by 1 in the range where no information
is lost, initializing to zero. The cross-check for failure is
if it finds an example of n_as_dbl != (double)n . An example
build-then-run showing a failure is:
# g++12 -std=c++20 -pedantic -g -O3 -pthread -Wl,-rpath=/usr/local/lib/gcc12 dbl_and_ull_multithread.cpp
# ./a.out
95534435.000000 != 95531411
^C
(The program would run for a very long time unless both threads
observe such a failure in a shorter time frame. So the normal
exit is to use control-C (SIGINT).)
So far, the values printed are always similar instead of
random data showing up. This is part of what suggests
that data from the wrong thread has shown up.
Because libc++ does not yet have <syncstream> I build with using
libstdc++. I have demonstrated the problem via libc++ (clang++
and g++12) as well, calling std::abort instead of outputting.
(But that crashes armv7 FreeBSD during the attempt to produce
the core file.)
The C++ program source and how-to-use-comment is:
(whitespace details might not be preserved)
// # g++12 -std=c++20 -pedantic -g -O3 -pthread -Wl,-rpath=/usr/local/lib/gcc12 dbl_and_ull_multithread.cpp
// # ./a.out
// double_value != unsigned_long_long_value
// Use control-C to stop it.
#include <limits> // std::numeric_limits
#include <future> // std::future, std::async, std::launch::async
#include <string> // std::to_string
#include <syncstream> // std::osyncstream
#include <iostream> // std::cout
int main(void) {
static_assert(std::numeric_limits<double>::radix==2,"double's radix is not 2 and is unhandled");
constexpr unsigned int ull_width { std::numeric_limits<unsigned long long>::digits };
constexpr unsigned int dbl_width { std::numeric_limits<double>::digits };
constexpr unsigned int use_width { (dbl_width<ull_width) ? dbl_width : ull_width };
constexpr unsigned long long bound { (1ull<<use_width)-1ull };
auto the_job {
[](){
unsigned long long n { 0ull };
double n_as_dbl= n;
while (n < bound) {
if (n_as_dbl != (double)n) {
std::osyncstream output{std::cout};
output << std::to_string(n_as_dbl) // questionable if still same?
<< " != "
<< std::to_string(n)
<< "\n";
break;
}
n++;
n_as_dbl+= 1.0;
}
}
};
auto thread_0 {
std::async( std::launch::async
, the_job
)
};
auto thread_1 {
std::async( std::launch::async
, the_job
)
};
thread_0.wait();
thread_1.wait();
return 0;
}
===
Mark Millard
marklmi at yahoo.com