]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/btimers.c
kes Prepare to add JS_Warnings termination status.
[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 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 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    wid = btimer_start_common(wait);
170    if (wid == NULL) {
171       return NULL;
172    }
173    wid->type = TYPE_BSOCK;
174    wid->tid = pthread_self();
175    wid->bsock = bsock;
176    wid->jcr = bsock->jcr(); 
177
178    wid->wd->callback = callback_thread_timer;
179    wid->wd->one_shot = true;
180    wid->wd->interval = wait;
181    register_watchdog(wid->wd);
182
183    Dmsg4(dbglvl, "Start bsock timer %p tid=%p for %d secs at %d\n", wid,
184          wid->tid, wait, time(NULL));
185
186    return wid;
187 }
188
189 /*
190  * Stop bsock timer
191  */
192 void stop_bsock_timer(btimer_t *wid)
193 {
194    if (wid == NULL) {
195       Dmsg0(900, "stop_bsock_timer called with NULL btimer_id\n");
196       return;
197    }
198    Dmsg3(dbglvl, "Stop bsock timer %p tid=%p at %d.\n", wid, wid->tid, time(NULL));
199    stop_btimer(wid);
200 }
201
202
203 /*
204  * Stop thread timer
205  */
206 void stop_thread_timer(btimer_t *wid)
207 {
208    if (wid == NULL) {
209       Dmsg0(dbglvl, "stop_thread_timer called with NULL btimer_id\n");
210       return;
211    }
212    Dmsg2(dbglvl, "Stop thread timer %p tid=%p.\n", wid, wid->tid);
213    stop_btimer(wid);
214 }
215
216 #ifdef xxx
217 static void destructor_thread_timer(watchdog_t *self)
218 {
219    btimer_t *wid = (btimer_t *)self->data;
220    free(wid->wd);
221    free(wid);
222 }
223 #endif
224
225 static void callback_thread_timer(watchdog_t *self)
226 {
227    btimer_t *wid = (btimer_t *)self->data;
228
229    Dmsg4(dbglvl, "thread timer %p kill %s tid=%p at %d.\n", self,
230       wid->type == TYPE_BSOCK ? "bsock" : "thread", wid->tid, time(NULL));
231    if (wid->jcr) {
232       Dmsg2(dbglvl, "killed jid=%u Job=%s\n", wid->jcr->JobId, wid->jcr->Job);
233    }
234
235    if (wid->type == TYPE_BSOCK && wid->bsock) {
236       wid->bsock->set_timed_out();
237    }
238    pthread_kill(wid->tid, TIMEOUT_SIGNAL);
239 }
240
241 static btimer_t *btimer_start_common(uint32_t wait)
242 {
243    btimer_t *wid = (btimer_t *)malloc(sizeof(btimer_t));
244
245    wid->wd = new_watchdog();
246    if (wid->wd == NULL) {
247       free(wid);
248       return NULL;
249    }
250    wid->wd->data = wid;
251    wid->killed = FALSE;
252
253    return wid;
254 }
255
256 /*
257  * Stop btimer
258  */
259 static void stop_btimer(btimer_t *wid)
260 {
261    if (wid == NULL) {
262       Emsg0(M_ABORT, 0, _("stop_btimer called with NULL btimer_id\n"));
263    }
264    unregister_watchdog(wid->wd);
265    free(wid->wd);
266    free(wid);
267 }