xref: /haiku/src/system/kernel/kernel_daemon.cpp (revision 079eccf655ba39812b421ae1b87a727d41b50354)
1 /*
2  * Copyright 2003-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <kernel_daemon.h>
8 
9 #include <new>
10 #include <signal.h>
11 #include <stdlib.h>
12 
13 #include <KernelExport.h>
14 
15 #include <lock.h>
16 #include <util/AutoLock.h>
17 #include <util/DoublyLinkedList.h>
18 
19 
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.
25 
26 struct daemon : DoublyLinkedListLinkImpl<struct daemon> {
27 	daemon_hook	function;
28 	void*		arg;
29 	int32		frequency;
30 	int32		offset;
31 };
32 
33 
34 typedef DoublyLinkedList<struct daemon> DaemonList;
35 
36 static mutex sDaemonMutex = MUTEX_INITIALIZER("kernel daemon");
37 static DaemonList sDaemons;
38 
39 
40 static status_t
41 kernel_daemon(void* data)
42 {
43 	int32 iteration = 0;
44 
45 	while (true) {
46 		mutex_lock(&sDaemonMutex);
47 
48 		DaemonList::Iterator iterator = sDaemons.GetIterator();
49 
50 		// iterate through the list and execute each daemon if needed
51 		while (iterator.HasNext()) {
52 			struct daemon* daemon = iterator.Next();
53 
54 			if (((iteration + daemon->offset) % daemon->frequency) == 0)
55 				daemon->function(daemon->arg, iteration);
56 		}
57 		mutex_unlock(&sDaemonMutex);
58 
59 		iteration++;
60 		snooze(100000);	// 0.1 seconds
61 	}
62 
63 	return B_OK;
64 }
65 
66 
67 //	#pragma mark -
68 
69 
70 extern "C" status_t
71 unregister_kernel_daemon(daemon_hook function, void* arg)
72 {
73 	MutexLocker _(sDaemonMutex);
74 
75 	DaemonList::Iterator iterator = sDaemons.GetIterator();
76 
77 	// search for the daemon and remove it from the list
78 	while (iterator.HasNext()) {
79 		struct daemon* daemon = iterator.Next();
80 
81 		if (daemon->function == function && daemon->arg == arg) {
82 			// found it!
83 			iterator.Remove();
84 			delete daemon;
85 			return B_OK;
86 		}
87 	}
88 
89 	return B_ENTRY_NOT_FOUND;
90 }
91 
92 
93 extern "C" status_t
94 register_kernel_daemon(daemon_hook function, void* arg, int frequency)
95 {
96 	if (function == NULL || frequency < 1)
97 		return B_BAD_VALUE;
98 
99 	struct daemon* daemon = new(std::nothrow) struct daemon();
100 	if (daemon == NULL)
101 		return B_NO_MEMORY;
102 
103 	daemon->function = function;
104 	daemon->arg = arg;
105 	daemon->frequency = frequency;
106 
107 	MutexLocker _(sDaemonMutex);
108 
109 	if (frequency > 1) {
110 		// we try to balance the work-load for each daemon run
111 		// (beware, it's a very simple algorithm, yet effective)
112 
113 		DaemonList::Iterator iterator = sDaemons.GetIterator();
114 		int32 num = 0;
115 
116 		while (iterator.HasNext()) {
117 			if (iterator.Next()->frequency == frequency)
118 				num++;
119 		}
120 
121 		daemon->offset = num % frequency;
122 	} else
123 		daemon->offset = 0;
124 
125 	sDaemons.Add(daemon);
126 	return B_OK;
127 }
128 
129 
130 extern "C" status_t
131 kernel_daemon_init(void)
132 {
133 	new(&sDaemons) DaemonList;
134 
135 	thread_id thread = spawn_kernel_thread(&kernel_daemon, "kernel daemon",
136 		B_LOW_PRIORITY, NULL);
137 	send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE);
138 
139 	return B_OK;
140 }
141