xref: /openbsd-src/sys/kern/kern_sensors.c (revision a3fa1869fb5535bc29eac7d2884480572f957a2c)
1 /* $OpenBSD: kern_sensors.c,v 1.5 2005/11/21 13:47:52 dlg Exp $ */
2 
3 /*
4  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/malloc.h>
23 #include <sys/kthread.h>
24 #include <sys/queue.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 
28 #include <sys/sensors.h>
29 
30 int _sensors_count = 0;
31 struct sensors_head _sensors_list = SLIST_HEAD_INITIALIZER(&_sensors_list);
32 
33 struct sensor_task {
34 	void				*arg;
35 	void				(*func)(void *);
36 
37 	int				period;
38 	time_t				nextrun;
39 	volatile int			running;
40 	TAILQ_ENTRY(sensor_task)	entry;
41 };
42 
43 void	sensor_task_create(void *);
44 void	sensor_task_thread(void *);
45 void	sensor_task_schedule(struct sensor_task *);
46 
47 TAILQ_HEAD(, sensor_task) tasklist = TAILQ_HEAD_INITIALIZER(tasklist);
48 
49 int
50 sensor_task_register(void *arg, void (*func)(void *), int period)
51 {
52 	struct sensor_task	*st;
53 
54 	st = malloc(sizeof(struct sensor_task), M_DEVBUF, M_NOWAIT);
55 	if (st == NULL)
56 		return (1);
57 
58 	st->arg = arg;
59 	st->func = func;
60 	st->period = period;
61 
62 	st->running = 1;
63 
64 	if (TAILQ_EMPTY(&tasklist))
65 		kthread_create_deferred(sensor_task_create, NULL);
66 
67 	sensor_task_schedule(st);
68 	wakeup(&tasklist);
69 
70 	return (0);
71 }
72 
73 void
74 sensor_task_unregister(void *arg)
75 {
76 	struct sensor_task	*st;
77 
78 	TAILQ_FOREACH(st, &tasklist, entry) {
79 		if (st->arg == arg)
80 			st->running = 0;
81 	}
82 }
83 
84 void
85 sensor_task_create(void *arg)
86 {
87 	if (kthread_create(sensor_task_thread, NULL, NULL, "sensors") != 0)
88 		panic("sensors kthread");
89 }
90 
91 void
92 sensor_task_thread(void *arg)
93 {
94 	struct sensor_task	*st, *nst;
95 	time_t			now;
96 
97 	while (!TAILQ_EMPTY(&tasklist)) {
98 		while ((nst = TAILQ_FIRST(&tasklist))->nextrun >
99 		    (now = time_uptime))
100 			tsleep(&tasklist, PWAIT, "timeout",
101 			    (nst->nextrun - now) * hz);
102 
103 		while ((st = nst) != NULL) {
104 			nst = TAILQ_NEXT(st, entry);
105 
106 			if (st->nextrun > now)
107 				break;
108 
109 			/* take it out while we work on it */
110 			TAILQ_REMOVE(&tasklist, st, entry);
111 
112 			if (!st->running) {
113 				free(st, M_DEVBUF);
114 				continue;
115 			}
116 
117 			/* run the task */
118 			st->func(st->arg);
119 			/* stick it back in the tasklist */
120 			sensor_task_schedule(st);
121 		}
122 	}
123 
124 	kthread_exit(0);
125 }
126 
127 void
128 sensor_task_schedule(struct sensor_task *st)
129 {
130 	struct sensor_task 	*cst;
131 
132 	st->nextrun = time_uptime + st->period;
133 
134 	TAILQ_FOREACH(cst, &tasklist, entry) {
135 		if (cst->nextrun > st->nextrun) {
136 			TAILQ_INSERT_BEFORE(cst, st, entry);
137 			return;
138 		}
139 	}
140 
141 	/* must be an empty list, or at the end of the list */
142 	TAILQ_INSERT_TAIL(&tasklist, st, entry);
143 }
144 
145