Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.93/41: Рейтинг темы: голосов - 41, средняя оценка - 4.93
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
1

Watchdog на основе таймеров POSIX

29.12.2019, 22:41. Показов 7536. Ответов 65
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Добрый день, решил написать watchdog для сервера и чтобы не тратить зазря процессрное время решил реализовать это на основе таймеров POSIX, а не через создание отдельного потока.

Почитал документацию и остались некоторые вопросы:

1)Как должна быть организована проверка что сигнал пришёл от созданного мною таймера, а не от стороннего приложения ?
Сечас в обработчик приходит _si->si_pid == 0

2)Как сделать сброс таймера т.е. чтоб начинал считать по новому ? это всётаки watchdog.

3)Как подружить мой watchdog и std::getline(cin, str_command ?

4)Надо ли вызывать предыдущие обработчики если я их не создавал ?

5)Надо ли делать задержку после вызова timer_settime ?

6)Какой тип таймера выбрать ? CLOCK_REALTIME меня смущает что ктото мжет перевести время.

код внизу

watchdog.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "../include/error.h"
#include "../include/watchdog.h"
 
// (с) http://man7.org/linux/man-pages/man2/timer_create.2.html
#define CLOCKID CLOCK_REALTIME
#define SIG SIGRTMIN + 10
 
IWatcher* callback = nullptr;
 
typedef void (*TSigFunc1)(int, siginfo_t *, void *);
typedef void (*TSigFunc2)(int);
TSigFunc1 prev_handler1 = nullptr;
TSigFunc2 prev_handler2 = nullptr;
pid_t current_pid = getpid();
 
void IWatcher::reset()
{
    //
}
 
static void signal_handler(int _sig, siginfo_t * _si, void * _uc)
{
    bool result = false;
    if ((_sig == SIG) && (_si))
    {
        if ((callback) && (_si->si_pid == current_pid))
        {
            //errspace::show_errmsg("caught valid signal");
            //(*callback)(_si);
            result = true;
        }
    }
    if (!result)
    {
        //errspace::show_errmsg("caught invalid signal");
    }
    //if (prev_handler1) prev_handler1(_sig, _si, _uc);
    //if (prev_handler2) prev_handler2(_sig);
    //signal(_sig, SIG_IGN);
}
 
timer_t timerid;
 
bool start_wd(std::size_t _msecs, IWatcher* _cback)
{
   static constexpr auto billion = 1'000'000'000;
   static constexpr auto million = 1'000'000;
   callback = _cback;
   bool result = false;
   struct sigevent sev;
   struct itimerspec its;
   long long freq_nanosecs;
   sigset_t mask;
   struct sigaction sa;
   struct sigaction old_sa;
   // Establish handler for timer signal
   sa.sa_flags = SA_SIGINFO;
   sa.sa_sigaction = signal_handler;
   sigemptyset(&sa.sa_mask);
   if (sigaction(SIG, &sa, &old_sa) == -1)
   {
       errspace::show_errmsg("Failed to setup watchdog: Establish handler");
       return result;
   }
   prev_handler1 =  old_sa.sa_sigaction;
   prev_handler2 =  old_sa.sa_handler;
   // Block timer signal temporarily
   sigemptyset(&mask);
   sigaddset(&mask, SIG);
   if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
   {
       errspace::show_errmsg("Failed to setup watchdog: Blocking signal");
       return result;
   }
 
   // Create the timer
   sev.sigev_notify = SIGEV_SIGNAL;
   sev.sigev_signo = SIG;
   sev.sigev_value.sival_ptr = &timerid;
   if (timer_create(CLOCKID, &sev, &timerid) == -1)
   {
       errspace::show_errmsg("Failed to setup watchdog: create timer");
       return result;
   }
 
   // Start the timer
   freq_nanosecs = million*_msecs;
   its.it_value.tv_sec = freq_nanosecs / billion;
   its.it_value.tv_nsec = freq_nanosecs % billion;
   its.it_interval.tv_sec = its.it_value.tv_sec;
   its.it_interval.tv_nsec = its.it_value.tv_nsec;
 
   if (timer_settime(timerid, 0, &its, NULL) == -1)
   {
       errspace::show_errmsg("Failed to setup watchdog: set time");
       return result;
   }
   // ????
   // std::this_thread::sleep_for(std::chrono::milliseconds(_msecs*2));
   /* Sleep for a while; meanwhile, the timer may expire
      multiple times */
 
   //printf("Sleeping for %d seconds\n", atoi(argv[1]));
   //sleep(atoi(argv[1]));
 
   // Unlock the timer signal, so that timer notification can be delivered
   if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
   {
       errspace::show_errmsg("Failed to setup watchdog: Unblocking signal");
       return result;
   }
    result = true;
    return result;
}
 
