2012-11-04 9 views
9

Предположим, у меня есть совместный планировщик во встроенной среде. У меня много процессов. Я хочу использовать сторожевой таймер, чтобы я мог обнаружить, когда процесс прекратил вести себя по какой-либо причине и сбросить процессор.Как использовать сторожевой таймер в RTOS?

В простых приложениях без RTOS я всегда касался сторожевого таймера из основного контура, и это было всегда адекватно. Однако здесь существует множество процессов, которые могут потенциально зависать. Какой чистый метод периодически касаться сторожевого таймера, гарантируя, что каждый процесс находится в хорошем состоянии?

Я думал, что могу предоставить функцию обратного вызова для каждого процесса, чтобы он мог позволить другой функции, которая контролирует всех, знает, что она все еще жива. Обратный вызов передал бы параметр, который был бы уникальным идентификатором задач, чтобы надсмотрщик мог определить, кто перезвонил.

+1

Мы принимаем сторожевой таймер, который является частью RTOS или фактическим сторожевым таймером оборудования, который предоставляет службы RTOS? –

ответ

13

Один общий подход заключается в делегировании сторожевого пиная к конкретной задаче (часто либо с наивысшим приоритетом, или самый низкий приоритет, компромиссах/мотиваций для каждого подхода), а затем все другие задачи «проверить в» с этой задачей.

Таким образом:

  • если прерывание подвешивают (100% CPU), задача кикер не будет работать, вы сбрасываете

  • если задача кикер подвешивают, вы сбрасываете

  • если другая задача подвешивают, кикер задача не видит проверку в, кикер задача не пинать ВДГ, вы сбрасываете

Теперь, конечно, детали реализации должны быть рассмотрены. У некоторых людей каждая задача задает свой собственный выделенный бит (атомарно) в глобальной переменной; задача кикера проверяет эту группу бит-флагов с определенной скоростью и очищает/сбрасывает, когда все проверили (наряду с ударом WDG, конечно). Я избегаю глобалов, таких как чума, и избегаю такого подхода. Флаги событий RTOS обеспечивают несколько схожий механизм, который является более элегантным.

Обычно я проектирую свои встроенные системы как управляемые событиями системы. В этом случае каждая задача блокируется в одном конкретном месте - в очереди сообщений. Все задачи (и ISR) общаются друг с другом, отправляя события/сообщения. Таким образом, вам не нужно беспокоиться о том, что задача не проверяется, потому что она заблокирована на семафоре «туда, где есть» (если это не имеет смысла, извините, не написав много больше, я не могу объяснить это лучше).

Также есть соображение - выполнять задачи в автономном режиме или отвечать или отвечать на запрос задания кикера. Автономный - например, один раз в секунду каждая задача получает событие в своей очереди «сообщите, что задача кикера еще жива».Ответ-запрос - раз в секунду (или что-то еще) задачи кикера говорят всем (через очереди) «время для регистрации» - и в конечном итоге каждая задача запускает свою очередь, получает запрос и отвечает. Учитываются приоритеты задач, теория массового обслуживания и т. Д.

Существует 100 способов скинуть этот кот, но основной принцип одной задачи, которая отвечает за то, чтобы пинать WDG и иметь другие задачи, выполняемые до задачи кикера, довольно стандартная.

Существует, по крайней мере, еще один аспект для рассмотрения - вне сферы действия этого вопроса - и это касается прерываний. Метод, описанный выше, вызовет сброс WDG, если ISR зацикливает CPU (хорошо), но как насчет противоположного сценария - ISR (к сожалению) случайно и непреднамеренно отключен. Во многих сценариях это не будет поймано, и ваша система все равно будет пинать WDG, но часть вашей системы искалечена. Забавный материал, вот почему я люблю встроенное развитие.

1

Традиционный метод должен иметь процесс сторожевого с наименьшим возможным приоритетом

PROCESS(watchdog, PRIORITY_LOWEST) { while(1){reset_timer(); sleep(1);} } 

А где фактический аппаратный таймер сбрасывает CPU каждые 3 или 5 секунд возможно.

Отслеживание отдельных процессов может быть достигнуто с помощью обратной логики: каждый процесс будет устанавливать таймер, чей обратный вызов отправляет сторожевому сигналу сообщение «остановить». Затем каждый процесс должен будет отменить предыдущее событие таймера и установить новый в каком-либо месте в цикле «получение события/сообщения из очереди».

