У меня есть многопоточное приложение пользовательского пространства, работающее на 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 }