void stop_wd()
{
    sigset_t mask;
    struct sigaction action;
 
    // Block timer signal temporarily
    sigemptyset(&mask);
    sigaddset(&mask, SIG);
    if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
    {
        errspace::show_errmsg("Failed to reset watchdog: Blocking signal");
        return;
    }
    timer_delete(timerid);
    action.sa_handler = SIG_DFL;
    action.sa_flags   = SA_RESETHAND;
 
    if (sigaction(SIGINT, &action, NULL) == -1)
    {
        errspace::show_errmsg("Failed to reset watchdog: reset handler");
        return;
    }
 
    // Unlock the timer signal, so that timer notification
    //   can be delivered
    if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
    {
        errspace::show_errmsg("Failed to reset watchdog: Unblocking signal");
        return;
    }
}
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include "../include/common.h"
#include "../include/error.h"
#include "../include/watchdog.h"
#include "../include/mng_thread.h"
 
class Watcher : public IWatcher
{
public:
    template<typename ...Args>
    Watcher(Args... _args)
    {
        auto tpack = std::make_tuple(_args...);
    }
protected:
    virtual void operator ()(siginfo_t *si)
    {
        //printf("Caught signal %d\n", sig);
        //print_siginfo(si);
        //#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
        //                           } while (0)
        errspace::show_errmsg("watchdog timeout");
        timer_t tidp;
        int _or;
 
        tidp = si->si_value.sival_ptr;
 
        //printf("    sival_ptr = %p; ", si->si_value.sival_ptr);
        //printf("    *sival_ptr = 0x%lx\n", (long) tidp);
 
        _or = timer_getoverrun(tidp);
        //if (_or == -1)
        //    errExit("timer_getoverrun");
        //else
         //   printf("    overrun count = %d\n", _or);
    }
};
 
int main(int argc, char *argv[])
{
    static Watcher w{};
    IWatcher* iw = &w;
 
    const char * FUNCTION = __FUNCTION__;
    try
    {
        using std::cout;
        using std::cin;
        using std::endl;
        cout << "Server is started" << endl;
        std::string str_command;
        while(1)
        {
            LOG << "enter command:";
            if (std::getline(cin, str_command))
            {
                LOG << "command:" << str_command << " was got";
                if (str_command == "q") break;
                if (str_command == "e") throw 0;
                if (str_command == "s")
                {
                    start_wd(1000, iw );
                }
                if (str_command == "p") stop_wd();
            }
            str_command = "";
        }
    }
    catch (...)
    {
        errspace::show_errmsg(FUNCTION);
    }
    return EXIT_SUCCESS;
}
#endif
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.12.2019, 22:41
Ответы с готовыми решениями:

WatchDog
Есть устройство на меге16 (пока на ней) которое тупо запоминает в EEPROM во сколько на одном из...

Пробуждение по watchdog
Доброго времени суток. На старом АТ90S нужно уйти в сон, проснуться по watchdog, убедиться что...

WatchDog в Python
Добрый день! Интересует возможность использования watchdoga в Python. Есть ли реализация или...

Watchdog из Arduino
Есть пк, который может зависнуть, или может зависнуть у него сетевуха. Просьба не пинать в...

