Я хочу использовать mod_timer для таймера на 10 миллисекунд, но результат всегда 20 миллисекунд

мой тестовый код драйвера, я хочу использовать mod_timer для таймера на 10 миллисекунд, но результат всегда составляет 20 миллисекунд. что с этим не так? ..

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/unistd.h>
#include <linux/delay.h>

static struct timer_list my_timer;

void my_timer_callback(struct timer_list *timer)
{
    printk("my_timer_callback called (%lu).\n", jiffies);

    mod_timer(&my_timer, jiffies + msecs_to_jiffies(10));
}

static int __init my_init(void)
{
    printk("Timer module loaded\n");

    timer_setup(&my_timer, my_timer_callback, 0);

    mod_timer(&my_timer, jiffies + msecs_to_jiffies(10));

    return 0;
}

static void __exit my_exit(void)
{
    printk("Timer module unloaded\n");

    del_timer(&my_timer);
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("[email protected]");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);

результат dmesg:

[   70.391971] my_timer_callback called (4294944328).
[   70.411947] my_timer_callback called (4294944330).
[   70.431944] my_timer_callback called (4294944332).
[   70.451961] my_timer_callback called (4294944334).

версия ядра: 5.10

.config: КОНФИГ_ГЦ=100

Какова ценность ХЗ?

chux - Reinstate Monica 30.07.2024 06:46

значение ХЗ равно 100

dragonkyl 30.07.2024 07:31
./sound/isa/sb/sb8_midi.c: mod_timer(&chip->midi_timer, 1 + jiffies); ./sound/isa/sb/sb8_midi.c: mod_timer(&chip->midi_timer, 1 + jiffies); ./sound/isa/sb/emu8000_pcm.c: mod_timer(&rec->timer, jiffies + 1); ./sound/isa/sb/emu8000_pcm.c: mod_timer(&rec->timer, jiffies + 1); код ядра также использует jiffies
dragonkyl 30.07.2024 09:02

Разве jiffies не является u64, то есть неподписанным?

Allan Wind 30.07.2024 09:15

Есть ли связь с беззнаковым? Кажется, это связано с неподписанным.

dragonkyl 30.07.2024 09:30

Этот вопрос похож на: Надежность add_timer ядра Linux при разрешении в один миг?. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.

sawdust 30.07.2024 10:37

См. проблему с mod_timer в ядре Linux 4.18 для возможного решения.

sawdust 30.07.2024 11:03

Что произойдет, если заменить mod_timer(&my_timer, jiffies + msecs_to_jiffies(10)); на mod_timer(&my_timer, my_timer.expires + msecs_to_jiffies(10)); в my_timer_callback()?

Ian Abbott 30.07.2024 11:32

@AllanWind Нет, jiffies — это volatile unsigned long. get_jiffies_64() возвращает u64.

Ian Abbott 30.07.2024 11:35

@IanAbbott Второй раз (обратный вызов) и последующие таймеры работают нормально, почему? Почему они не работали раньше? [ 71.822001] my_timer_callback called (4294944471). [ 71.831990] my_timer_callback called (4294944472). [ 71.841988] my_timer_callback called (4294944473). [ 71.851989] my_timer_callback called (4294944474).

dragonkyl 30.07.2024 11:47

Можете ли вы напечатать оба timer->expires (или my_timer.expires, поскольку это одно и то же) и jiffies в обратном вызове, чтобы проверить наличие расхождений?

Ian Abbott 30.07.2024 12:23

Я хочу сказать, что вы печатаете значение как подписанное.

Allan Wind 30.07.2024 23:25

@AllanWind Он был изменен на %lu.

dragonkyl 31.07.2024 03:38

@IanAbbott Это результат печати обоих файлов . [ 32.651901] my_timer_callback called (4294940554). [ 32.651922] my_timer.expires=4294940553 [ 32.661892] my_timer_callback called (4294940555). [ 32.661911] my_timer.expires=4294940554 [ 32.671892] my_timer_callback called (4294940556). [ 32.671906] my_timer.expires=4294940555 [ 32.681892] my_timer_callback called (4294940557). [ 32.681907] my_timer.expires=4294940556

dragonkyl 31.07.2024 04:00

Похоже, обратный вызов вызывается через 1 миг после истечения срока действия. (В вашем случае миг составляет 10 мс).

