* The kernel daemon no longer hold its lock when calling the registered hooks.

* This fixes bug #5421.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36209 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-04-13 12:09:56 +00:00
parent 0d84b31334
commit 2e7bd0169f
1 changed files with 48 additions and 7 deletions

View File

@ -29,6 +29,7 @@ struct daemon : DoublyLinkedListLinkImpl<struct daemon> {
void* arg; void* arg;
int32 frequency; int32 frequency;
int32 offset; int32 offset;
bool executing;
}; };
@ -49,11 +50,14 @@ private:
static status_t _DaemonThreadEntry(void* data); static status_t _DaemonThreadEntry(void* data);
struct daemon* _NextDaemon(struct daemon& marker); struct daemon* _NextDaemon(struct daemon& marker);
status_t _DaemonThread(); status_t _DaemonThread();
bool _IsDaemon() const;
private: private:
recursive_lock fLock; recursive_lock fLock;
DaemonList fDaemons; DaemonList fDaemons;
thread_id fThread; thread_id fThread;
ConditionVariable fUnregisterCondition;
int32 fUnregisterWaiters;
}; };
@ -72,6 +76,7 @@ KernelDaemon::Init(const char* name)
return fThread; return fThread;
send_signal_etc(fThread, SIGCONT, B_DO_NOT_RESCHEDULE); send_signal_etc(fThread, SIGCONT, B_DO_NOT_RESCHEDULE);
fUnregisterCondition.Init(this, name);
return B_OK; return B_OK;
} }
@ -90,6 +95,7 @@ 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->executing = false;
RecursiveLocker _(fLock); RecursiveLocker _(fLock);
@ -117,7 +123,7 @@ KernelDaemon::Register(daemon_hook function, void* arg, int frequency)
status_t status_t
KernelDaemon::Unregister(daemon_hook function, void* arg) KernelDaemon::Unregister(daemon_hook function, void* arg)
{ {
RecursiveLocker _(fLock); RecursiveLocker locker(fLock);
DaemonList::Iterator iterator = fDaemons.GetIterator(); DaemonList::Iterator iterator = fDaemons.GetIterator();
@ -127,6 +133,22 @@ KernelDaemon::Unregister(daemon_hook function, void* arg)
if (daemon->function == function && daemon->arg == arg) { if (daemon->function == function && daemon->arg == arg) {
// found it! // 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(); iterator.Remove();
delete daemon; delete daemon;
return B_OK; return B_OK;
@ -154,11 +176,12 @@ KernelDaemon::Dump()
if (strchr(imageName, '/') != NULL) if (strchr(imageName, '/') != NULL)
imageName = strrchr(imageName, '/') + 1; imageName = strrchr(imageName, '/') + 1;
kprintf("\t%s:%s (%p), arg %p\n", imageName, symbol, kprintf("\t%s:%s (%p)", imageName, symbol, daemon->function);
daemon->function, daemon->arg); } else
} else { kprintf("\t%p", daemon->function);
kprintf("\t%p, arg %p\n", daemon->function, daemon->arg);
} kprintf(", arg %p%s\n", daemon->arg,
daemon->executing ? " (running) " : "");
} }
} }
@ -205,8 +228,19 @@ KernelDaemon::_DaemonThread()
// 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;
locker.Unlock();
if (((iteration + daemon->offset) % daemon->frequency) == 0) if (((iteration + daemon->offset) % daemon->frequency) == 0)
daemon->function(daemon->arg, iteration); daemon->function(daemon->arg, iteration);
locker.Lock();
daemon->executing = false;
}
if (fUnregisterWaiters != 0) {
fUnregisterCondition.NotifyAll();
fUnregisterWaiters = 0;
} }
locker.Unlock(); locker.Unlock();
@ -219,7 +253,14 @@ KernelDaemon::_DaemonThread()
} }
// #pragma mark - bool
KernelDaemon::_IsDaemon() const
{
return find_thread(NULL) == fThread;
}
// #pragma mark -
static int static int