9 /* #include <watchdog.h>
11 /* WATCHDOG *watchdog_create(timeout, action, context)
13 /* void (*action)(WATCHDOG *watchdog, char *context);
16 /* void watchdog_start(watchdog)
17 /* WATCHDOG *watchdog;
19 /* void watchdog_stop(watchdog)
20 /* WATCHDOG *watchdog;
22 /* void watchdog_destroy(watchdog)
23 /* WATCHDOG *watchdog;
25 /* void watchdog_pat()
27 /* This module implements watchdog timers that are based on ugly
28 /* UNIX alarm timers. The module is designed to survive systems
29 /* with clocks that jump occasionally.
31 /* Watchdog timers can be stacked. Only one watchdog timer can be
32 /* active at a time. Only the last created watchdog timer can be
33 /* manipulated. Watchdog timers must be destroyed in reverse order
36 /* watchdog_create() suspends the current watchdog timer, if any,
37 /* and instantiates a new watchdog timer.
39 /* watchdog_start() starts or restarts the watchdog timer.
41 /* watchdog_stop() stops the watchdog timer.
43 /* watchdog_destroy() stops the watchdog timer, and resumes the
44 /* watchdog timer instance that was suspended by watchdog_create().
46 /* watchdog_pat() pats the watchdog, so it stays quiet.
50 /* The watchdog time limit. When the watchdog timer runs, the
51 /* process must invoke watchdog_start(), watchdog_stop() or
52 /* watchdog_destroy() before the time limit is reached.
54 /* A null pointer, or pointer to function that is called when the
55 /* watchdog alarm goes off. The default action is to terminate
56 /* the process with a fatal error.
58 /* Application context that is passed to the action routine.
60 /* Must be a pointer to the most recently created watchdog instance.
61 /* This argument is checked upon each call.
63 /* UNIX alarm timers are not stackable, so there can be at most one
64 /* watchdog instance active at any given time.
66 /* msg(3) diagnostics interface
68 /* Fatal errors: memory allocation problem, system call failure.
69 /* Panics: interface violations.
73 /* The Secure Mailer license must be distributed with this software.
76 /* IBM T.J. Watson Research
78 /* Yorktown Heights, NY 10598, USA
86 #include <posix_signals.h>
88 /* Utility library. */
92 #include <killme_after.h>
95 /* Application-specific. */
98 * Rather than having one timer that goes off when it is too late, we break
99 * up the time limit into smaller intervals so that we can deal with clocks
100 * that jump occasionally.
102 #define WATCHDOG_STEPS 3
105 * UNIX alarms are not stackable, but we can save and restore state, so that
106 * watchdogs can at least be nested, sort of.
109 unsigned timeout
; /* our time resolution */
110 WATCHDOG_FN action
; /* application routine */
111 char *context
; /* application context */
112 int trip_run
; /* number of successive timeouts */
113 WATCHDOG
*saved_watchdog
; /* saved state */
114 struct sigaction saved_action
; /* saved state */
115 unsigned saved_time
; /* saved state */
119 * However, only one watchdog instance can be current, and the caller has to
120 * restore state before a prior watchdog instance can be manipulated.
122 static WATCHDOG
*watchdog_curr
;
124 /* watchdog_event - handle timeout event */
126 static void watchdog_event(int unused_sig
)
128 const char *myname
= "watchdog_event";
132 * This routine runs as a signal handler. We should not do anything that
133 * could involve memory allocation/deallocation, but exiting without
134 * proper explanation would be unacceptable. For this reason, msg(3) was
135 * made safe for usage by signal handlers that terminate the process.
137 if ((wp
= watchdog_curr
) == 0)
138 msg_panic("%s: no instance", myname
);
140 msg_info("%s: %p %d", myname
, (void *) wp
, wp
->trip_run
);
141 if (++(wp
->trip_run
) < WATCHDOG_STEPS
) {
145 wp
->action(wp
, wp
->context
);
151 msg_fatal("watchdog timeout");
156 /* watchdog_create - create watchdog instance */
158 WATCHDOG
*watchdog_create(unsigned timeout
, WATCHDOG_FN action
, char *context
)
160 const char *myname
= "watchdog_create";
161 struct sigaction sig_action
;
164 wp
= (WATCHDOG
*) mymalloc(sizeof(*wp
));
165 if ((wp
->timeout
= timeout
/ WATCHDOG_STEPS
) == 0)
166 msg_panic("%s: timeout %d is too small", myname
, timeout
);
168 wp
->context
= context
;
169 wp
->saved_watchdog
= watchdog_curr
;
170 wp
->saved_time
= alarm(0);
171 sigemptyset(&sig_action
.sa_mask
);
173 sig_action
.sa_flags
= SA_RESTART
;
175 sig_action
.sa_flags
= 0;
177 sig_action
.sa_handler
= watchdog_event
;
178 if (sigaction(SIGALRM
, &sig_action
, &wp
->saved_action
) < 0)
179 msg_fatal("%s: sigaction(SIGALRM): %m", myname
);
181 msg_info("%s: %p %d", myname
, (void *) wp
, timeout
);
182 return (watchdog_curr
= wp
);
185 /* watchdog_destroy - destroy watchdog instance, restore state */
187 void watchdog_destroy(WATCHDOG
*wp
)
189 const char *myname
= "watchdog_destroy";
192 watchdog_curr
= wp
->saved_watchdog
;
193 if (sigaction(SIGALRM
, &wp
->saved_action
, (struct sigaction
*) 0) < 0)
194 msg_fatal("%s: sigaction(SIGALRM): %m", myname
);
196 alarm(wp
->saved_time
);
199 msg_info("%s: %p", myname
, (void *) wp
);
202 /* watchdog_start - enable watchdog timer */
204 void watchdog_start(WATCHDOG
*wp
)
206 const char *myname
= "watchdog_start";
208 if (wp
!= watchdog_curr
)
209 msg_panic("%s: wrong watchdog instance", myname
);
213 msg_info("%s: %p", myname
, (void *) wp
);
216 /* watchdog_stop - disable watchdog timer */
218 void watchdog_stop(WATCHDOG
*wp
)
220 const char *myname
= "watchdog_stop";
222 if (wp
!= watchdog_curr
)
223 msg_panic("%s: wrong watchdog instance", myname
);
226 msg_info("%s: %p", myname
, (void *) wp
);
229 /* watchdog_pat - pat the dog so it stays quiet */
231 void watchdog_pat(void)
233 const char *myname
= "watchdog_pat";
236 watchdog_curr
->trip_run
= 0;
238 msg_info("%s: %p", myname
, (void *) watchdog_curr
);
245 int main(int unused_argc
, char **unused_argv
)
251 wp
= watchdog_create(10, (WATCHDOG_FN
) 0, (char *) 0);
255 } while (VSTREAM_GETCHAR() != VSTREAM_EOF
);
256 watchdog_destroy(wp
);