65
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
30.12.2019, 11:39 2
Цитата Сообщение от squareroot Посмотреть сообщение
Добрый день, решил написать watchdog для сервера и чтобы не тратить зазря процессрное время решил реализовать это на основе таймеров POSIX, а не через создание отдельного потока.
Через создание потока как то проще будет, раз в десять. И процессорное время тратиться зазря не будет - таймеры они тоже не в сферическом вакууме работают.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
30.12.2019, 17:07  [ТС] 3
Хлчется получить ответ хотябы на три наиболее важных вопроса:

4)Надо ли вызывать предыдущие обработчики если я их не создавал ?

5)Надо ли делать задержку после вызова timer_settime ?

6)Какой тип таймера выбрать ? CLOCK_REALTIME меня смущает что ктото мжет перевести время.

С остальным както можно найти обходные пути.


Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Через создание потока как то проще будет, раз в десять. И процессорное время тратиться зазря не будет - таймеры они тоже не в сферическом вакууме работают.
Ну так речь идёт о watchdog-е, а не о простом таймере.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 07:18  [ТС] 4
Появились новые вопросы.
1)Выбрасывают ли функции POSIX исключения ?
Вроде это всётаки набор Си библиотек, но я до конца не уверен
2)Что будет если в обработчик сигнала добавить обработчик исключения или ещё хуже в обработчика сигнала ()без обработки исключений
) будет выброшено исключение ?
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 14:58 5
Цитата Сообщение от squareroot Посмотреть сообщение
3)Как подружить мой watchdog и std::getline(cin, str_command ?
Что значит подружить?

Цитата Сообщение от squareroot Посмотреть сообщение
6)Какой тип таймера выбрать ?
CLOCK_MONOTONIC

Цитата Сообщение от squareroot Посмотреть сообщение
Выбрасывают ли функции POSIX исключения ?
Речь о С++ исключениях? Нет.

Цитата Сообщение от squareroot Посмотреть сообщение
Что будет если в обработчик сигнала добавить обработчик исключения или ещё хуже в обработчика сигнала ()без обработки исключений
) будет выброшено исключение ?
Из обработчика сигнала можно делать весьма ограниченное число операций. Вот их перечень: http://man7.org/linux/man-page... ety.7.html. Т.е. вы не можете в обработчике сигнала запрашивать, например, динамическую память. Исключений C++, естественно, в нем тоже не должно быть.
Поэтому предлагаю не тратить время на разбор этого примера, а использовать, например, timerfd, коль уж у нас тут Linux.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 15:19  [ТС] 6
Цитата Сообщение от DrOffset Посмотреть сообщение
Что значит подружить?
CLOCK_MONOTONIC
Все пишут что он не перегружаемый ? Т.е. его нельзя сбросить в ноль, вызвав timer_settime с темиже значениями при инициаллизации.


Цитата Сообщение от DrOffset Посмотреть сообщение
Что значит подружить?
Речь о С++ исключениях? Нет.
Да именно о них. Но интересно конечно рассмотреть вопрос шире. Если есть перехватчик posix segfault-ов(SIGSEGV) в линуксе или SEH в винде.
Сработают ли они ?

Цитата Сообщение от DrOffset Посмотреть сообщение
Что значит подружить?
Это значит что я сталкиваюсь с неправильным поведением при вызове std::getline(cin, str_command) когда включен мой watchdog/
std::cin не дожидаясь окончания ввода завершается, как будто ктото нажал ENTER.
Проблему вроде вылечил, но вылкчил, но не уверен что правильно и/или полностью:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        while(!ns_wd::is_timeout())
        {
            if (!std::cin)
            {
              std::cin.clear();
            }
            else
            {
                LOG << "enter command:";
            }
            if (std::getline(cin, str_command))
            {
                LOG << "command:" << str_command << " was got";
                if (str_command == "q") break;
                if (str_command == "e") throw 0;
                if (str_command == "s")
                {
                    ns_wd::start_wd(1000);
                }
                if (str_command == "p") ns_wd::stop_wd();
                if (str_command == "r") reseter = new Reseter;
                if (str_command == "d") delete reseter;
 
            }
            //if (pclient->isError()) break;
            str_command = "";
            //pclient->Process();
        }
