root/trunk/libffado/src/libutil/Watchdog.cpp

Revision 1336, 8.7 kB (checked in by ppalmers, 16 years ago)

Bring trunk up to date with branches/libffado-2.0:

"""
svn merge -r 1254:1299 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
svn merge -r 1301:1320 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
svn merge -r 1322:1323 svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
svn merge -r 1329:HEAD svn+ssh://ffadosvn@ffado.org/ffado/branches/libffado-2.0
"""

Add getSupportedSamplingFrequencies() to DICE, RME and Metric Halo AvDevices?

Line 
1 /*
2  * Copyright (C) 2005-2008 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "Watchdog.h"
25 #include "SystemTimeSource.h"
26 #include "PosixThread.h"
27
28 #include "config.h"
29
30 // needed for clock_nanosleep
31 #ifndef _GNU_SOURCE
32     #define _GNU_SOURCE
33 #endif
34
35 #include <time.h>
36
37 namespace Util {
38
39 IMPL_DEBUG_MODULE( Watchdog, Watchdog, DEBUG_LEVEL_NORMAL );
40
41 // --- liveness check Thread --- //
42 Watchdog::WatchdogCheckTask::WatchdogCheckTask(Watchdog& parent, unsigned int interval_usecs)
43     : m_parent( parent )
44     , m_interval( interval_usecs )
45     , m_debugModule( parent.m_debugModule )
46 {
47 }
48
49 bool
50 Watchdog::WatchdogCheckTask::Init()
51 {
52     #ifdef DEBUG
53     m_last_loop_entry = 0;
54     m_successive_short_loops = 0;
55     #endif
56     return true;
57 }
58
59 bool
60 Watchdog::WatchdogCheckTask::Execute()
61 {
62     SystemTimeSource::SleepUsecRelative(m_interval);
63     if(m_parent.getHartbeat()) {
64         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
65                     "(%p) watchdog %p still alive\n", this, &m_parent);
66         m_parent.clearHartbeat();
67     } else {
68         debugWarning("(%p) watchdog %p died\n", this, &m_parent);
69         // set all watched threads to non-rt scheduling
70         m_parent.rescheduleThreads();
71     }
72
73     #ifdef DEBUG
74     uint64_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
75     int diff = now - m_last_loop_entry;
76     if(diff < 100) {
77         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
78                            "(%p) short loop detected (%d usec), cnt: %d\n",
79                            this, diff, m_successive_short_loops);
80         m_successive_short_loops++;
81         if(m_successive_short_loops > 100) {
82             debugError("Shutting down runaway thread\n");
83             return false;
84         }
85     } else {
86         // reset the counter
87         m_successive_short_loops = 0;
88     }
89     m_last_loop_entry = now;
90     #endif
91
92     return true;
93 }
94
95 // --- hartbeat Thread --- //
96
97 Watchdog::WatchdogHartbeatTask::WatchdogHartbeatTask(Watchdog& parent, unsigned int interval_usecs)
98     : m_parent( parent )
99     , m_interval( interval_usecs )
100     , m_debugModule( parent.m_debugModule )
101 {
102 }
103
104 bool
105 Watchdog::WatchdogHartbeatTask::Init()
106 {
107     #ifdef DEBUG
108     m_last_loop_entry = 0;
109     m_successive_short_loops = 0;
110     #endif
111     return true;
112 }
113
114 bool
115 Watchdog::WatchdogHartbeatTask::Execute()
116 {
117     SystemTimeSource::SleepUsecRelative(m_interval);
118     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
119                 "(%p) watchdog %p hartbeat\n", this, &m_parent);
120     m_parent.setHartbeat();
121
122     #ifdef DEBUG
123     uint64_t now = Util::SystemTimeSource::getCurrentTimeAsUsecs();
124     int diff = now - m_last_loop_entry;
125     if(diff < 100) {
126         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
127                            "(%p) short loop detected (%d usec), cnt: %d\n",
128                            this, diff, m_successive_short_loops);
129         m_successive_short_loops++;
130         if(m_successive_short_loops > 100) {
131             debugError("Shutting down runaway thread\n");
132             return false;
133         }
134     } else {
135         // reset the counter
136         m_successive_short_loops = 0;
137     }
138     m_last_loop_entry = now;
139     #endif
140
141     return true;
142 }
143
144 // the actual watchdog class
145 Watchdog::Watchdog()
146 : m_hartbeat( true )
147 , m_check_interval( WATCHDOG_DEFAULT_CHECK_INTERVAL_USECS )
148 , m_realtime( WATCHDOG_DEFAULT_RUN_REALTIME )
149 , m_priority( WATCHDOG_DEFAULT_PRIORITY )
150 , m_CheckThread( NULL )
151 , m_HartbeatThread( NULL )
152 , m_CheckTask( NULL )
153 , m_HartbeatTask( NULL )
154 {
155 }
156
157 Watchdog::Watchdog(unsigned int interval_usec, bool realtime, unsigned int priority)
158 : m_hartbeat( true )
159 , m_check_interval( interval_usec )
160 , m_realtime( realtime )
161 , m_priority( priority )
162 , m_CheckThread( NULL )
163 , m_HartbeatThread( NULL )
164 , m_CheckTask( NULL )
165 , m_HartbeatTask( NULL )
166 {
167 }
168
169 Watchdog::~Watchdog()
170 {
171     // kill threads instead of stoping them since
172     // they are sleeping
173     if (m_CheckThread) {
174         //m_CheckThread->Stop();
175         m_CheckThread->Kill();
176         delete m_CheckThread;
177     }
178     if (m_HartbeatThread) {
179         //m_HartbeatThread->Stop();
180         m_HartbeatThread->Kill();
181         delete m_HartbeatThread;
182     }
183     if (m_CheckTask) {
184         delete m_CheckTask;
185     }
186     if (m_HartbeatTask) {
187         delete m_HartbeatTask;
188     }
189 }
190
191 void
192 Watchdog::setVerboseLevel(int i)
193 {
194     setDebugLevel(i);
195 }
196
197 bool
198 Watchdog::start()
199 {
200     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) Starting watchdog...\n", this);
201     debugOutput( DEBUG_LEVEL_VERBOSE, "Create hartbeat task/thread for %p...\n", this);
202     m_HartbeatTask = new WatchdogHartbeatTask( *this, m_check_interval/2 );
203     if(!m_HartbeatTask) {
204         debugFatal("No hartbeat task\n");
205         return false;
206     }
207     m_HartbeatThread = new Util::PosixThread(m_HartbeatTask, "WDGHBT", false,
208                                              0, PTHREAD_CANCEL_ASYNCHRONOUS);
209     if(!m_HartbeatThread) {
210         debugFatal("No hartbeat thread\n");
211         return false;
212     }
213     debugOutput( DEBUG_LEVEL_VERBOSE,
214                  " hartbeat task: %p, thread %p...\n",
215                  m_HartbeatTask, m_HartbeatThread);
216
217     debugOutput( DEBUG_LEVEL_VERBOSE, "Create check task/thread for %p...\n", this);
218     m_CheckTask = new WatchdogCheckTask( *this, m_check_interval );
219     if(!m_CheckTask) {
220         debugFatal("No check task\n");
221         return false;
222     }
223     m_CheckThread = new Util::PosixThread(m_CheckTask,"WDGCHK", false,
224                                           0, PTHREAD_CANCEL_ASYNCHRONOUS);
225     if(!m_CheckThread) {
226         debugFatal("No check thread\n");
227         return false;
228     }
229     debugOutput( DEBUG_LEVEL_VERBOSE,
230                  " check task: %p, thread %p...\n",
231                  m_CheckTask, m_CheckThread);
232
233     // switch to realtime if necessary
234     if(m_realtime) {
235         if(!m_CheckThread->AcquireRealTime(m_priority)) {
236             debugWarning("(%p) Could not aquire realtime priotiry for watchdog thread.\n", this);
237         }
238     }
239
240     // start threads
241     if (m_HartbeatThread->Start() != 0) {
242         debugFatal("Could not start hartbeat thread\n");
243         return false;
244     }
245     if (m_CheckThread->Start() != 0) {
246         debugFatal("Could not start check thread\n");
247         return false;
248     }
249     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) Watchdog running...\n", this);
250     return true;
251 }
252
253 bool
254 Watchdog::setThreadParameters(bool rt, int priority)
255 {
256     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
257     if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority
258     m_realtime = rt;
259     m_priority = priority;
260
261     if (m_CheckThread) {
262         if (m_realtime) {
263             m_CheckThread->AcquireRealTime(m_priority);
264         } else {
265             m_CheckThread->DropRealTime();
266         }
267     }
268     return true;
269 }
270
271 /**
272  * register a thread to the watchdog
273  * @param thread
274  * @return
275  */
276 bool
277 Watchdog::registerThread(Thread *thread)
278 {
279     assert(thread);
280     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) Adding thread %p\n",
281         this, thread);
282
283     for ( ThreadVectorIterator it = m_Threads.begin();
284       it != m_Threads.end();
285       ++it )
286     {
287         if(*it == thread) {
288             debugError("Thread %p already registered with watchdog\n", thread);
289             return false;
290         }
291     }
292     m_Threads.push_back(thread);
293     return true;
294 }
295
296 bool
297 Watchdog::unregisterThread(Thread *thread)
298 {
299     assert(thread);
300     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) unregistering thread %p\n", this, thread);
301
302     for ( ThreadVectorIterator it = m_Threads.begin();
303       it != m_Threads.end();
304       ++it )
305     {
306         if(*it == thread) {
307             m_Threads.erase(it);
308             return true;
309         }
310     }
311     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) thread %p not found \n", this, thread);
312     return false; //not found
313 }
314
315 void Watchdog::rescheduleThreads()
316 {
317     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) rescheduling threads\n", this);
318
319     for ( ThreadVectorIterator it = m_Threads.begin();
320       it != m_Threads.end();
321       ++it )
322     {
323         (*it)->DropRealTime();
324     }
325 }
326
327 } // end of namespace Util
Note: See TracBrowser for help on using the browser.