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