LINUX.ORG.RU

Как сделать ожидание прерывания не усыпляя процесс?

 , ,


1

4

Есть такой механизм wait_event_interruptible, он хороший, вопросов нет. Но иногда, даже с RT 99 приоритетом процесс может слишком долго пробуждаться, то есть проходит слишком много времени между irq_handler и моментом, когда пробуждение отработает

Почитал хорошую статеечку https://kerneltweaks.wordpress.com/2015/03/20/quick-guide-for-choosing-correct-synchronization-mechanism-inside-linux-kernel/

И ничего умнее чем просто ставить какое то число через atomic_set в irq_handler и сделать while(atomic_read == 0) в ожидающем процессе - я не придумал. Вместо wait_event_interruptible

Ясно что идеология работы с устройствами она иная, что обмен по DMA, что IRQ оно не для чего то иного. Там всё не требует быстрой реакции чтобы всё успевало и ничего не терялось. Понятно что не для того всё это сделано, считается что поймал irq handler сделал что надо и свободен. Но что если надо немедленно это сообщить в userspace?

Такое ощущение, что kernel module он при wait_event_interruptible спит прямо вместе с процессом userspace, который вызвал этот конкретный ioctl. Может есть что то более приспособленное для этой цели?

Может какой нибудь типа disable preempt??? Система SMP, почему бы нет. Но вероятно этот wait_event_interruptible или там какой нибудь семафор - они все «хотят спать»

★★★★★

Последнее исправление: I-Love-Microsoft (всего исправлений: 4)

Ясно что идеология работы с устройствами она иная, что обмен по DMA, что IRQ оно не для чего то иного. Там всё не требует быстрой реакции чтобы всё успевало и ничего не терялось. Понятно что не для того всё это сделано, считается что поймал irq handler сделал что надо и свободен. Но что если надо немедленно это сообщить в userspace?

Ничерта не ясно, по крайней мере мне.

Ядро реалтаймовое? Группа SCHED_RR? SCHED_FIFO? SCHED_NORMAL? SCHED_OTHER? «Слишком много времени» это сколько? Что при этом в /proc/sys/kernel/sched_r*? Задавай вопросы нормально, уважай форумчан.

t184256 ★★★★★
()
Ответ на: комментарий от t184256

Ядро вроде как не realtime. Использую SHED_RR (не знаю, может факт поддержки SHED_RR означает что ядро содержит RT-патчи, тут я хз) и приоритет 99, максимальный в системе. Слишком много, это когда «обычно» процесс занимает ну порядка 50-200 микросекунд, а в случае когда это для меня уже сбой - там уже тысячи микросекунд

Делаю вывод, что wait_event_interruptible не спешит «проснуться», то есть большую часть времени, десятки тысяч циклов не происходит задержка, а потом внезапно вылезает большая задержка и у меня всё ломается

Сейчас я переписал один драйвер на while(atomic_read) - жрет процессор конечно, это ожидаемо, но работает. Сейчас и второй драйвер перепишу в данном месте на atomic_t переменные

В принципе, если это будет работать надежно, то на потребление процессора плевать, задача специализированная, лютой эффективности не требуют, ядер свободных много еще. Конечно с wait_queue процессора жрет 3% а тут 50%

Возможно, существует более интеллектуальный способ передать событие о срабатывании IRQ, но быть может все решение, будь то семафоры и прочие примитивы синхронизации в ядре Linux приведут меня к ровно такой же проблеме

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)
Ответ на: комментарий от I-Love-Microsoft

Умные люди риалтайм делают на отдельном микроконтроллере, а на линуксе делают уже какой нибудь гуй или постобработку, где тупить несколько миллисекунд вполне позволительно.

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

Ох, подписываюсь ну под каждым словом. Я говорил им «не надо через Linux - не получится» и «давайте хотя бы что то типа QNX поставим», надо аппаратно обмениваться, да хоть по оптике напрямую, но только не через процессор. Уперлись на своем, хотя я изначально видел, что то как я предлагаю - это реально сделать аппаратно

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Ядро вроде как не realtime.

Ну и о чем тогда разговор? Пробуй реалтаймовое, там другие свойства будут у примерно всего, что тебя волнует.

t184256 ★★★★★
()
Последнее исправление: t184256 (всего исправлений: 1)

Такое ощущение, что kernel module он при wait_event_interruptible спит прямо вместе с процессом userspace, который вызвал этот конкретный ioctl. Может есть что то более приспособленное для этой цели?

Если ты вызываешь wait в контексте процесса, то процесс уходит спать. Все очень прямолинейно :))))

cumvillain
()

Пока что, ценой загрузки процессора, сделав в irq handler atomic_set 1 и в месте ожидания while(atomic_read < 1), мне удалось добиться многочасовой стабильности работы системы в этой задаче

Стабильность сохраняется даже если завалить все ядра чем то на фоне, принимать 125 мегабайт по сети и в цикле читать содержимое SSD диска и всё это одновременно - стабильность даже в таких жестких условиях сохраняется

Следующий шаг, это должно быть действительно RT-патчи к ядру или иные расширения к ядру Linux, вплоть до перехода на ЗОСРВ Нейтрино. Драйвера все свои, можно портировать, опыт под QNX есть

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Если это такая система, где можно играться «жесткой» привязкой потока к ядру, то посмотрите на (это совет по повышению стабильности вашего решения с while, а не альтернативный подход):

  1. параметр ядра isolcpu - позволит вывести CPU core из-под контроля планировщика
  2. affinity - привязка вашего потока к выделенному CPU core. После этого цикл будет себе крутиться, и планировщик не будет вмешиваться и вытеснять процесс, даже заоблачный приоритет не понадобится.
blex ★★★
()
Ответ на: комментарий от blex

Спасибо, попробуем. Пытался привязывать процесс через taskset (кстати, это работает). А как заставить, чтобы и драйвер и irq_handler сидел только на этом ядре? И чтобы другие драйвера и их обработчики прерывания, и другие вообще процессы, вообще забыли про дорогу к ядру этому

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Управлять распределением прерываний по ядрам процессора можно с помощью smp_affinity, но там далеко не всё управляемо; тут практического опыта не имею, деталей не подскажу. Если будут напрягать прерывания от таймера, то посмотрите в сторону NO_HZ_FULL, full-tickless CPU.

Другие процессы забудут путь к этому ядру благодаря isolcpu.

Потоки ядра путь не забудут; может и есть средства, но я их не знаю. Кое-что достигается CONFIG_RCU_NOCB_CPU, rcu_nocbs

Не изолируйте 0 и 1 ядро, их линукс кернел теребонькает значительно чаще чем 2, 3 и т.д.

blex ★★★
()