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