Повреждение регистра с плавающей запятой в ARM Cortex A57 (ARMv8) с RT_PREEMPT linux - PullRequest
0 голосов
/ 05 октября 2018

У меня есть многопоточное приложение пользовательского пространства, работающее на Linux RT_PREEMPT на ARM Cortex A57 (ARMv8).Версия для Linux - 4.14.0 с соответствующим патчем RT_PREEMPT.Приведенный ниже код является упрощенной версией для повторного создания проблемы.Когда код компилируется с уровнем оптимизации -O1 и выше, через какое-то время из него выходит ошибка со случайным значением в fl_val (результат умножения в thr_fn) в строке 24.Посмотрев на код скомпилированной сборки и через gdb, заметил, что значение 0,002 загружается в регистр с плавающей запятой (s8) перед началом цикла в строке 21.Значение регистра s8 затем используется для умножения на значение сохранения в регистре в строке 24.В случайное время значение в s8 имеет значение мусора, и процесс прерывается, как и ожидалось.Похоже, что во время переключений контекста ядра он неправильно восстанавливает значения регистров с плавающей запятой.Тот же код прекрасно работает без каких-либо ошибок на не-rt ядре той же версии на том же оборудовании.

Мои вопросы

1) Есть ли какие-либо настройки ядра, связанные с плавающей запятой, которые я должен установить в ядре RT_PREEMPT?Я установил eagerfpu = on (хотя он включен по умолчанию)

2) Читал о «Ленивом стеке» для Cortex-M4, но не уверен, применимо ли это к Cortex A57

Будем благодарны за любые комментарии.

------- Тест-код --------------------------

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdint>
  4 #include <ctime>
  5 #include <random>
  6 #include <pthread.h>
  7 #include <string.h>
  8 #include <errno.h>
  9 #include <unistd.h>
 10 #include <signal.h>
 11 
 12 #define MAX_THR 30
 13 
 14 typedef float float32_t;
 15 int32_t gflag = 0;
 16 
 17 void *thr_fn(void *arg) {
 18   //pthread_t cur_tid = pthread_self();
 19   std::random_device rd;   // non-deterministic generator
 20   std::mt19937 gen(rd());
 21   while (1) {
 22     uint32_t rand_num = gen() % 1000;
 23     float32_t frand = static_cast<float32_t>(rand_num);
 24     float32_t fl_val = (frand * 0.002F);
 25     if ((fl_val < 0.0F) || (fl_val > 2.0F)) {
 26       gflag = -1;
 27       // Keep sleeping till the process gets aborted by the main thread
 28       while(1){usleep(2000);}
 29     }
 30     usleep(1000);
 31   }
 32 }
 33 
 34 int main() {
 35   int thr_cnt;
 36   int res = 0;
 37   pthread_t tid;
 38   for (thr_cnt = 0; thr_cnt < MAX_THR; thr_cnt++) {
 39     res = pthread_create(&tid,  NULL, thr_fn, NULL);
 40     if (res != 0) {
 41       std::cout <<"Error creating pthread: " <<strerror(errno);
 42     }
 43   }
 44   while(1){
 45     if (gflag != 0) {
 46       kill(getpid(), SIGABRT);
 47     }
 48     usleep(1000 * 1000 * 1);
 49   }
 50   return (0);
 51 }
...