]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/btimers.c
Allow plugins to add drives to vss snapshot
[bacula/bacula] / bacula / src / lib / btimers.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Process and thread timer routines, built on top of watchdogs.
30  *
31  *    Nic Bellamy <nic@bellamy.co.nz>, October 2004.
32  *
33 */
34
35 #include "bacula.h"
36 #include "jcr.h"
37
38 const int dbglvl = 900;
39
40 /* Forward referenced functions */
41 static void stop_btimer(btimer_t *wid);
42 static btimer_t *btimer_start_common(uint32_t wait);
43
44 /* Forward referenced callback functions */
45 static void callback_child_timer(watchdog_t *self);
46 static void callback_thread_timer(watchdog_t *self);
47 #ifdef xxx
48 static void destructor_thread_timer(watchdog_t *self);
49 static void destructor_child_timer(watchdog_t *self);
50 #endif
51
52 /*
53  * Start a timer on a child process of pid, kill it after wait seconds.
54  *
55  *  Returns: btimer_t *(pointer to btimer_t struct) on success
56  *           NULL on failure
57  */
58 btimer_t *start_child_timer(JCR *jcr, pid_t pid, uint32_t wait)
59 {
60    btimer_t *wid;
61
62    wid = btimer_start_common(wait);
63    if (wid == NULL) {
64       return NULL;
65    }
66    wid->type = TYPE_CHILD;
67    wid->pid = pid;
68    wid->killed = false;
69    wid->jcr = jcr;
70
71    wid->wd->callback = callback_child_timer;
72    wid->wd->one_shot = false;
73    wid->wd->interval = wait;
74    register_watchdog(wid->wd);
75
76    Dmsg3(dbglvl, "Start child timer %p, pid %d for %d secs.\n", wid, pid, wait);
77    return wid;
78 }
79
80 /*
81  * Stop child timer
82  */
83 void stop_child_timer(btimer_t *wid)
84 {
85    if (wid == NULL) {
86       Dmsg0(dbglvl, "stop_child_timer called with NULL btimer_id\n");
87       return;
88    }
89    Dmsg2(dbglvl, "Stop child timer %p pid %d\n", wid, wid->pid);
90    stop_btimer(wid);
91 }
92
93 #ifdef xxx
94 static void destructor_child_timer(watchdog_t *self)
95 {
96    btimer_t *wid = (btimer_t *)self->data;
97    free(wid->wd);
98    free(wid);
99 }
100 #endif
101
102 static void callback_child_timer(watchdog_t *self)
103 {
104    btimer_t *wid = (btimer_t *)self->data;
105
106    if (!wid->killed) {
107       /* First kill attempt; try killing it softly (kill -SONG) first */
108       wid->killed = true;
109
110       Dmsg2(dbglvl, "watchdog %p term PID %d\n", self, wid->pid);
111
112       /* Kill -TERM the specified PID, and reschedule a -KILL for 5 seconds
113        * later. (Warning: this should let dvd-writepart enough time to term
114        * and kill growisofs, which takes 3 seconds, so the interval must not
115        * be less than 5 seconds)
116        */
117       kill(wid->pid, SIGTERM);
118       self->interval = 5;
119    } else {
120       /* This is the second call - terminate with prejudice. */
121       Dmsg2(dbglvl, "watchdog %p kill PID %d\n", self, wid->pid);
122
123       kill(wid->pid, SIGKILL);
124
125       /* Setting one_shot to true before we leave ensures we don't get
126        * rescheduled.
127        */
128       self->one_shot = true;
129    }
130 }
131
132 /*
133  * Start a timer on a thread. kill it after wait seconds.
134  *
135  *  Returns: btimer_t *(pointer to btimer_t struct) on success
136  *           NULL on failure
137  */
138 btimer_t *start_thread_timer(JCR *jcr, pthread_t tid, uint32_t wait)
139 {
140    btimer_t *wid;
141    wid = btimer_start_common(wait);
142    if (wid == NULL) {
143       Dmsg1(dbglvl, "start_thread_timer return NULL from common. wait=%d.\n", wait);
144       return NULL;
145    }
146    wid->type = TYPE_PTHREAD;
147    wid->tid = tid;
148    wid->jcr = jcr;
149
150    wid->wd->callback = callback_thread_timer;
151    wid->wd->one_shot = true;
152    wid->wd->interval = wait;
153    register_watchdog(wid->wd);
154
155    Dmsg3(dbglvl, "Start thread timer %p tid %p for %d secs.\n", wid, tid, wait);
156
157    return wid;
158 }
159
160 /*
161  * Start a timer on a BSOCK. kill it after wait seconds.
162  *
163  *  Returns: btimer_t *(pointer to btimer_t struct) on success
164  *           NULL on failure
165  */
166 btimer_t *start_bsock_timer(BSOCK *bsock, uint32_t wait)
167 {
168    btimer_t *wid;
169    if (wait <= 0) {                 /* wait should be > 0 */
170       return NULL;
171    }
172    wid = btimer_start_common(wait);
173    if (wid == NULL) {
174       return NULL;
175    }
176    wid->type = TYPE_BSOCK;
177    wid->tid = pthread_self();
178    wid->bsock = bsock;
179    wid->jcr = bsock->jcr(); 
180
181    wid->wd->callback = callback_thread_timer;
182    wid->wd->one_shot = true;
183    wid->wd->interval = wait;
184    register_watchdog(wid->wd);
185
186    Dmsg4(dbglvl, "Start bsock timer %p tid=%p for %d secs at %d\n", wid,
187          wid->tid, wait, time(NULL));
188
189    return wid;
190 }
191
192 /*
193  * Stop bsock timer
194  */
195 void stop_bsock_timer(btimer_t *wid)
196 {
197    if (wid == NULL) {
198       Dmsg0(900, "stop_bsock_timer called with NULL btimer_id\n");
199       return;
200    }
201    Dmsg3(dbglvl, "Stop bsock timer %p tid=%p at %d.\n", wid, wid->tid, time(NULL));
202    stop_btimer(wid);
203 }
204
205
206 /*
207  * Stop thread timer
208  */
209 void stop_thread_timer(btimer_t *wid)
210 {
211    if (wid == NULL) {
212       Dmsg0(dbglvl, "stop_thread_timer called with NULL btimer_id\n");
213       return;
214    }
215    Dmsg2(dbglvl, "Stop thread timer %p tid=%p.\n", wid, wid->tid);
216    stop_btimer(wid);
217 }
218
219 #ifdef xxx
220 static void destructor_thread_timer(watchdog_t *self)
221 {
222    btimer_t *wid = (btimer_t *)self->data;
223    free(wid->wd);
224    free(wid);
225 }
226 #endif
227
228 static void callback_thread_timer(watchdog_t *self)
229 {
230    btimer_t *wid = (btimer_t *)self->data;
231
232    Dmsg4(dbglvl, "thread timer %p kill %s tid=%p at %d.\n", self,
233       wid->type == TYPE_BSOCK ? "bsock" : "thread", wid->tid, time(NULL));
234    if (wid->jcr) {
235       Dmsg2(dbglvl, "killed jid=%u Job=%s\n", wid->jcr->JobId, wid->jcr->Job);
236    }
237
238    if (wid->type == TYPE_BSOCK && wid->bsock) {
239       wid->bsock->set_timed_out();
240    }
241    pthread_kill(wid->tid, TIMEOUT_SIGNAL);
242 }
243
244 static btimer_t *btimer_start_common(uint32_t wait)
245 {
246    btimer_t *wid = (btimer_t *)malloc(sizeof(btimer_t));
247
248    wid->wd = new_watchdog();
249    if (wid->wd == NULL) {
250       free(wid);
251       return NULL;
252    }
253    wid->wd->data = wid;
254    wid->killed = FALSE;
255
256    return wid;
257 }
258
259 /*
260  * Stop btimer
261  */
262 static void stop_btimer(btimer_t *wid)
263 {
264    if (wid == NULL) {
265       Emsg0(M_ABORT, 0, _("stop_btimer called with NULL btimer_id\n"));
266    }
267    unregister_watchdog(wid->wd);
268    free(wid->wd);
269    free(wid);
270 }