xref: /openbsd-src/sys/kern/kern_watchdog.c (revision 0d280c5f69f6ef21f5dca2b37e738de752505c51)
1*0d280c5fSjsg /*      $OpenBSD: kern_watchdog.c,v 1.16 2022/08/14 01:58:27 jsg Exp $        */
2f206784aSmarkus 
3f206784aSmarkus /*
4f206784aSmarkus  * Copyright (c) 2003 Markus Friedl.  All rights reserved.
5f206784aSmarkus  *
6f206784aSmarkus  * Redistribution and use in source and binary forms, with or without
7f206784aSmarkus  * modification, are permitted provided that the following conditions
8f206784aSmarkus  * are met:
9f206784aSmarkus  * 1. Redistributions of source code must retain the above copyright
10f206784aSmarkus  *    notice, this list of conditions and the following disclaimer.
11f206784aSmarkus  * 2. Redistributions in binary form must reproduce the above copyright
12f206784aSmarkus  *    notice, this list of conditions and the following disclaimer in the
13f206784aSmarkus  *    documentation and/or other materials provided with the distribution.
14f206784aSmarkus  *
15f206784aSmarkus  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16f206784aSmarkus  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17f206784aSmarkus  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18f206784aSmarkus  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19f206784aSmarkus  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20f206784aSmarkus  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21f206784aSmarkus  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22f206784aSmarkus  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23f206784aSmarkus  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24f206784aSmarkus  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25f206784aSmarkus  */
26f206784aSmarkus #include <sys/param.h>
27f206784aSmarkus #include <sys/systm.h>
287f58a11fSjsg #include <sys/timeout.h>
29f206784aSmarkus #include <sys/sysctl.h>
30f206784aSmarkus 
31f206784aSmarkus void	wdog_tickle(void *arg);
32f206784aSmarkus int	(*wdog_ctl_cb)(void *, int) = NULL;
33f206784aSmarkus void	*wdog_ctl_cb_arg = NULL;
34f206784aSmarkus int	wdog_period = 0;
35f206784aSmarkus int	wdog_auto = 1;
36f206784aSmarkus struct	timeout wdog_timeout;
37f206784aSmarkus 
38f206784aSmarkus void
wdog_register(int (* cb)(void *,int),void * cb_arg)392bc62decSderaadt wdog_register(int (*cb)(void *, int), void *cb_arg)
40f206784aSmarkus {
41f206784aSmarkus 	if (wdog_ctl_cb != NULL)
42f206784aSmarkus 		return;
43883c1f79Sdlg 
44f206784aSmarkus 	wdog_ctl_cb = cb;
45f206784aSmarkus 	wdog_ctl_cb_arg = cb_arg;
46883c1f79Sdlg 	timeout_set(&wdog_timeout, wdog_tickle, NULL);
47f206784aSmarkus }
48f206784aSmarkus 
49f206784aSmarkus void
wdog_tickle(void * arg)50f206784aSmarkus wdog_tickle(void *arg)
51f206784aSmarkus {
52f206784aSmarkus 	if (wdog_ctl_cb == NULL)
53f206784aSmarkus 		return;
54f206784aSmarkus 	(void) (*wdog_ctl_cb)(wdog_ctl_cb_arg, wdog_period);
55a71d95e2Skn 	timeout_add_msec(&wdog_timeout, wdog_period * 1000 / 2);
56f206784aSmarkus }
57f206784aSmarkus 
58f206784aSmarkus void
wdog_shutdown(void * arg)593b06f262Smikeb wdog_shutdown(void *arg)
60f206784aSmarkus {
613b06f262Smikeb 	if (wdog_ctl_cb == NULL || wdog_ctl_cb_arg != arg)
62f206784aSmarkus 		return;
63f206784aSmarkus 	timeout_del(&wdog_timeout);
64f206784aSmarkus 	(void) (*wdog_ctl_cb)(wdog_ctl_cb_arg, 0);
65aebf3f9bSdlg 	wdog_ctl_cb = NULL;
66aebf3f9bSdlg 	wdog_period = 0;
67aebf3f9bSdlg 	wdog_auto = 1;
68f206784aSmarkus }
69f206784aSmarkus 
70f206784aSmarkus int
sysctl_wdog(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)71158fb4f9Sjsg sysctl_wdog(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
72158fb4f9Sjsg     size_t newlen)
73f206784aSmarkus {
74f206784aSmarkus 	int error, period;
75f206784aSmarkus 
76f206784aSmarkus 	if (wdog_ctl_cb == NULL)
77f206784aSmarkus 		return (EOPNOTSUPP);
78f206784aSmarkus 
79f206784aSmarkus 	switch (name[0]) {
80f206784aSmarkus 	case KERN_WATCHDOG_PERIOD:
81f206784aSmarkus 		period = wdog_period;
824dffe6e9Sgnezdo 		error = sysctl_int_bounded(oldp, oldlenp, newp, newlen,
834dffe6e9Sgnezdo 		    &period, 0, INT_MAX);
84f206784aSmarkus 		if (error)
85f206784aSmarkus 			return (error);
86f206784aSmarkus 		if (newp) {
87f206784aSmarkus 			timeout_del(&wdog_timeout);
88f206784aSmarkus 			wdog_period = (*wdog_ctl_cb)(wdog_ctl_cb_arg, period);
89f206784aSmarkus 		}
90f206784aSmarkus 		break;
91f206784aSmarkus 	case KERN_WATCHDOG_AUTO:
924dffe6e9Sgnezdo 		error = sysctl_int_bounded(oldp, oldlenp, newp, newlen,
934dffe6e9Sgnezdo 		    &wdog_auto, 0, 1);
94f206784aSmarkus 		if (error)
95f206784aSmarkus 			return (error);
96f206784aSmarkus 		break;
97f206784aSmarkus 	default:
98f206784aSmarkus 		return (EINVAL);
99f206784aSmarkus 	}
100f206784aSmarkus 
101f206784aSmarkus 	if (wdog_auto && wdog_period > 0) {
102f206784aSmarkus 		(void) (*wdog_ctl_cb)(wdog_ctl_cb_arg, wdog_period);
103a71d95e2Skn 		timeout_add_msec(&wdog_timeout, wdog_period * 1000 / 2);
10448c577acSmk 	} else
10548c577acSmk 		timeout_del(&wdog_timeout);
10648c577acSmk 
107f206784aSmarkus 	return (error);
108f206784aSmarkus }
109