У меня есть простой сторожевой механизм, сделанный следующим образом:
time_t timer = time(NULL);
int n = 0;
while (true) {
if (time(NULL) >= timer + 10) {
timer = time(NULL);
char szData[64];
memset(szData, 0, 64);
sprintf(szData, "s|%d|%s", tid, function_name);
if ((n = strlen(szData)) > 0) {
int t = 0;
int fp = 0;
while ((fp = open("/proc/counters", O_WRONLY | O_EXCL)) == -1 && errno == EACCESS) {
if (++t > 4) {
break;
}
usleep(260000);
}
if (fp == -1) {
return 1;
}
write(fp, szData, n);
close(fp);
}
}
}
В этом состоянии каждый счетчик должен достигать максимального значения 10, но моя проблема в том, что иногда некоторые из них достигают максимального значения 20, затем 30 и так далее. На стороне модуля ядра я вижу, что действительно команда сброса не приходит вовремя и на следующем раунде получает две команды за одну секунду, как будто первая задержалась. Пример:
Содержимое файла счетчиков /proc
*856 7 20/600 thread_function_name
Отладочные распечатки модуля ядра
26 августа 11:16:38 XWEB-PRO ядро kern.info: [114.086453] зарегистрируйте 856
26 августа 11:16:38 XWEB-PRO ядро kern.info: [124.138523] зарегистрируйте 856
26 августа 11:16:58 XWEB-PRO ядро kern.info: [134.190508] зарегистрируйте 856
26 августа 11:16:58 XWEB-PRO ядро kern.info: [144.242274] зарегистрируйте 856
26 августа 11:16:58 XWEB-PRO ядро kern.info: [144.242277] зарегистрируйте 856
26 августа 11:17:08 XWEB-PRO ядро kern.info: [154.294433] зарегистрируйте 856
26 августа 11:17:28 XWEB-PRO ядро kern.info: [164.346516] зарегистрируйте 856
26 августа 11:17:28 XWEB-PRO ядро kern.info: [174.398552] зарегистрируйте 856
26 августа 11:17:38 XWEB-PRO ядро kern.info: [184.468022] зарегистрируйте 856
26 августа 11:17:48 XWEB-PRO ядро kern.info: [194.522241] регистр 856
Как видите, я пропустил команду в 11:16:48, но у меня 3 в 11:16:58. Потом я пропустил один в 11:17:18, но есть 2 в 11:17:28. Я уже пробовал fflush, fsync и sync, но безуспешно. Кто-нибудь может указать мне в правильном направлении? Спасибо
Извините, я отредактировал вопрос. Это длина команды сброса.
Почему вы открываете файл с помощью O_EXCL? Насколько я понимаю, файл предоставляется вашим модулем, а значит существует всегда. Более того, вы не используете O_CREAT, который вам почти всегда нужен вместе с O_EXCL. Поведение вашего вызова open() с указанными флагами не определено.
А почему вы не проверяете, действительно ли удается открыть файл? Даже если вы решите проблему с помощью O_EXCL, вполне возможно, что open() иногда может дать сбой. Надежный код должен это распознавать и обрабатывать соответствующим образом.
Я несколько удивлен, что вы каждый раз открываете и закрываете файл. Я не вижу для этого веской причины. Однако, вероятно, это не причинит вам проблем, если только некоторые из этих open() действительно не работают.
Я использую O_EXCL, потому что у меня есть много асинхронных потоков, которые выполняют одну и ту же запись в этот файл, каждый со своим собственным tid. Я не использую флаг O_CREAT, поскольку файл уже существует и содержит другую информацию, которую я должен сохранить. Результат открытия проверяется и повторяется 3 раза, я пропустил эту часть, но теперь добавил ее.
Вы упускаете суть. O_EXCL имеет смысл только при использовании вместе с O_CREAT (или в Linux, в особом случае, который здесь не применяется). Поведение не определено, если в противном случае используется O_EXCL. Я думаю, вы думаете, что это предотвращает одновременное открытие файла несколькими потоками, но это не так.
Хорошо, извините, теперь более понятно. Я заметил, что если я добавляю печать в файл журнала непосредственно перед записью в файл /proc, счетчики сбрасываются каждые 10 секунд.
Конечно, вполне вероятно, что запись потока может быть отложена — в конце концов, в этом и есть смысл сторожевого таймера. Но я не вижу в представленном коде причин для задержки на полный 10-секундный цикл или для записи трех отдельных операций записи в одном цикле с пропуском только одного цикла. Я думаю, что основная проблема, вероятно, в модуле, а не в клиенте.
Нам нужно увидеть код вашего модуля ядра. Что такое файл /proc? (например) /proc/counters или /proc/pid/watchdog? Как получить счетчик потоков, если вы не добавляете поле в task_struct?





Наконец я заметил проблему. Похоже, это была проблема с состоянием гонки. В файл /proc одновременно записывают 10 потоков, поэтому, возможно, какая-то операция записи была пропущена модулем ядра (действительно, сброс всегда происходил кратно 10 секундам). Я окружил последовательность открытия/записи/закрытия в пользовательском пространстве мьютексом, и проблема, кажется, исчезла.
Что такое
n? (тип и значение)