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