]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/watchdog.c
Initial revision
[bacula/bacula] / bacula / src / lib / watchdog.c
1 /*
2  * Bacula thread watchdog routine. General routine that monitors
3  *  the daemon and signals a thread if it is blocked on a BSOCK
4  *  too long. This prevents catastropic long waits -- generally
5  *  due to Windows "hanging" the app.
6  *
7  *  Kern Sibbald, January MMII
8  *
9  */
10 /*
11    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "jcr.h"
32
33 /* Exported globals */
34 time_t watchdog_time;                 /* this has granularity of SLEEP_TIME */
35
36
37 #define TIMEOUT_SIGNAL SIGUSR2
38 #define SLEEP_TIME 30                 /* examine things every 30 seconds */
39
40 /* Forward referenced functions */
41 static void *watchdog_thread(void *arg);
42
43 /* Static globals */
44 static pthread_mutex_t mutex;
45 static pthread_cond_t  timer;
46 static int quit;
47
48
49 /*
50  * Timeout signal comes here
51  */
52 static void timeout_handler(int sig)
53 {
54    return;                            /* thus interrupting the function */
55 }
56
57
58 /*   
59  * Initialize watchdog thread
60  *
61  *  Returns: 0 on success
62  *           errno on failure
63  */
64 int init_watchdog(void)
65 {
66    int stat;
67    pthread_t wdid;
68    struct sigaction sigtimer;
69                         
70    sigtimer.sa_flags = 0;
71    sigtimer.sa_handler = timeout_handler;
72    sigfillset(&sigtimer.sa_mask);
73    sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
74    watchdog_time = time(NULL);
75    if ((stat = pthread_mutex_init(&mutex, NULL)) != 0) {
76       return stat;
77    }
78    if ((stat = pthread_cond_init(&timer, NULL)) != 0) {
79       pthread_mutex_destroy(&mutex);
80       return stat;
81    }
82    quit = FALSE;
83    if ((stat = pthread_create(&wdid, NULL, watchdog_thread, (void *)NULL)) != 0) {
84       pthread_mutex_destroy(&mutex);
85       pthread_cond_destroy(&timer);
86       return stat;
87    }
88    return 0;
89 }
90
91 /*
92  * Terminate the watchdog thread
93  *
94  * Returns: 0 on success
95  *          errno on failure
96  */
97 int term_watchdog(void)
98 {
99    int stat;
100
101    if ((stat = pthread_mutex_lock(&mutex)) != 0) {
102       return stat;
103    }
104    quit = TRUE;
105
106    if ((stat = pthread_cond_signal(&timer)) != 0) {
107       pthread_mutex_unlock(&mutex);
108       return stat;
109    }
110    if ((stat = pthread_mutex_unlock(&mutex)) != 0) {
111       return stat;
112    }
113    return 0;
114 }
115
116
117 /* 
118  * This is the actual watchdog thread.
119  */
120 static void *watchdog_thread(void *arg)
121 {
122    struct timespec timeout;
123    int stat;
124    JCR *jcr;
125    BSOCK *fd;
126
127    Dmsg0(200, "Start watchdog thread\n");
128    pthread_detach(pthread_self());
129
130    if ((stat = pthread_mutex_lock(&mutex)) != 0) {
131       return NULL;
132    }
133
134    for ( ;!quit; ) {
135       struct timeval tv;
136       struct timezone tz;
137
138       Dmsg0(200, "Top of for loop\n");
139
140       watchdog_time = time(NULL);     /* update timer */
141
142       /* Walk through all JCRs checking if any one is 
143        * blocked for more than specified max time.
144        */
145       lock_jcr_chain();
146       for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
147          free_locked_jcr(jcr);
148          if (jcr->JobId == 0) {
149             continue;
150          }
151          fd = jcr->store_bsock;
152          if (fd && fd->timer_start && (watchdog_time - fd->timer_start) > fd->timeout) {
153             fd->timed_out = TRUE;
154             Jmsg(jcr, M_ERROR, 0, "Watchdog sending kill to thread stalled reading Storage daemon.\n");
155             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
156          }
157          fd = jcr->file_bsock;
158          if (fd && fd->timer_start && (watchdog_time - fd->timer_start) > fd->timeout) {
159             fd->timed_out = TRUE;
160             Jmsg(jcr, M_ERROR, 0, "Watchdog sending kill to thread stalled reading File daemon.\n");
161             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
162          }
163          fd = jcr->dir_bsock;
164          if (fd && fd->timer_start && (watchdog_time - fd->timer_start) > fd->timeout) {
165             fd->timed_out = TRUE;
166             Jmsg(jcr, M_ERROR, 0, "Watchdog sending kill to thread stalled reading Director.\n");
167             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
168          }
169
170       }
171       unlock_jcr_chain();
172
173       gettimeofday(&tv, &tz);
174       timeout.tv_nsec = 0;
175       timeout.tv_sec = tv.tv_sec + SLEEP_TIME;
176
177       Dmsg1(200, "pthread_cond_timedwait sec=%d\n", timeout.tv_sec);
178 #ifdef xxxxxxxxxxxxxxx_was_HAVE_CYGWIN
179       /* CYGWIN dies with a page fault the second
180        * time that pthread_cond_timedwait() is called
181        * so fake it out.
182        */
183       sleep(SLEEP_TIME); 
184 #else
185       stat = pthread_cond_timedwait(&timer, &mutex, &timeout);
186       Dmsg1(200, "pthread_cond_timedwait stat=%d\n", stat);
187 #endif
188       
189    } /* end of big for loop */
190
191    Dmsg0(200, "End watchdog\n");
192    return NULL;
193 }