Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * watchdog framework
3
 */
4
#include	"u.h"
5
#include	"../port/lib.h"
6
#include	"mem.h"
7
#include	"dat.h"
8
#include	"fns.h"
9
#include	"io.h"
10
#include	"../port/error.h"
11
 
12
enum {
13
	Qdir,
14
	Qwdctl,
15
};
16
 
17
/*
18
 * these are exposed so that delay() and the like can disable the watchdog
19
 * before busy looping for a long time.
20
 */
21
Watchdog*watchdog;
22
int	watchdogon;
23
 
24
static Watchdog *wd;
25
static int wdautopet;
26
static int wdclock0called;
27
static Ref refs;
28
static Dirtab wddir[] = {
29
	".",		{ Qdir, 0, QTDIR },	0,		0555,
30
	"wdctl",	{ Qwdctl, 0 },		0,		0664,
31
};
32
 
33
 
34
void
35
addwatchdog(Watchdog *wdog)
36
{
37
	if(wd){
38
		print("addwatchdog: watchdog already installed\n");
39
		return;
40
	}
41
	wd = watchdog = wdog;
42
	if(wd)
43
		wd->disable();
44
}
45
 
46
static int
47
wdallowed(void)
48
{
49
	return getconf("*nowatchdog") == nil;
50
}
51
 
52
static void
53
wdshutdown(void)
54
{
55
	if (wd) {
56
		wd->disable();
57
		watchdogon = 0;
58
	}
59
}
60
 
61
/* called from clock interrupt, so restart needs ilock internally */
62
static void
63
wdpet(void)
64
{
65
	/* watchdog could be paused; if so, don't restart */
66
	if (wdautopet && watchdogon)
67
		wd->restart();
68
}
69
 
70
/*
71
 * reassure the watchdog from the clock interrupt
72
 * until the user takes control of it.
73
 */
74
static void
75
wdautostart(void)
76
{
77
	if (wdautopet || !wd || !wdallowed())
78
		return;
79
	if (waserror()) {
80
		print("watchdog: automatic enable failed\n");
81
		return;
82
	}
83
	wd->enable();
84
	poperror();
85
 
86
	wdautopet = watchdogon = 1;
87
	if (!wdclock0called) {
88
		addclock0link(wdpet, 200);
89
		wdclock0called = 1;
90
	}
91
}
92
 
93
/*
94
 * disable strokes from the clock interrupt.
95
 * have to disable the watchdog to mark it `not in use'.
96
 */
97
static void
98
wdautostop(void)
99
{
100
	if (!wdautopet)
101
		return;
102
	wdautopet = 0;
103
	wdshutdown();
104
}
105
 
106
/*
107
 * user processes exist and up is non-nil when the
108
 * device init routines are called.
109
 */
110
static void
111
wdinit(void)
112
{
113
	wdautostart();
114
}
115
 
116
static Chan*
117
wdattach(char *spec)
118
{
119
	return devattach('w', spec);
120
}
121
 
122
static Walkqid*
123
wdwalk(Chan *c, Chan *nc, char **name, int nname)
124
{
125
	return devwalk(c, nc, name, nname, wddir, nelem(wddir), devgen);
126
}
127
 
128
static int
129
wdstat(Chan *c, uchar *dp, int n)
130
{
131
	return devstat(c, dp, n, wddir, nelem(wddir), devgen);
132
}
133
 
134
static Chan*
135
wdopen(Chan* c, int omode)
136
{
137
	wdautostop();
138
	c = devopen(c, omode, wddir, nelem(wddir), devgen);
139
	if (c->qid.path == Qwdctl)
140
		incref(&refs);
141
	return c;
142
}
143
 
144
static void
145
wdclose(Chan *c)
146
{
147
	if(c->qid.path == Qwdctl && c->flag&COPEN && decref(&refs) <= 0)
148
		wdshutdown();
149
}
150
 
151
static long
152
wdread(Chan* c, void* a, long n, vlong off)
153
{
154
	ulong offset = off;
155
	char *p;
156
 
157
	switch((ulong)c->qid.path){
158
	case Qdir:
159
		return devdirread(c, a, n, wddir, nelem(wddir), devgen);
160
 
161
	case Qwdctl:
162
		if(wd == nil || wd->stat == nil)
163
			return 0;
164
 
165
		p = malloc(READSTR);
166
		if(p == nil)
167
			error(Enomem);
168
		if(waserror()){
169
			free(p);
170
			nexterror();
171
		}
172
 
173
		wd->stat(p, p + READSTR);
174
		n = readstr(offset, a, n, p);
175
		free(p);
176
		poperror();
177
		return n;
178
 
179
	default:
180
		error(Egreg);
181
		break;
182
	}
183
	return 0;
184
}
185
 
186
static long
187
wdwrite(Chan* c, void* a, long n, vlong off)
188
{
189
	ulong offset = off;
190
	char *p;
191
 
192
	switch((ulong)c->qid.path){
193
	case Qdir:
194
		error(Eperm);
195
 
196
	case Qwdctl:
197
		if(wd == nil)
198
			return n;
199
 
200
		if(offset || n >= READSTR)
201
			error(Ebadarg);
202
 
203
		if((p = strchr(a, '\n')) != nil)
204
			*p = 0;
205
 
206
		if(strncmp(a, "enable", n) == 0) {
207
			if (waserror()) {
208
				print("watchdog: enable failed\n");
209
				nexterror();
210
			}
211
			wd->enable();
212
			poperror();
213
			watchdogon = 1;
214
		} else if(strncmp(a, "disable", n) == 0)
215
			wdshutdown();
216
		else if(strncmp(a, "restart", n) == 0)
217
			wd->restart();
218
		else
219
			error(Ebadarg);
220
		return n;
221
 
222
	default:
223
		error(Egreg);
224
		break;
225
	}
226
 
227
	return 0;
228
}
229
 
230
Dev wddevtab = {
231
	'w',
232
	"watchdog",
233
 
234
	devreset,
235
	wdinit,
236
	wdshutdown,
237
	wdattach,
238
	wdwalk,
239
	wdstat,
240
	wdopen,
241
	devcreate,
242
	wdclose,
243
	wdread,
244
	devbread,
245
	wdwrite,
246
	devbwrite,
247
	devremove,
248
	devwstat,
249
	devpower,
250
};