Ian Abbott 31.07.2024 10:36

@IanAbbott В файле kernel/time/timer.c есть несколько комментариев. Кажется, есть какая-то корреляция, но я пока не смог ее выяснить. Когда я пытаюсь установить таймер от 10 мс до 1000 мс, мой обратный вызов всегда происходит через 960 мс или 1040 мс. Дрейф (80 мс) — это уровень детализации 1. * HZ 100 * Level Offset Granularity Range * 0 0 10 ms 0 ms - 630 ms * 1 64 80 ms 640 ms - 5110 ms (640ms - ~5s)

dragonkyl 31.07.2024 11:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
16
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По опыту OP и как отмечено в этом сообщении электронной почты , вполне возможно, что при вызове функций истечения срока действия таймера может возникнуть задержка в один миг из-за того, что некоторые процессоры читают старое значение jiffies, в то время как другой его обновляет.

Поскольку функция обратного вызова таймера OP добавляет относительную сумму к jiffies, чтобы установить следующее время истечения срока действия, время между обратными вызовами может быть на один миг дольше, чем требуется. Эту проблему можно смягчить, установив следующее время истечения срока действия относительно предыдущего. Если задержка в один миг постоянна, то все функции обратного вызова будут выполняться с опозданием на один миг. Однако возможно, что некоторые функции обратного вызова будут запущены вовремя, а некоторые — с опозданием, что может быть нежелательно.

Если вариант использования требует более точного времени, было бы лучше использовать API hrtimer, как показано в модифицированной версии кода OP ниже:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/unistd.h>
#include <linux/delay.h>

static struct hrtimer my_timer;

static enum hrtimer_restart my_timer_callback(struct hrtimer *timer)
{
    s64 now = ktime_to_ns(hrtimer_cb_get_time(timer));
    s64 expires = ktime_to_ns(hrtimer_get_softexpires(timer));
    s64 diff = now - expires;

    printk("my_timer_callback called (now %lld, expired %lld, diff %lld).\n",
           now, expires, diff);

    hrtimer_add_expires_ns(timer, 10 * NSEC_PER_MSEC);
    return HRTIMER_RESTART;
}

static int __init my_init(void)
{
    printk("Timer module loaded\n");

    hrtimer_init(&my_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
    my_timer.function = my_timer_callback;

    hrtimer_start(&my_timer,
                  ktime_add_ms(hrtimer_cb_get_time(&my_timer), 10),
                  HRTIMER_MODE_ABS);

    return 0;
}

static void __exit my_exit(void)
{
    printk("Timer module unloaded\n");

    hrtimer_cancel(&my_timer);
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("[email protected]");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);

Пример вывода dmesg из модуля показан ниже:

[ 7119.967286] my_timer_callback called (now 7119822903369, expired 7119822900229, diff 3140).
[ 7119.977294] my_timer_callback called (now 7119832911804, expired 7119832900229, diff 11575).
[ 7119.987347] my_timer_callback called (now 7119842964493, expired 7119842900229, diff 64264).
[ 7119.997286] my_timer_callback called (now 7119852903102, expired 7119852900229, diff 2873).
[ 7120.007348] my_timer_callback called (now 7119862964879, expired 7119862900229, diff 64650).
[ 7120.017348] my_timer_callback called (now 7119872964924, expired 7119872900229, diff 64695).
[ 7120.027347] my_timer_callback called (now 7119882964377, expired 7119882900229, diff 64148).
[ 7120.037333] my_timer_callback called (now 7119892950004, expired 7119892900229, diff 49775).
[ 7120.047348] my_timer_callback called (now 7119902964627, expired 7119902900229, diff 64398).
[ 7120.057348] my_timer_callback called (now 7119912964748, expired 7119912900229, diff 64519).
[ 7120.067337] my_timer_callback called (now 7119922952994, expired 7119922900229, diff 52765).
[ 7120.077350] my_timer_callback called (now 7119932966586, expired 7119932900229, diff 66357).
[ 7120.087348] my_timer_callback called (now 7119942964245, expired 7119942900229, diff 64016).
[ 7120.097334] my_timer_callback called (now 7119952950074, expired 7119952900229, diff 49845).
[ 7120.107351] my_timer_callback called (now 7119962966616, expired 7119962900229, diff 66387).

Другие вопросы по теме