2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include <kernel_daemon.h>
12 #include <KernelExport.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
> {
35 typedef DoublyLinkedList
<struct daemon
> DaemonList
;
40 status_t
Init(const char* name
);
42 status_t
Register(daemon_hook function
, void* arg
,
44 status_t
Unregister(daemon_hook function
, void* arg
);
49 static status_t
_DaemonThreadEntry(void* data
);
50 struct daemon
* _NextDaemon(struct daemon
& marker
);
51 status_t
_DaemonThread();
52 bool _IsDaemon() const;
58 ConditionVariable fUnregisterCondition
;
59 int32 fUnregisterWaiters
;
63 static KernelDaemon sKernelDaemon
;
64 static KernelDaemon sResourceResizer
;
68 KernelDaemon::Init(const char* name
)
70 recursive_lock_init(&fLock
, name
);
72 fThread
= spawn_kernel_thread(&_DaemonThreadEntry
, name
, B_LOW_PRIORITY
,
77 resume_thread(fThread
);
78 fUnregisterCondition
.Init(this, name
);
85 KernelDaemon::Register(daemon_hook function
, void* arg
, int frequency
)
87 if (function
== NULL
|| frequency
< 1)
90 struct ::daemon
* daemon
= new(std::nothrow
) (struct ::daemon
);
94 daemon
->function
= function
;
96 daemon
->frequency
= frequency
;
97 daemon
->executing
= false;
99 RecursiveLocker
_(fLock
);
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();
108 while (iterator
.HasNext()) {
109 if (iterator
.Next()->frequency
== frequency
)
113 daemon
->offset
= num
% frequency
;
117 fDaemons
.Add(daemon
);
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
) {
137 while (daemon
->executing
) {
138 fUnregisterWaiters
++;
140 ConditionVariableEntry entry
;
141 fUnregisterCondition
.Add(&entry
);
157 return B_ENTRY_NOT_FOUND
;
164 DaemonList::Iterator iterator
= fDaemons
.GetIterator();
166 while (iterator
.HasNext()) {
167 struct daemon
* daemon
= iterator
.Next();
168 const char* imageName
;
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
);
180 kprintf("\t%p", daemon
->function
);
182 kprintf(", arg %p%s\n", daemon
->arg
,
183 daemon
->executing
? " (running) " : "");
189 KernelDaemon::_DaemonThreadEntry(void* data
)
191 return ((KernelDaemon
*)data
)->_DaemonThread();
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();
204 daemon
= fDaemons
.GetNext(&marker
);
205 fDaemons
.Remove(&marker
);
211 fDaemons
.InsertAfter(daemon
, &marker
);
218 KernelDaemon::_DaemonThread()
220 struct daemon marker
;
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;
233 if (((iteration
+ daemon
->offset
) % daemon
->frequency
) == 0)
234 daemon
->function(daemon
->arg
, iteration
);
237 daemon
->executing
= false;
240 if (fUnregisterWaiters
!= 0) {
241 fUnregisterCondition
.NotifyAll();
242 fUnregisterWaiters
= 0;
248 snooze(100000); // 0.1 seconds
256 KernelDaemon::_IsDaemon() const
258 return find_thread(NULL
) == fThread
;
266 dump_daemons(int argc
, char** argv
)
268 kprintf("kernel daemons:\n");
269 sKernelDaemon
.Dump();
271 kprintf("\nresource resizers:\n");
272 sResourceResizer
.Dump();
282 register_kernel_daemon(daemon_hook function
, void* arg
, int frequency
)
284 return sKernelDaemon
.Register(function
, arg
, frequency
);
289 unregister_kernel_daemon(daemon_hook function
, void* arg
)
291 return sKernelDaemon
.Unregister(function
, arg
);
296 register_resource_resizer(daemon_hook function
, void* arg
, int frequency
)
298 return sResourceResizer
.Register(function
, arg
, frequency
);
303 unregister_resource_resizer(daemon_hook function
, void* arg
)
305 return sResourceResizer
.Unregister(function
, arg
);
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.");