]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/watchdog.c
Use the command line utility dropdb instead of the psql command
[bacula/bacula] / bacula / src / lib / watchdog.c
1 /*
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.
6  *
7  *  Kern Sibbald, January MMII
8  *
9  */
10 /*
11    Copyright (C) 2000-2003 Kern Sibbald and John Walker
12
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.
17
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.
22
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,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "jcr.h"
32
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"
36
37 /* Exported globals */
38 time_t watchdog_time;                 /* this has granularity of SLEEP_TIME */
39
40 #define SLEEP_TIME 1                  /* examine things every second */
41
42 /* Forward referenced functions */
43 static void *watchdog_thread(void *arg);
44
45 /* Static globals */
46 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
47 static pthread_cond_t  timer = PTHREAD_COND_INITIALIZER;
48 static bool quit;
49 static bool wd_is_init = false;
50
51 /* Forward referenced callback functions */
52 static pthread_t wd_tid;
53
54 /* Static globals */
55 static TAILQ_HEAD(/* no struct */, s_watchdog_t) wd_queue =
56         TAILQ_HEAD_INITIALIZER(wd_queue);
57 static TAILQ_HEAD(/* no struct */, s_watchdog_t) wd_inactive =
58         TAILQ_HEAD_INITIALIZER(wd_inactive);
59
60 /*   
61  * Start watchdog thread
62  *
63  *  Returns: 0 on success
64  *           errno on failure
65  */
66 int start_watchdog(void)
67 {
68    int stat;
69
70    Dmsg0(200, "Initialising NicB-hacked watchdog thread\n");
71    watchdog_time = time(NULL);
72    quit = false;
73    if ((stat = pthread_create(&wd_tid, NULL, watchdog_thread, NULL)) != 0) {
74       return stat;
75    }
76    wd_is_init = true;
77    return 0;
78 }
79
80 /*
81  * Terminate the watchdog thread
82  *
83  * Returns: 0 on success
84  *          errno on failure
85  */
86 int stop_watchdog(void)
87 {
88    int stat;
89    watchdog_t *p, *n;
90
91    if (!wd_is_init) {
92       return 0;
93    }
94
95    Dmsg0(200, "Sending stop signal to NicB-hacked watchdog thread\n");
96    P(mutex);
97    quit = true;
98    stat = pthread_cond_signal(&timer);
99    V(mutex);
100
101    wd_is_init = false;
102
103    stat = pthread_join(wd_tid, NULL);
104
105    TAILQ_FOREACH_SAFE(p, &wd_queue, qe, n) {
106       TAILQ_REMOVE(&wd_queue, p, qe);
107       if (p->destructor != NULL) {
108          p->destructor(p);
109       }
110       free(p);
111    }
112
113    TAILQ_FOREACH_SAFE(p, &wd_inactive, qe, n) {
114       TAILQ_REMOVE(&wd_inactive, p, qe);
115       if (p->destructor != NULL) {
116          p->destructor(p);
117       }
118       free(p);
119    }
120
121    return stat;
122 }
123
124 watchdog_t *watchdog_new(void)
125 {
126    watchdog_t *wd = (watchdog_t *) malloc(sizeof(watchdog_t));
127
128    if (!wd_is_init) {
129       Emsg0(M_ABORT, 0, "BUG! watchdog_new called before start_watchdog\n");
130    }
131
132    if (wd == NULL) {
133       return NULL;
134    }
135    wd->one_shot = true;
136    wd->interval = 0;
137    wd->callback = NULL;
138    wd->destructor = NULL;
139    wd->data = NULL;
140
141    return wd;
142 }
143
144 bool register_watchdog(watchdog_t *wd)
145 {
146    if (!wd_is_init) {
147       Emsg0(M_ABORT, 0, "BUG! register_watchdog called before start_watchdog\n");
148    }
149    if (wd->callback == NULL) {
150       Emsg1(M_ABORT, 0, "BUG! Watchdog %p has NULL callback\n", wd);
151    }
152    if (wd->interval == 0) {
153       Emsg1(M_ABORT, 0, "BUG! Watchdog %p has zero interval\n", wd);
154    }
155
156    P(mutex);
157    wd->next_fire = watchdog_time + wd->interval;
158    TAILQ_INSERT_TAIL(&wd_queue, wd, qe);
159    Dmsg3(200, "Registered watchdog %p, interval %d%s\n",
160          wd, wd->interval, wd->one_shot ? " one shot" : "");
161    V(mutex);
162
163    return false;
164 }
165
166 bool unregister_watchdog_unlocked(watchdog_t *wd)
167 {
168    watchdog_t *p, *n;
169
170    if (!wd_is_init) {
171       Emsg0(M_ABORT, 0, "BUG! unregister_watchdog_unlocked called before start_watchdog\n");
172    }
173
174    TAILQ_FOREACH_SAFE(p, &wd_queue, qe, n) {
175       if (wd == p) {
176          TAILQ_REMOVE(&wd_queue, wd, qe);
177          Dmsg1(200, "Unregistered watchdog %p\n", wd);
178          return true;
179       }
180    }
181
182    TAILQ_FOREACH_SAFE(p, &wd_inactive, qe, n) {
183       if (wd == p) {
184          TAILQ_REMOVE(&wd_inactive, wd, qe);
185          Dmsg1(200, "Unregistered inactive watchdog %p\n", wd);
186          return true;
187       }
188    }
189
190    Dmsg1(200, "Failed to unregister watchdog %p\n", wd);
191
192    return false;
193 }
194
195 bool unregister_watchdog(watchdog_t *wd)
196 {
197    bool ret;
198
199    if (!wd_is_init) {
200       Emsg0(M_ABORT, 0, "BUG! unregister_watchdog called before start_watchdog\n");
201    }
202
203    P(mutex);
204    ret = unregister_watchdog_unlocked(wd);
205    V(mutex);
206
207    return ret;
208 }
209
210 static void *watchdog_thread(void *arg)
211 {
212    Dmsg0(200, "NicB-reworked watchdog thread entered\n");
213
214    while (true) {
215       watchdog_t *p, *n;
216
217       P(mutex);
218       if (quit) {
219          V(mutex);
220          break;
221       }
222
223       watchdog_time = time(NULL);
224
225       TAILQ_FOREACH_SAFE(p, &wd_queue, qe, n) {
226          if (p->next_fire < watchdog_time) {
227             /* Run the callback */
228             p->callback(p);
229
230             /* Reschedule (or move to inactive list if it's a one-shot timer) */
231             if (p->one_shot) {
232                TAILQ_REMOVE(&wd_queue, p, qe);
233                TAILQ_INSERT_TAIL(&wd_inactive, p, qe);
234             } else {
235                p->next_fire = watchdog_time + p->interval;
236             }
237          }
238       }
239       V(mutex);
240       bmicrosleep(SLEEP_TIME, 0);
241    }
242
243    Dmsg0(200, "NicB-reworked watchdog thread exited\n");
244
245    return NULL;
246 }