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