Author: axeld Date: 2010-04-13 14:09:56 +0200 (Tue, 13 Apr 2010) New Revision: 36209 Changeset: http://dev.haiku-os.org/changeset/36209/haiku Ticket: http://dev.haiku-os.org/ticket/5421 Modified: haiku/trunk/src/system/kernel/kernel_daemon.cpp Log: * The kernel daemon no longer hold its lock when calling the registered hooks. * This fixes bug #5421. Modified: haiku/trunk/src/system/kernel/kernel_daemon.cpp =================================================================== --- haiku/trunk/src/system/kernel/kernel_daemon.cpp 2010-04-13 11:25:15 UTC (rev 36208) +++ haiku/trunk/src/system/kernel/kernel_daemon.cpp 2010-04-13 12:09:56 UTC (rev 36209) @@ -29,6 +29,7 @@ void* arg; int32 frequency; int32 offset; + bool executing; }; @@ -49,11 +50,14 @@ static status_t _DaemonThreadEntry(void* data); struct daemon* _NextDaemon(struct daemon& marker); status_t _DaemonThread(); + bool _IsDaemon() const; private: recursive_lock fLock; DaemonList fDaemons; thread_id fThread; + ConditionVariable fUnregisterCondition; + int32 fUnregisterWaiters; }; @@ -72,6 +76,7 @@ return fThread; send_signal_etc(fThread, SIGCONT, B_DO_NOT_RESCHEDULE); + fUnregisterCondition.Init(this, name); return B_OK; } @@ -90,6 +95,7 @@ daemon->function = function; daemon->arg = arg; daemon->frequency = frequency; + daemon->executing = false; RecursiveLocker _(fLock); @@ -117,7 +123,7 @@ status_t KernelDaemon::Unregister(daemon_hook function, void* arg) { - RecursiveLocker _(fLock); + RecursiveLocker locker(fLock); DaemonList::Iterator iterator = fDaemons.GetIterator(); @@ -127,6 +133,22 @@ if (daemon->function == function && daemon->arg == arg) { // found it! + if (!_IsDaemon()) { + // wait if it's busy + while (daemon->executing) { + fUnregisterWaiters++; + + ConditionVariableEntry entry; + fUnregisterCondition.Add(&entry); + + locker.Unlock(); + + entry.Wait(); + + locker.Lock(); + } + } + iterator.Remove(); delete daemon; return B_OK; @@ -154,11 +176,12 @@ if (strchr(imageName, '/') != NULL) imageName = strrchr(imageName, '/') + 1; - kprintf("\t%s:%s (%p), arg %p\n", imageName, symbol, - daemon->function, daemon->arg); - } else { - kprintf("\t%p, arg %p\n", daemon->function, daemon->arg); - } + kprintf("\t%s:%s (%p)", imageName, symbol, daemon->function); + } else + kprintf("\t%p", daemon->function); + + kprintf(", arg %p%s\n", daemon->arg, + daemon->executing ? " (running) " : ""); } } @@ -205,10 +228,21 @@ // iterate through the list and execute each daemon if needed while (struct daemon* daemon = _NextDaemon(marker)) { + daemon->executing = true; + locker.Unlock(); + if (((iteration + daemon->offset) % daemon->frequency) == 0) daemon->function(daemon->arg, iteration); + + locker.Lock(); + daemon->executing = false; } + if (fUnregisterWaiters != 0) { + fUnregisterCondition.NotifyAll(); + fUnregisterWaiters = 0; + } + locker.Unlock(); iteration++; @@ -219,9 +253,16 @@ } -// #pragma mark - +bool +KernelDaemon::_IsDaemon() const +{ + return find_thread(NULL) == fThread; +} +// #pragma mark - + + static int dump_daemons(int argc, char** argv) {