PROCESS(watchdog, PRIORITY_LOWEST) { 
    while(1) { 
     if (!messages_in_queue()) reset_timer(); 
     sleep(1); 
    } 
} 
void wdg_callback(int event) { 
    msg = new Message(); 
    send(&msg, watchdog); 
}; 
PROCESS(foo, PRIORITY_HIGH) { 
    timer event=new Timer(1000, wdg_callback); 
    while (1) { 
     if (receive(msg, TIMEOUT)) { 
      // handle msg  
     } else { // TIMEOUT expired 
      cancel_event(event); 
      event = new Timer(1000,wdg_callback); 
     } 
    } 
} 
+0

Но проблема с этим подходом заключается в том, что проблема может быть решена только в том случае, если процесс сторожевого таймера был голоден или возникла большая проблема с RTOS. Это не вызовет проблем с каким-либо конкретным процессом. Или я чего-то не хватает? – user946230

+0

@ user946230: нет, вы правы. Проблема устранена в обновлении. Это уменьшает количество отправленных сообщений. Также можно закодировать функции сторожевого таймера внутри процесса «холостого хода», который обычно имеет PID = 0 и одновременно захватывает наиболее типичный случай потерянных сообщений. –

+0

Ну, простоя не может спать. но иначе .... –

1

Один образец решения:

  • Каждый поток, который хочет проверить явно регистрирует обратный вызов с сторожевого таймера, который поддерживает список таких обратных вызовов.
  • Когда сторожевой таймер запланирован, он может перебирать список зарегистрированных задач
  • Каждый обратный вызов называется итеративно, пока он не вернет здоровое состояние.
  • В конце списка аппаратного сторожевого пса.

Таким образом, любой поток, который никогда не возвращает здоровое состояние, остановит задачу сторожевого таймера до тех пор, пока не произойдет тайм-аут аппаратного сторожевого таймера.

В упреждающей ОС сторожевой поток будет наименее приоритетным или незанятым. В совместном планировщике он должен работать между обратными вызовами.

Дизайн самих функций обратного вызова зависит от конкретной задачи и ее поведения и периодичности. Каждая функция может быть адаптирована к потребностям и характеристикам задачи. Задачи с высокой периодичностью могут просто увеличивать счетчик, который устанавливается на ноль при вызове обратного вызова. Если счетчик равен нулю при входе, задача не планировалась с момента последней проверки сторожевого таймера. Задачи с низким или апериодическим поведением могут нанести вред их планированию, тогда обратный вызов может вернуть сбой, если задача не была запланирована на определенный период времени. Таким образом можно отслеживать обе задачи и обработчики прерываний. Более того, поскольку ответственность за регистрацию в контролере несет ответственность за поток, у вас могут быть потоки, которые вообще не регистрируются.

0

Каждая задача должна иметь свой собственный имитируемый сторожевой таймер. И реальный сторожевой таймер питается высокоприоритетной задачей в режиме реального времени, только если у всех симулированных сторожевых таймеров нет тайм-аута.

т.е:

void taskN_handler() 
{ 
    watchdog *wd = watchdog_create(100); /* Create an simulated watchdog with timeout of 100 ms */ 
    /* Do init */ 
    while (task1_should_run) 
    { 
     watchdog_feed(wd); /* feed it */ 
     /* do stuff */ 
    } 
    watchdog_destroy(wd); /* destroy when no longer necessary */ 
} 

void watchdog_task_handler() 
{ 
    int i; 
    bool feed_flag = true; 
    while(1) 
    { 
     /* Check if any simulated watchdog has timeout */ 
     for (i = 0; i < getNOfEnabledWatchdogs(); i++) 
     { 
      if (watchogHasTimeout(i)) { 
        feed_flag = false; 
        break; 
      } 
     } 

     if (feed_flag) 
      WatchdogFeedTheHardware(); 

     task_sleep(10); 
} 

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

0

Другие ответы затронули ваш вопрос, я просто хотел бы предложить вам добавить что-то в свою прежнюю процедуру (без RTOS). Не пренебрегайте сторожевым плеером безоговорочно только с основного(), возможно, что некоторые ISR застряли, но система продолжит работу без уведомления (проблема, о которой упоминал Дэн, также относится к RTOS).

То, что я всегда делал, касалось основного и таймерного прерываний, так что в течение таймера обратный отсчет был выполнен по переменной до тех пор, пока она не станет равна нулю, и из основного я бы проверил, было ли оно нулевым, и только затем кормить сторожевого пса. Конечно, после подачи возвращаем переменную до начального значения. Простой, если переменная перестает уменьшаться, вы получаете сброс. Если основные остановки питания сторожевого таймера, вы получите сброс.

Эта концепция проста в применении только для известных периодических событий, но все же лучше делать все как угодно, начиная с основного. Другим преимуществом является то, что искаженный код не так сильно ударит сторожевого таймера, потому что процедура вашего сторожевого канала в основной части закончилась в каком-то диком цикле.

 Смежные вопросы

  • Нет связанных вопросов^_^