diff --git a/src/kernel/core/Jamfile b/src/kernel/core/Jamfile index 8f4dc5d840..c3b0755710 100644 --- a/src/kernel/core/Jamfile +++ b/src/kernel/core/Jamfile @@ -13,6 +13,7 @@ KernelMergeObject kernel_core.o : <$(SOURCE_GRIST)>heap.c <$(SOURCE_GRIST)>image.c <$(SOURCE_GRIST)>int.c + <$(SOURCE_GRIST)>kernel_daemon.c <$(SOURCE_GRIST)>khash.c <$(SOURCE_GRIST)>linkhack.c <$(SOURCE_GRIST)>list.c diff --git a/src/kernel/core/kernel_daemon.c b/src/kernel/core/kernel_daemon.c new file mode 100644 index 0000000000..5db3d68da3 --- /dev/null +++ b/src/kernel/core/kernel_daemon.c @@ -0,0 +1,132 @@ +/* +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include +#include + +#include +#include +#include + + +// ToDo: 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 { + list_link link; + void (*function)(void *, int); + void *arg; + int32 frequency; + int32 offset; +}; + + +mutex gDaemonMutex; +struct list gDaemons; + + +static int32 +kernel_daemon(void *data) +{ + int32 iteration = 0; + + while (true) { + struct daemon *daemon = NULL; + + mutex_lock(&gDaemonMutex); + + // iterate through the list and execute each daemon if needed + while ((daemon = list_get_next_item(&gDaemons, daemon)) != NULL) { + if (((iteration + daemon->offset) % daemon->frequency) == 0) + daemon->function(daemon->arg, iteration); + } + mutex_lock(&gDaemonMutex); + + iteration++; + snooze(100000); // 0.1 seconds + } +} + + +status_t +unregister_kernel_daemon(void (*function)(void *, int), void *arg) +{ + struct daemon *daemon = NULL; + + mutex_lock(&gDaemonMutex); + + // search for the daemon and remove it from the list + while ((daemon = list_get_next_item(&gDaemons, daemon)) != NULL) { + if (daemon->function == function && daemon->arg == arg) { + // found it! + list_remove_link(daemon); + free(daemon); + break; + } + } + mutex_lock(&gDaemonMutex); + + // if we've iterated through the whole list, we didn't + // find the daemon, and "daemon" is NULL + return daemon != NULL ? B_OK : B_ENTRY_NOT_FOUND; +} + + +status_t +register_kernel_daemon(void (*function)(void *, int), void *arg, int frequency) +{ + struct daemon *daemon; + + if (function == NULL || frequency < 1) + return B_BAD_VALUE; + + daemon = malloc(sizeof(daemon)); + if (daemon == NULL) + return B_NO_MEMORY; + + daemon->function = function; + daemon->arg = arg; + daemon->frequency = frequency; + + mutex_lock(&gDaemonMutex); + + if (frequency > 1) { + // we try to balance the work-load for each daemon run + // (beware, it's a very simple algorithm, yet effective) + + struct daemon *d = NULL; + int32 num = 0; + + while ((d = list_get_next_item(&gDaemons, d)) != NULL) { + if (d->frequency == frequency) + num++; + } + + daemon->offset = num % frequency; + } else + daemon->offset = 0; + + list_add_link_to_tail(&gDaemons, daemon); + mutex_lock(&gDaemonMutex); + + return B_OK; +} + + +status_t +kernel_daemon_init(void) +{ + if (mutex_init(&gDaemonMutex, "kernel daemon") < B_OK) + return B_ERROR; + + list_init(&gDaemons); + + return spawn_kernel_thread(&kernel_daemon, "kernel daemon", B_LOW_PRIORITY, NULL); +} diff --git a/src/kernel/core/main.c b/src/kernel/core/main.c index 5854910a35..6cb462e94b 100644 --- a/src/kernel/core/main.c +++ b/src/kernel/core/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -101,6 +102,7 @@ _start(kernel_args *oldka, int cpu_num) team_init(&ka); thread_init(&ka); port_init(&ka); + kernel_daemon_init(); vm_init_postthread(&ka); elf_init(&ka);