vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / kernel_daemon.cpp
blobfbc7a2cae3d124ec50d99457054f00e3328da05c
1 /*
2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <kernel_daemon.h>
9 #include <new>
10 #include <stdlib.h>
12 #include <KernelExport.h>
14 #include <elf.h>
15 #include <lock.h>
16 #include <util/AutoLock.h>
17 #include <util/DoublyLinkedList.h>
20 // The use of snooze() in the kernel_daemon() function is very inaccurate, of
21 // course - the time the daemons need to execute add up in each iteration.
22 // But since the kernel daemon is documented to be very inaccurate, this
23 // actually might be okay (and that's why it's implemented this way now :-).
24 // BeOS R5 seems to do it in the same way, anyway.
26 struct daemon : DoublyLinkedListLinkImpl<struct daemon> {
27 daemon_hook function;
28 void* arg;
29 int32 frequency;
30 int32 offset;
31 bool executing;
35 typedef DoublyLinkedList<struct daemon> DaemonList;
38 class KernelDaemon {
39 public:
40 status_t Init(const char* name);
42 status_t Register(daemon_hook function, void* arg,
43 int frequency);
44 status_t Unregister(daemon_hook function, void* arg);
46 void Dump();
48 private:
49 static status_t _DaemonThreadEntry(void* data);
50 struct daemon* _NextDaemon(struct daemon& marker);
51 status_t _DaemonThread();
52 bool _IsDaemon() const;
54 private:
55 recursive_lock fLock;
56 DaemonList fDaemons;
57 thread_id fThread;
58 ConditionVariable fUnregisterCondition;
59 int32 fUnregisterWaiters;
63 static KernelDaemon sKernelDaemon;
64 static KernelDaemon sResourceResizer;
67 status_t
68 KernelDaemon::Init(const char* name)
70 recursive_lock_init(&fLock, name);
72 fThread = spawn_kernel_thread(&_DaemonThreadEntry, name, B_LOW_PRIORITY,
73 this);
74 if (fThread < 0)
75 return fThread;
77 resume_thread(fThread);
78 fUnregisterCondition.Init(this, name);
80 return B_OK;
84 status_t
85 KernelDaemon::Register(daemon_hook function, void* arg, int frequency)
87 if (function == NULL || frequency < 1)
88 return B_BAD_VALUE;
90 struct ::daemon* daemon = new(std::nothrow) (struct ::daemon);
91 if (daemon == NULL)
92 return B_NO_MEMORY;
94 daemon->function = function;
95 daemon->arg = arg;
96 daemon->frequency = frequency;
97 daemon->executing = false;
99 RecursiveLocker _(fLock);
101 if (frequency > 1) {
102 // we try to balance the work-load for each daemon run
103 // (beware, it's a very simple algorithm, yet effective)
105 DaemonList::Iterator iterator = fDaemons.GetIterator();
106 int32 num = 0;
108 while (iterator.HasNext()) {
109 if (iterator.Next()->frequency == frequency)
110 num++;
113 daemon->offset = num % frequency;
114 } else
115 daemon->offset = 0;
117 fDaemons.Add(daemon);
118 return B_OK;
122 status_t
123 KernelDaemon::Unregister(daemon_hook function, void* arg)
125 RecursiveLocker locker(fLock);
127 DaemonList::Iterator iterator = fDaemons.GetIterator();
129 // search for the daemon and remove it from the list
130 while (iterator.HasNext()) {
131 struct daemon* daemon = iterator.Next();
133 if (daemon->function == function && daemon->arg == arg) {
134 // found it!
135 if (!_IsDaemon()) {
136 // wait if it's busy
137 while (daemon->executing) {
138 fUnregisterWaiters++;
140 ConditionVariableEntry entry;
141 fUnregisterCondition.Add(&entry);
143 locker.Unlock();
145 entry.Wait();
147 locker.Lock();
151 iterator.Remove();
152 delete daemon;
153 return B_OK;
157 return B_ENTRY_NOT_FOUND;
161 void
162 KernelDaemon::Dump()
164 DaemonList::Iterator iterator = fDaemons.GetIterator();
166 while (iterator.HasNext()) {
167 struct daemon* daemon = iterator.Next();
168 const char* imageName;
169 const char* symbol;
170 bool exactMatch;
172 status_t status = elf_debug_lookup_symbol_address(
173 (addr_t)daemon->function, NULL, &symbol, &imageName, &exactMatch);
174 if (status == B_OK && exactMatch) {
175 if (strchr(imageName, '/') != NULL)
176 imageName = strrchr(imageName, '/') + 1;
178 kprintf("\t%s:%s (%p)", imageName, symbol, daemon->function);
179 } else
180 kprintf("\t%p", daemon->function);
182 kprintf(", arg %p%s\n", daemon->arg,
183 daemon->executing ? " (running) " : "");
188 /*static*/ status_t
189 KernelDaemon::_DaemonThreadEntry(void* data)
191 return ((KernelDaemon*)data)->_DaemonThread();
195 struct daemon*
196 KernelDaemon::_NextDaemon(struct daemon& marker)
198 struct daemon* daemon;
200 if (marker.arg == NULL) {
201 // The marker is not part of the list yet, just return the first entry
202 daemon = fDaemons.Head();
203 } else {
204 daemon = fDaemons.GetNext(&marker);
205 fDaemons.Remove(&marker);
208 marker.arg = daemon;
210 if (daemon != NULL)
211 fDaemons.InsertAfter(daemon, &marker);
213 return daemon;
217 status_t
218 KernelDaemon::_DaemonThread()
220 struct daemon marker;
221 int32 iteration = 0;
223 marker.arg = NULL;
225 while (true) {
226 RecursiveLocker locker(fLock);
228 // iterate through the list and execute each daemon if needed
229 while (struct daemon* daemon = _NextDaemon(marker)) {
230 daemon->executing = true;
231 locker.Unlock();
233 if (((iteration + daemon->offset) % daemon->frequency) == 0)
234 daemon->function(daemon->arg, iteration);
236 locker.Lock();
237 daemon->executing = false;
240 if (fUnregisterWaiters != 0) {
241 fUnregisterCondition.NotifyAll();
242 fUnregisterWaiters = 0;
245 locker.Unlock();
247 iteration++;
248 snooze(100000); // 0.1 seconds
251 return B_OK;
255 bool
256 KernelDaemon::_IsDaemon() const
258 return find_thread(NULL) == fThread;
262 // #pragma mark -
265 static int
266 dump_daemons(int argc, char** argv)
268 kprintf("kernel daemons:\n");
269 sKernelDaemon.Dump();
271 kprintf("\nresource resizers:\n");
272 sResourceResizer.Dump();
274 return 0;
278 // #pragma mark -
281 extern "C" status_t
282 register_kernel_daemon(daemon_hook function, void* arg, int frequency)
284 return sKernelDaemon.Register(function, arg, frequency);
288 extern "C" status_t
289 unregister_kernel_daemon(daemon_hook function, void* arg)
291 return sKernelDaemon.Unregister(function, arg);
295 extern "C" status_t
296 register_resource_resizer(daemon_hook function, void* arg, int frequency)
298 return sResourceResizer.Register(function, arg, frequency);
302 extern "C" status_t
303 unregister_resource_resizer(daemon_hook function, void* arg)
305 return sResourceResizer.Unregister(function, arg);
309 // #pragma mark -
312 extern "C" status_t
313 kernel_daemon_init(void)
315 new(&sKernelDaemon) KernelDaemon;
316 if (sKernelDaemon.Init("kernel daemon") != B_OK)
317 panic("kernel_daemon_init(): failed to init kernel daemon");
319 new(&sResourceResizer) KernelDaemon;
320 if (sResourceResizer.Init("resource resizer") != B_OK)
321 panic("kernel_daemon_init(): failed to init resource resizer");
323 add_debugger_command("daemons", dump_daemons,
324 "Shows registered kernel daemons.");
325 return B_OK;