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