2 * Bacula thread watchdog routine. General routine that monitors
3 * the daemon and signals a thread if it is blocked on a BSOCK
4 * too long. This prevents catastropic long waits -- generally
5 * due to Windows "hanging" the app.
7 * Kern Sibbald, January MMII
11 Copyright (C) 2000-2003 Kern Sibbald and John Walker
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
33 /* This breaks Kern's #include rules, but I don't want to put it into bacula.h
34 * until it has been discussed with him */
35 #include "bsd_queue.h"
37 /* Exported globals */
38 time_t watchdog_time; /* this has granularity of SLEEP_TIME */
40 #define SLEEP_TIME 1 /* examine things every second */
42 /* Forward referenced functions */
43 static void *watchdog_thread(void *arg);
46 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
47 static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
49 static bool wd_is_init = false;
51 /* Forward referenced callback functions */
52 static void callback_child_timer(watchdog_t *self);
53 static void callback_thread_timer(watchdog_t *self);
54 static pthread_t wd_tid;
57 static TAILQ_HEAD(/* no struct */, s_watchdog_t) wd_queue =
58 TAILQ_HEAD_INITIALIZER(wd_queue);
59 static TAILQ_HEAD(/* no struct */, s_watchdog_t) wd_inactive =
60 TAILQ_HEAD_INITIALIZER(wd_inactive);
63 * Start watchdog thread
65 * Returns: 0 on success
68 int start_watchdog(void)
72 Dmsg0(200, "Initialising NicB-hacked watchdog thread\n");
73 watchdog_time = time(NULL);
75 if ((stat = pthread_create(&wd_tid, NULL, watchdog_thread, NULL)) != 0) {
83 * Terminate the watchdog thread
85 * Returns: 0 on success
88 int stop_watchdog(void)
94 Emsg0(M_ABORT, 0, "BUG! stop_watchdog called before start_watchdog\n");
97 Dmsg0(200, "Sending stop signal to NicB-hacked watchdog thread\n");
100 stat = pthread_cond_signal(&timer);
105 stat = pthread_join(wd_tid, NULL);
107 TAILQ_FOREACH_SAFE(p, &wd_queue, qe, n) {
108 TAILQ_REMOVE(&wd_queue, p, qe);
109 if (p->destructor != NULL) {
115 TAILQ_FOREACH_SAFE(p, &wd_inactive, qe, n) {
116 TAILQ_REMOVE(&wd_inactive, p, qe);
117 if (p->destructor != NULL) {
126 watchdog_t *watchdog_new(void)
128 watchdog_t *wd = (watchdog_t *) malloc(sizeof(watchdog_t));
131 Emsg0(M_ABORT, 0, "BUG! watchdog_new called before start_watchdog\n");
140 wd->destructor = NULL;
146 bool register_watchdog(watchdog_t *wd)
149 Emsg0(M_ABORT, 0, "BUG! register_watchdog called before start_watchdog\n");
151 if (wd->callback == NULL) {
152 Emsg1(M_ABORT, 0, "BUG! Watchdog %p has NULL callback\n", wd);
154 if (wd->interval == 0) {
155 Emsg1(M_ABORT, 0, "BUG! Watchdog %p has zero interval\n", wd);
159 wd->next_fire = watchdog_time + wd->interval;
160 TAILQ_INSERT_TAIL(&wd_queue, wd, qe);
161 Dmsg3(200, "Registered watchdog %p, interval %d%s\n",
162 wd, wd->interval, wd->one_shot ? " one shot" : "");
168 bool unregister_watchdog_unlocked(watchdog_t *wd)
173 Emsg0(M_ABORT, 0, "BUG! unregister_watchdog_unlocked called before start_watchdog\n");
176 TAILQ_FOREACH_SAFE(p, &wd_queue, qe, n) {
178 TAILQ_REMOVE(&wd_queue, wd, qe);
179 Dmsg1(200, "Unregistered watchdog %p\n", wd);
184 TAILQ_FOREACH_SAFE(p, &wd_inactive, qe, n) {
186 TAILQ_REMOVE(&wd_inactive, wd, qe);
187 Dmsg1(200, "Unregistered inactive watchdog %p\n", wd);
192 Dmsg1(200, "Failed to unregister watchdog %p\n", wd);
197 bool unregister_watchdog(watchdog_t *wd)
202 Emsg0(M_ABORT, 0, "BUG! unregister_watchdog called before start_watchdog\n");
206 ret = unregister_watchdog_unlocked(wd);
212 static void *watchdog_thread(void *arg)
214 Dmsg0(200, "NicB-reworked watchdog thread entered\n");
225 watchdog_time = time(NULL);
227 TAILQ_FOREACH_SAFE(p, &wd_queue, qe, n) {
228 if (p->next_fire < watchdog_time) {
229 /* Run the callback */
232 /* Reschedule (or move to inactive list if it's a one-shot timer) */
234 TAILQ_REMOVE(&wd_queue, p, qe);
235 TAILQ_INSERT_TAIL(&wd_inactive, p, qe);
237 p->next_fire = watchdog_time + p->interval;
242 bmicrosleep(SLEEP_TIME, 0);
245 Dmsg0(200, "NicB-reworked watchdog thread exited\n");