Цитата Сообщение от DrOffset Посмотреть сообщение
Из обработчика сигнала можно делать весьма ограниченное число операций. Вот их перечень: http://man7.org/linux/man-page... ety.7.html. Т.е. вы не можете в обработчике сигнала запрашивать, например, динамическую память. Исключений C++, естественно, в нем тоже не должно быть.
Поэтому предлагаю не тратить время на разбор этого примера, а использовать, например, timerfd, коль уж у нас тут Linux.
Спасибо учту.
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 15:52 7
Цитата Сообщение от squareroot Посмотреть сообщение
Но интересно конечно рассмотреть вопрос шире. Если есть перехватчик posix segfault-ов(SIGSEGV) в линуксе или SEH в винде.
Сработают ли они ?
Сработают, однако программа будет в состоянии UB.
Я бы не стал на это закладываться.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 16:16  [ТС] 8
Цитата Сообщение от DrOffset Посмотреть сообщение
Поэтому предлагаю не тратить время на разбор этого примера, а использовать, например, timerfd, коль уж у нас тут Linux.
Задача watchdog-а следить чтоб потоки(основной и дополнительный) не тупили и тем более не были в зависшем состоянии, а если уж такое случилось. то надо как можно корректнее завершить программу. Из этого списка применим только abort, но это уж совсем жёстко. Надо по хорошему счёту вызвать какой нибудь pthread_cancel или ещё лучше меод https://en.cppreference.com/w/cpp/memory/unique_ptr/release какого нибудь умного указателя или на худой конец delete.
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 16:18 9
squareroot, timerfd позволит организовать обработку внутри штатного контекста выполнения, без всех этих ограничений.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 16:25  [ТС] 10
Цитата Сообщение от DrOffset Посмотреть сообщение
squareroot, timerfd позволит организовать обработку внутри штатного контекста выполнения, без всех этих ограничений.
Я щас как вы могли заметить пишу сервер на основе boost::asio и его достоинство перед нативными сокетами это кроссплатформенность.
Если я запихну не кроссплатформенный watchdog то получиться каламбур, хотя подозреваю использование POSIX под виндой это большая боль.
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 16:29 11
squareroot, он у вас и так некросплатформенный.
Да и в asio есть свои таймеры.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 16:33  [ТС] 12
Цитата Сообщение от DrOffset Посмотреть сообщение
squareroot, он у вас и так некросплатформенный.
Да и в asio есть свои таймеры.
Почему не кроссплатформенный ?
А таймеры в asio для меня кот в мешке. Годяться ли они для целей watchdog-а большой вопрос. С сигналами всё както понятно. Их посылает система и он сработает если не железно то более гарантированно при подвисших потоках.
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 16:42 13
Цитата Сообщение от squareroot Посмотреть сообщение
Почему не кроссплатформенный ?
Потому что POSIX нет под виндой. Потому что реализации POSIX различаются в Linux и других юникс-подобных ОС, в небольших, но иногда существенных деталях.

Цитата Сообщение от squareroot Посмотреть сообщение
А таймеры в asio для меня кот в мешке.
Надо разбираться, значит.
Цитата Сообщение от squareroot Посмотреть сообщение
Годяться ли они для целей watchdog-а большой вопрос.
Очень маленький это вопрос.
Asio использует те же системные механизмы внутри.
Если у вас не получается использовать asio, то вы просто что-то не так делаете.
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 16:51  [ТС] 14
Цитата Сообщение от DrOffset Посмотреть сообщение
Потому что POSIX нет под виндой. Потому что реализации POSIX различаются в Linux и других юникс-подобных ОС, в небольших, но иногда существенных деталях.
Наверно надо будет переделать часть кода, применяя std::signal. Плюсы зато под виндой есть А вот с POSIX таймерами надо поколдовать или заглянуть под капот boost::asio. С наступающем Вас!
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 16:56 15
Цитата Сообщение от squareroot Посмотреть сообщение
А вот с POSIX таймерами надо поколдовать или заглянуть под капот boost::asio.
https://www.boost.org/doc/libs... boost_1_43
use timerfd for dispatching timers on Linux, when available.
Для версии 1.43 и выше.

