/* ** 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; daemon_hook function; 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_unlock(&gDaemonMutex); iteration++; snooze(100000); // 0.1 seconds } } status_t unregister_kernel_daemon(daemon_hook function, 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_item(&gDaemons, daemon); free(daemon); break; } } mutex_unlock(&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(daemon_hook function, 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_item(&gDaemons, daemon); mutex_unlock(&gDaemonMutex); return B_OK; } status_t kernel_daemon_init(void) { thread_id thread; if (mutex_init(&gDaemonMutex, "kernel daemon") < B_OK) return B_ERROR; list_init(&gDaemons); thread = spawn_kernel_thread(&kernel_daemon, "kernel daemon", B_LOW_PRIORITY, NULL); return resume_thread(thread); }