Closed
Description
When testing arc64 glibc hf support (on nSIM/FPGA) I observed sporadic failure of math/test-fenv-tls
cat build/glibc-arc64/build/math/test-fenv-tls.out
FE_INVALID not raised
exceptions not all cleared
FE_INEXACT not raised
It seems the issue was always FP exceptions related (test also checks rounding modes etc which works fine). So created a simple test.
#define TEST_ONE_RAISE(EX) \
do \
{ \
if (feraiseexcept (EX) == 0) \
if (fetestexcept (EX) != EX) \
{ \
printf (#EX " not raised #%d %s\n", i, p); \
ret = 1; \
} \
if (feclearexcept (FE_ALL_EXCEPT) == 0) \
if (fetestexcept (FE_ALL_EXCEPT) != 0) \
{ \
printf ("exceptions not all cleared #%d %s\n", i, p); \
ret = 1; \
} \
} \
while (0)
static void * test_raise (void *arg)
{
intptr_t ret = 0;
char *p = arg;
for (int i = 0; i < 10000; i++)
{
TEST_ONE_RAISE (FE_INEXACT);
}
return (void *) ret;
}
int main(void)
{
int ret = 0;
void *vret;
vret = test_raise("direct");
ret |= (intptr_t) vret;
return ret;
}
This test would always passes.
Next as in original test, adding a thread doing this (in addition to main thread) and was able to hit the problem.
int main(void)
{
int ret = 0;
void *vret;
+ int pret;
+ pthread_t thread_id;
+ pret = pthread_create (&thread_id, NULL, test_raise, "pthread");
vret = test_raise("direct");
ret |= (intptr_t) vret;
+ pret = pthread_join (thread_id, &vret);
return ret;
}
The issue turned out to be FPU_STATUS register which is poked by feraiseexcept / feclearexcept / fetestexcept was not retaining the right value across Linux task switch. This is despite CONFIG_ARC_FPU_SAVE_RESTORE=y in kernel.