|
From: <can...@li...> - 2007-02-13 17:02:18
|
Hi Francis, I do program another node consumer producer (0x1017/0) time to 1 second . I do receive heartbeats every 1 second - I can see it in debugger.. As I said, problem is if you will call DelAlarm and SetAlarm. You can follow my logic it in my reply to myself yesterday and you will easy find. Bug is trackable through static code analysis, you event don't need debug it. Again, problem is fixed in my Win32 port and I can go ahead. my fix is here: http://www.tochinski.com/files/CanFestival-3.win32.zip Regards, -Leonid my latest timer driver implementation code class class_timers { public: class_timers(); ~class_timers(); void start_timer_thread(); void resume_timer_thread(); void stop_timer_thread(); void set_timer(TIMEVAL value); TIMEVAL get_elapsed_time(); private: TIMEVAL get_timer() const; static DWORD WINAPI timer_loop_thread_proc(void* arg); private: TIMEVAL m_last_occured_alarm_time; volatile TIMEVAL m_last_alarm_set_time; HANDLE m_timer_thread; volatile bool m_continue_timer_loop; bool m_use_hi_res_timer; double m_counts_per_usec; }; class_timers::class_timers() : m_last_occured_alarm_time(TIMEVAL_MAX), m_last_alarm_set_time(TIMEVAL_MAX), m_timer_thread(0), m_continue_timer_loop(false), m_use_hi_res_timer(false), m_counts_per_usec(0.) { // initialize hi resolution timer LARGE_INTEGER counts_per_sec = {0, 0}; if (::QueryPerformanceFrequency(&counts_per_sec) && counts_per_sec.QuadPart > 0) { m_use_hi_res_timer = true; m_counts_per_usec = counts_per_sec.QuadPart / 1000000.; } m_use_hi_res_timer = true; } class_timers::~class_timers() { stop_timer_thread(); } // time is in micro seconds TIMEVAL class_timers::get_timer() const { if (m_use_hi_res_timer) { LARGE_INTEGER performance_count = {0, 0}; ::QueryPerformanceCounter(&performance_count); return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec); } // hi-res timer is unavailable return 1000 * ::GetTickCount(); } DWORD WINAPI class_timers::timer_loop_thread_proc(void* arg) { class_timers* This = reinterpret_cast<class_timers*>(arg); while (This->m_continue_timer_loop) { TIMEVAL cur_time = This->get_timer(); if (cur_time >= This->m_last_alarm_set_time) { This->m_last_occured_alarm_time = cur_time; This->m_last_alarm_set_time = TIMEVAL_MAX; EnterMutex(); TimeDispatch(); LeaveMutex(); } else ::Sleep(1); } return 0; } void class_timers::start_timer_thread() { if (m_timer_thread == 0) { unsigned long thread_id = 0; m_timer_thread = ::CreateThread(NULL, 0, &timer_loop_thread_proc, this, CREATE_SUSPENDED, &thread_id); m_last_alarm_set_time = TIMEVAL_MAX; m_last_occured_alarm_time = get_timer(); } } void class_timers::resume_timer_thread() { if (m_timer_thread) { m_continue_timer_loop = true; ::ResumeThread(m_timer_thread); } } void class_timers::stop_timer_thread() { if (m_timer_thread) { m_continue_timer_loop = false; ::WaitForSingleObject(m_timer_thread, INFINITE); ::CloseHandle(m_timer_thread); m_timer_thread = 0; } } void class_timers::set_timer(TIMEVAL value) { m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : get_timer() + value; } // elapsed time since last occured alarm TIMEVAL class_timers::get_elapsed_time() { return get_timer() - m_last_occured_alarm_time; } // ---------------------------------------------------------- static class_timers s_timers; void StartTimerLoop(TimerCallback_t init_callback) { s_timers.start_timer_thread(); // At first, TimeDispatch will call init_callback. if (init_callback != NULL) SetAlarm(NULL, 0, init_callback, 0, 0); s_timers.resume_timer_thread(); } void StopTimerLoop(void) { s_timers.stop_timer_thread(); } void setTimer(TIMEVAL value) { s_timers.set_timer(value); } TIMEVAL getElapsedTime(void) { return s_timers.get_elapsed_time(); } can...@li... wrote: > Hi Leonid, > > If you have programmed a consumer to 3 seconds and received a > heartbeatError every 3 seconds, maybe it is > > because you have not received a heartbeat from an other producer's node. > You should verify at index 0x1016 which nodes should send the heartbeat > and verify that it is sent more frequently than every 3 seconds. > > Regards, > > Francis > > can...@li... a йcrit : > >> HelloFrancis, >> >> While debugging Heartbeat Consumer on CanFestival Win32 port, I start >> feeling my timers implementation >> works not correct. I heartbeat producer set to 1 sec, consumer to 3 sec >> and I receive XXX_heartbeatError(UNS8) callback every 3 seconds. >> I'm pretty sure I'm working in correct time units, there some logical flow. >> >> Can you, please, clarify setTimer() and getElapsedTime() expected >> behaviour? >> >> I have time defined as following >> >> timerscfg.h >> >> // Time unit : us >> // Time resolution : 64bit (~584942 years) >> #define TIMEVAL unsigned __int64 >> #define TIMEVAL_MAX ~(TIMEVAL)0 >> #define MS_TO_TIMEVAL(ms) ms*1000 >> #define US_TO_TIMEVAL(us) us >> >> >> My understanding the following: >> >> void setTimer(TIMEVAL value); >> Sets timer to be triggered in specified by parameter value microseconds >> from the current time. >> >> >> TIMEVAL getElapsedTime(void); >> Returns elapsed time in microseconds since alarm was triggered for the >> last time. >> >> >> Also, what is expected return value of getElapsedTime() if no alarms >> were triggered yet >> >> Below is my implementation. >> >> Functions of interest are: >> >> void timers::start_timer_thread() >> DWORD WINAPI timers::timer_loop_thread_proc(void* arg) >> void timers::set_timer(TIMEVAL value) >> TIMEVAL timers::get_elapsed_time() >> >> >> // --------------- Timer Thread Implementation --------------- >> class timers >> { >> public: >> timers(); >> ~timers(); >> void start_timer_thread(); >> void resume_timer_thread(); >> void stop_timer_thread(); >> void set_timer(TIMEVAL value); >> TIMEVAL get_elapsed_time(); >> private: >> TIMEVAL get_timer() const; >> static DWORD WINAPI timer_loop_thread_proc(void* arg); >> private: >> TIMEVAL m_last_occured_alarm_time; >> volatile TIMEVAL m_last_alarm_set_time; >> HANDLE m_timer_thread; >> volatile bool m_continue_timer_loop; >> bool m_use_hi_res_timer; >> double m_counts_per_usec; >> }; >> >> timers::timers() : m_last_occured_alarm_time(TIMEVAL_MAX), >> m_last_alarm_set_time(TIMEVAL_MAX), >> m_timer_thread(0), >> m_continue_timer_loop(false), >> m_use_hi_res_timer(false), >> m_counts_per_usec(0.) >> { >> // initialize hi resolution timer >> LARGE_INTEGER counts_per_sec = {0, 0}; >> if (::QueryPerformanceFrequency(&counts_per_sec) && >> counts_per_sec.QuadPart > 0) >> { >> m_use_hi_res_timer = true; >> m_counts_per_usec = counts_per_sec.QuadPart / 1000000.; >> } >> } >> >> timers::~timers() >> { >> stop_timer_thread(); >> } >> >> // time is in micro seconds >> TIMEVAL timers::get_timer() const >> { >> if (m_use_hi_res_timer) >> { >> LARGE_INTEGER performance_count = {0, 0}; >> ::QueryPerformanceCounter(&performance_count); >> return (TIMEVAL)(performance_count.QuadPart / m_counts_per_usec); >> } >> // hi-res timer is unavailable >> return 1000 * ::GetTickCount(); >> } >> >> >> void timers::start_timer_thread() >> { >> if (m_timer_thread == 0) >> { >> unsigned long thread_id = 0; >> m_timer_thread = ::CreateThread(NULL, 0, &timer_loop_thread_proc, >> this, CREATE_SUSPENDED, &thread_id); >> m_last_alarm_set_time = TIMEVAL_MAX; >> m_last_occured_alarm_time = TIMEVAL_MAX; >> } >> } >> >> void timers::resume_timer_thread() >> { >> if (m_timer_thread) >> { >> m_continue_timer_loop = true; >> ::ResumeThread(m_timer_thread); >> } >> } >> >> void timers::stop_timer_thread() >> { >> if (m_timer_thread) >> { >> m_continue_timer_loop = false; >> ::WaitForSingleObject(m_timer_thread, INFINITE); >> ::CloseHandle(m_timer_thread); >> m_timer_thread = 0; >> } >> } >> >> >> DWORD WINAPI timers::timer_loop_thread_proc(void* arg) >> { >> timers* This = reinterpret_cast<timers*>(arg); >> while (This->m_continue_timer_loop) >> { >> TIMEVAL cur_time = This->get_timer(); >> if (cur_time >= This->m_last_alarm_set_time) >> { >> This->m_last_occured_alarm_time = cur_time; >> EnterMutex(); >> TimeDispatch(); >> LeaveMutex(); >> } >> else >> ::Sleep(1); >> } >> return 0; >> } >> >> void timers::set_timer(TIMEVAL value) >> { >> m_last_alarm_set_time = (value == TIMEVAL_MAX) ? TIMEVAL_MAX : >> get_timer() + value; >> } >> >> // elapsed time since last occured alarm >> TIMEVAL timers::get_elapsed_time() >> { >> if (m_last_occured_alarm_time == TIMEVAL_MAX) >> return 0; >> return get_timer() - m_last_occured_alarm_time; >> } >> >> // ---------------------------------------------------------- >> >> static timers s_timers; >> >> void StartTimerLoop(TimerCallback_t init_callback) >> { >> s_timers.start_timer_thread(); >> // At first, TimeDispatch will call init_callback. >> SetAlarm(NULL, 0, init_callback, 0, 0); >> s_timers.resume_timer_thread(); >> } >> >> void StopTimerLoop(void) >> { >> s_timers.stop_timer_thread(); >> } >> >> void setTimer(TIMEVAL value) >> { >> s_timers.set_timer(value); >> } >> >> TIMEVAL getElapsedTime(void) >> { >> return s_timers.get_elapsed_time(); >> } >> >> >> Regards, >> >> Leonid Tochinski >> >> >> >> >> >> ------------------------------------------------------------------------- >> Using Tomcat but need to do more? Need to support web services, security? >> Get stuff done quickly with pre-integrated technology to make your job easier. >> Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo >> http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 >> _______________________________________________ >> Canfestival-devel mailing list >> Can...@li... >> https://lists.sourceforge.net/lists/listinfo/canfestival-devel >> >> > > -- Leonid Tochinski Senior Software Architect ChattenAssociates, Inc. 610-940-6040x118 lto...@ch... |