kernel/daemon: Sleep as long as possible between runs.
Avoids waking up every 100ms to do nothing. Change-Id: I48c7be41f6102a76b7e770ea45c665ab991c79f0 Reviewed-on: https://review.haiku-os.org/c/haiku/+/1700 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
31d70c106b
commit
8c6b1519a2
@@ -17,17 +17,11 @@
|
|||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
|
||||||
// The use of snooze() in the kernel_daemon() function is very inaccurate, of
|
|
||||||
// course - the time the daemons need to execute add up in each iteration.
|
|
||||||
// But since the kernel daemon is documented to be very inaccurate, this
|
|
||||||
// actually might be okay (and that's why it's implemented this way now :-).
|
|
||||||
// BeOS R5 seems to do it in the same way, anyway.
|
|
||||||
|
|
||||||
struct daemon : DoublyLinkedListLinkImpl<struct daemon> {
|
struct daemon : DoublyLinkedListLinkImpl<struct daemon> {
|
||||||
daemon_hook function;
|
daemon_hook function;
|
||||||
void* arg;
|
void* arg;
|
||||||
int32 frequency;
|
int32 frequency;
|
||||||
int32 offset;
|
bigtime_t last;
|
||||||
bool executing;
|
bool executing;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,6 +48,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
recursive_lock fLock;
|
recursive_lock fLock;
|
||||||
DaemonList fDaemons;
|
DaemonList fDaemons;
|
||||||
|
sem_id fDaemonAddedSem;
|
||||||
thread_id fThread;
|
thread_id fThread;
|
||||||
ConditionVariable fUnregisterCondition;
|
ConditionVariable fUnregisterCondition;
|
||||||
int32 fUnregisterWaiters;
|
int32 fUnregisterWaiters;
|
||||||
@@ -69,6 +64,10 @@ KernelDaemon::Init(const char* name)
|
|||||||
{
|
{
|
||||||
recursive_lock_init(&fLock, name);
|
recursive_lock_init(&fLock, name);
|
||||||
|
|
||||||
|
fDaemonAddedSem = create_sem(0, "kernel daemon added");
|
||||||
|
if (fDaemonAddedSem < 0)
|
||||||
|
return fDaemonAddedSem;
|
||||||
|
|
||||||
fThread = spawn_kernel_thread(&_DaemonThreadEntry, name, B_LOW_PRIORITY,
|
fThread = spawn_kernel_thread(&_DaemonThreadEntry, name, B_LOW_PRIORITY,
|
||||||
this);
|
this);
|
||||||
if (fThread < 0)
|
if (fThread < 0)
|
||||||
@@ -94,27 +93,14 @@ KernelDaemon::Register(daemon_hook function, void* arg, int frequency)
|
|||||||
daemon->function = function;
|
daemon->function = function;
|
||||||
daemon->arg = arg;
|
daemon->arg = arg;
|
||||||
daemon->frequency = frequency;
|
daemon->frequency = frequency;
|
||||||
|
daemon->last = 0;
|
||||||
daemon->executing = false;
|
daemon->executing = false;
|
||||||
|
|
||||||
RecursiveLocker _(fLock);
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
if (frequency > 1) {
|
|
||||||
// we try to balance the work-load for each daemon run
|
|
||||||
// (beware, it's a very simple algorithm, yet effective)
|
|
||||||
|
|
||||||
DaemonList::Iterator iterator = fDaemons.GetIterator();
|
|
||||||
int32 num = 0;
|
|
||||||
|
|
||||||
while (iterator.HasNext()) {
|
|
||||||
if (iterator.Next()->frequency == frequency)
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
daemon->offset = num % frequency;
|
|
||||||
} else
|
|
||||||
daemon->offset = 0;
|
|
||||||
|
|
||||||
fDaemons.Add(daemon);
|
fDaemons.Add(daemon);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
release_sem(fDaemonAddedSem);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,20 +204,29 @@ status_t
|
|||||||
KernelDaemon::_DaemonThread()
|
KernelDaemon::_DaemonThread()
|
||||||
{
|
{
|
||||||
struct daemon marker;
|
struct daemon marker;
|
||||||
int32 iteration = 0;
|
const bigtime_t start = system_time(), iterationToUsecs = 100 * 1000;
|
||||||
|
|
||||||
marker.arg = NULL;
|
marker.arg = NULL;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
RecursiveLocker locker(fLock);
|
RecursiveLocker locker(fLock);
|
||||||
|
|
||||||
|
bigtime_t timeout = INT64_MAX;
|
||||||
|
|
||||||
// iterate through the list and execute each daemon if needed
|
// iterate through the list and execute each daemon if needed
|
||||||
while (struct daemon* daemon = _NextDaemon(marker)) {
|
while (struct daemon* daemon = _NextDaemon(marker)) {
|
||||||
daemon->executing = true;
|
daemon->executing = true;
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
if (((iteration + daemon->offset) % daemon->frequency) == 0)
|
const bigtime_t time = system_time();
|
||||||
daemon->function(daemon->arg, iteration);
|
bigtime_t next = (daemon->last +
|
||||||
|
(daemon->frequency * iterationToUsecs)) - time;
|
||||||
|
if (next <= 0) {
|
||||||
|
daemon->last = time;
|
||||||
|
next = daemon->frequency * iterationToUsecs;
|
||||||
|
daemon->function(daemon->arg, (time - start) / iterationToUsecs);
|
||||||
|
}
|
||||||
|
timeout = min_c(timeout, next);
|
||||||
|
|
||||||
locker.Lock();
|
locker.Lock();
|
||||||
daemon->executing = false;
|
daemon->executing = false;
|
||||||
@@ -244,8 +239,7 @@ KernelDaemon::_DaemonThread()
|
|||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
iteration++;
|
acquire_sem_etc(fDaemonAddedSem, 1, B_RELATIVE_TIMEOUT, timeout);
|
||||||
snooze(100000); // 0.1 seconds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user