]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/btimers.c
Restore JobIds in right order + Tru64 porting
[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(200, "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(200, "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    Dmsg3(200, "Start thread timer %p tip %p for %d secs.\n", wid, wid->tid, wait);
169
170    return wid;
171 }
172
173 /*
174  * Stop bsock timer
175  */
176 void stop_bsock_timer(btimer_t *wid)
177 {
178    if (wid == NULL) {
179       Dmsg0(200, "stop_bsock_timer called with NULL btimer_id\n");
180       return;
181    }
182    Dmsg2(200, "Stop bsock timer %p tid %p.\n", wid, wid->tid);
183    stop_btimer(wid);
184 }
185
186
187 /*
188  * Stop thread timer
189  */
190 void stop_thread_timer(btimer_t *wid)
191 {
192    if (wid == NULL) {
193       Dmsg0(200, "stop_thread_timer called with NULL btimer_id\n");
194       return;
195    }
196    Dmsg2(200, "Stop thread timer %p tid %p.\n", wid, wid->tid);
197    stop_btimer(wid);
198 }
199
200 #ifdef xxx
201 static void destructor_thread_timer(watchdog_t *self)
202 {
203    btimer_t *wid = (btimer_t *)self->data;
204    free(wid->wd);
205    free(wid);
206 }
207 #endif
208
209 static void callback_thread_timer(watchdog_t *self)
210 {
211    btimer_t *wid = (btimer_t *)self->data;
212
213    Dmsg2(200, "watchdog %p kill thread %d\n", self, wid->tid);
214
215    if (wid->type == TYPE_BSOCK && wid->bsock) {
216       Dmsg0(200, "kill type bsock ...\n");
217       wid->bsock->timed_out = true;
218    }
219    pthread_kill(wid->tid, TIMEOUT_SIGNAL);
220 }
221
222 static btimer_t *btimer_start_common(uint32_t wait)
223 {
224    btimer_t *wid = (btimer_t *)malloc(sizeof(btimer_t));
225
226    wid->wd = new_watchdog();
227    if (wid->wd == NULL) {
228       free(wid);
229       return NULL;
230    }
231    wid->wd->data = wid;
232    wid->killed = FALSE;
233
234    return wid;
235 }
236
237 /*
238  * Stop btimer
239  */
240 static void stop_btimer(btimer_t *wid)
241 {
242    if (wid == NULL) {
243       Emsg0(M_ABORT, 0, "stop_btimer called with NULL btimer_id\n");
244    }
245    unregister_watchdog(wid->wd);
246    free(wid->wd);
247    free(wid);
248 }