]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/btimers.c
8e3757e987617dc4d98f047ed0465356e94b778e
[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 two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed 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 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 John Walker.
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 /* Forward referenced functions */
39 static void stop_btimer(btimer_t *wid);
40 static btimer_t *btimer_start_common(uint32_t wait);
41
42 /* Forward referenced callback functions */
43 static void callback_child_timer(watchdog_t *self);
44 static void callback_thread_timer(watchdog_t *self);
45 #ifdef xxx
46 static void destructor_thread_timer(watchdog_t *self);
47 static void destructor_child_timer(watchdog_t *self);
48 #endif
49
50 /*
51  * Start a timer on a child process of pid, kill it after wait seconds.
52  *
53  *  Returns: btimer_t *(pointer to btimer_t struct) on success
54  *           NULL on failure
55  */
56 btimer_t *start_child_timer(pid_t pid, uint32_t wait)
57 {
58    btimer_t *wid;
59
60    wid = btimer_start_common(wait);
61    if (wid == NULL) {
62       return NULL;
63    }
64    wid->type = TYPE_CHILD;
65    wid->pid = pid;
66    wid->killed = false;
67
68    wid->wd->callback = callback_child_timer;
69    wid->wd->one_shot = false;
70    wid->wd->interval = wait;
71    register_watchdog(wid->wd);
72
73    Dmsg3(900, "Start child timer %p, pid %d for %d secs.\n", wid, pid, wait);
74    return wid;
75 }
76
77 /*
78  * Stop child timer
79  */
80 void stop_child_timer(btimer_t *wid)
81 {
82    if (wid == NULL) {
83       Dmsg0(900, "stop_child_timer called with NULL btimer_id\n");
84       return;
85    }
86    Dmsg2(900, "Stop child timer %p pid %d\n", wid, wid->pid);
87    stop_btimer(wid);
88 }
89
90 #ifdef xxx
91 static void destructor_child_timer(watchdog_t *self)
92 {
93    btimer_t *wid = (btimer_t *)self->data;
94    free(wid->wd);
95    free(wid);
96 }
97 #endif
98
99 static void callback_child_timer(watchdog_t *self)
100 {
101    btimer_t *wid = (btimer_t *)self->data;
102
103    if (!wid->killed) {
104       /* First kill attempt; try killing it softly (kill -SONG) first */
105       wid->killed = true;
106
107       Dmsg2(050, "watchdog %p term PID %d\n", self, wid->pid);
108
109       /* Kill -TERM the specified PID, and reschedule a -KILL for 5 seconds
110        * later. (Warning: this should let dvd-writepart enough time to term
111        * and kill growisofs, which takes 3 seconds, so the interval must not
112        * be less than 5 seconds)
113        */
114       kill(wid->pid, SIGTERM);
115       self->interval = 5;
116    } else {
117       /* This is the second call - terminate with prejudice. */
118       Dmsg2(050, "watchdog %p kill PID %d\n", self, wid->pid);
119
120       kill(wid->pid, SIGKILL);
121
122       /* Setting one_shot to true before we leave ensures we don't get
123        * rescheduled.
124        */
125       self->one_shot = true;
126    }
127 }
128
129 /*
130  * Start a timer on a thread. kill it after wait seconds.
131  *
132  *  Returns: btimer_t *(pointer to btimer_t struct) on success
133  *           NULL on failure
134  */
135 btimer_t *start_thread_timer(pthread_t tid, uint32_t wait)
136 {
137    btimer_t *wid;
138    wid = btimer_start_common(wait);
139    if (wid == NULL) {
140       Dmsg1(900, "start_thread_timer return NULL from common. wait=%d.\n", wait);
141       return NULL;
142    }
143    wid->type = TYPE_PTHREAD;
144    wid->tid = tid;
145
146    wid->wd->callback = callback_thread_timer;
147    wid->wd->one_shot = true;
148    wid->wd->interval = wait;
149    register_watchdog(wid->wd);
150
151    Dmsg3(900, "Start thread timer %p tid %p for %d secs.\n", wid, tid, wait);
152
153    return wid;
154 }
155
156 /*
157  * Start a timer on a BSOCK. kill it after wait seconds.
158  *
159  *  Returns: btimer_t *(pointer to btimer_t struct) on success
160  *           NULL on failure
161  */
162 btimer_t *start_bsock_timer(BSOCK *bsock, uint32_t wait)
163 {
164    btimer_t *wid;
165    wid = btimer_start_common(wait);
166    if (wid == NULL) {
167       return NULL;
168    }
169    wid->type = TYPE_BSOCK;
170    wid->tid = pthread_self();
171    wid->bsock = bsock;
172
173    wid->wd->callback = callback_thread_timer;
174    wid->wd->one_shot = true;
175    wid->wd->interval = wait;
176    register_watchdog(wid->wd);
177
178    Dmsg4(950, "Start bsock timer %p tid=%p for %d secs at %d\n", wid,
179          wid->tid, wait, time(NULL));
180
181    return wid;
182 }
183
184 /*
185  * Stop bsock timer
186  */
187 void stop_bsock_timer(btimer_t *wid)
188 {
189    if (wid == NULL) {
190       Dmsg0(900, "stop_bsock_timer called with NULL btimer_id\n");
191       return;
192    }
193    Dmsg3(950, "Stop bsock timer %p tid=%p at %d.\n", wid, wid->tid, time(NULL));
194    stop_btimer(wid);
195 }
196
197
198 /*
199  * Stop thread timer
200  */
201 void stop_thread_timer(btimer_t *wid)
202 {
203    if (wid == NULL) {
204       Dmsg0(900, "stop_thread_timer called with NULL btimer_id\n");
205       return;
206    }
207    Dmsg2(900, "Stop thread timer %p tid=%p.\n", wid, wid->tid);
208    stop_btimer(wid);
209 }
210
211 #ifdef xxx
212 static void destructor_thread_timer(watchdog_t *self)
213 {
214    btimer_t *wid = (btimer_t *)self->data;
215    free(wid->wd);
216    free(wid);
217 }
218 #endif
219
220 static void callback_thread_timer(watchdog_t *self)
221 {
222    btimer_t *wid = (btimer_t *)self->data;
223
224    Dmsg4(50, "thread timer %p kill %s tid=%p at %d.\n", self,
225       wid->type == TYPE_BSOCK ? "bsock" : "thread", wid->tid, time(NULL));
226
227    if (wid->type == TYPE_BSOCK && wid->bsock) {
228       wid->bsock->m_timed_out = true;
229    }
230    pthread_kill(wid->tid, TIMEOUT_SIGNAL);
231 }
232
233 static btimer_t *btimer_start_common(uint32_t wait)
234 {
235    btimer_t *wid = (btimer_t *)malloc(sizeof(btimer_t));
236
237    wid->wd = new_watchdog();
238    if (wid->wd == NULL) {
239       free(wid);
240       return NULL;
241    }
242    wid->wd->data = wid;
243    wid->killed = FALSE;
244
245    return wid;
246 }
247
248 /*
249  * Stop btimer
250  */
251 static void stop_btimer(btimer_t *wid)
252 {
253    if (wid == NULL) {
254       Emsg0(M_ABORT, 0, _("stop_btimer called with NULL btimer_id\n"));
255    }
256    unregister_watchdog(wid->wd);
257    free(wid->wd);
258    free(wid);
259 }