Цитата Сообщение от squareroot Посмотреть сообщение
Наверно надо будет переделать часть кода, применяя std::signal.
Я бы отказался от этой затеи. Вы либо сделаете все очень сложно и правильно, либо просто, но неправильно. Мне кажется оба варианта так себе.

Добавлено через 42 секунды
Цитата Сообщение от squareroot Посмотреть сообщение
С наступающем Вас!
И вас
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 19:17  [ТС] 16
DrOffset, А вот если сделать так: Пристрелить вторичные потоки в обработчике watchdog-a, а основной поток не трогать, но выставить флажок глобальной атомарной переменной. Ничего ведь страшного не случиться от того что немного расширим список http://man7.org/linux/man-page... ety.7.html атомарными переменными ?

Добавлено через 11 минут
Для винды надо будет запилить свой таймер, но там свои погремушки в части что надёжно/ненадёжно.

Добавлено через 2 минуты
Просто подозрительны мне таймеры, которые вызываются в контексте, который позволяет делать всё что хочешь, но делать полноценное нагрузочное тестирование я щас не готов. И тратить несколько недель(или месяцев ?) на изучение системного программирования по Linux и Windows я тоже не готов, так сильно отклоняться от первоначальной цели.
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 20:36 17
squareroot, проще всего вам использовать таймер asio. Это по всем параметрам выгоднее.

Добавлено через 45 секунд
Цитата Сообщение от squareroot Посмотреть сообщение
но выставить флажок глобальной атомарной переменной.
https://ru.cppreference.com/w/... g_atomic_t
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 20:55  [ТС] 18
Цитата Сообщение от DrOffset Посмотреть сообщение
squareroot, проще всего вам использовать таймер asio. Это по всем параметрам выгоднее.

Добавлено через 45 секунд

https://ru.cppreference.com/w/... g_atomic_t
timer asio как говядину второй свежести можно оставить для винды :-)
#ifdef __GNUC__ бла бла бла
В линуксе всё очень сурово и у меня иногда тормозит курсор мыши, а винде я такого не припомню.
0
18896 / 9854 / 2410
Регистрация: 30.01.2014
Сообщений: 17,297
31.12.2019, 21:00 19
Цитата Сообщение от squareroot Посмотреть сообщение
у меня иногда тормозит курсор мыши, а винде я такого не припомню.
Я тоже самое могу сказать про винду, и что, кому теперь верить?

Добавлено через 16 секунд
Цитата Сообщение от squareroot Посмотреть сообщение
#ifdef __GNUC__ бла бла бла
Зачем, если внутри ASIO уже это сделано?
0
13 / 13 / 1
Регистрация: 19.10.2019
Сообщений: 607
31.12.2019, 21:12  [ТС] 20
Цитата Сообщение от DrOffset Посмотреть сообщение
Я тоже самое могу сказать про винду, и что, кому теперь верить?

Добавлено через 16 секунд

Зачем, если внутри ASIO уже это сделано?
Затем что для линуксовой версии я бы использовал таймер POSIX потому как я понимаю, скорей всего он посылает сигнал в режиме ядра и в потоке ядра, а малохольный ваш таймер может тупо не сработать из-за какого нибудь гадкого потока при подвисании системы когда его обработчик надо будет вызвать в контексте пользовательского потока . Вот такой мой нубский взгляд на ситуацию.

Добавлено через 6 минут
Те ограничение о которых вы говорили, http://man7.org/linux/man-page... ety.7.html они не от балды взялись всётаки.
0
31.12.2019, 21:12
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
31.12.2019, 21:12
Помогаю со студенческими работами здесь

Внешний WAtchdog
Добрый день! Есть рабочее устройство на AVR! Надо к нему прикрепить внешний watchdog, тоесть...

AvrSudio и watchdog
Не могу дождаться чтобы аврстудия ушла в ресет или прерывание по вочдогу. В реале сбрасывает, а в...

Analog Watchdog (AWD)
Добрый день. Уже третьи сутки бъюсь с analog watchdog, не хочет зараза, нормально работать. Код...

Cortex m0 и watchdog таймер
Всем доброго времени суток!!! Программирую схему на базе ядра cortex m0. Не могу заставить работать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru