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