cache_end_transaction() doesn't remove the transaction, so that the

check in notify_transaction_listeners() didn't hold, although the
cache_hooks were deleted anyway. I've introduced a listener_change
counter to detect changes to the listener list while iterating, since
any change makes the iteration unsafe. Should fix bug #2008 for real.
Nevertheless I thing the transaction listener concept needs revision.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24761 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-04-03 02:24:46 +00:00
parent 3130aa793d
commit a5140cad6a
+14
View File
@@ -141,6 +141,7 @@ struct cache_transaction {
transaction_notification_hook notification_hook;
void *notification_data;
HookList listeners;
uint16 listener_change;
bool open;
bool has_sub_transaction;
bigtime_t last_used;
@@ -343,16 +344,27 @@ notify_transaction_listeners(block_cache *cache, cache_transaction *transaction,
while (iterator.HasNext()) {
cache_hook *hook = iterator.Next();
uint16 listenerChange = transaction->listener_change;
hook->hook(transaction->id, event, hook->data);
if (lookup_transaction(cache, id) != transaction) {
// transaction has been removed by the hook!
return;
} else if (listenerChange != transaction->listener_change) {
// Someone has meddled with the listener list, i.e. continuing the
// iteration is no longer safe. Rewind.
iterator.Rewind();
continue;
// TODO: Maybe even break out completely, but then we might miss
// listeners.
// TODO: The whole listener concept needs to be revised!
}
if (removeListener) {
iterator.Remove();
delete hook;
transaction->listener_change++;
}
}
}
@@ -1730,6 +1742,7 @@ cache_add_transaction_listener(void *_cache, int32 id,
hook->data = data;
transaction->listeners.Add(hook);
transaction->listener_change++;
return B_OK;
}
@@ -1752,6 +1765,7 @@ cache_remove_transaction_listener(void *_cache, int32 id,
if (hook->data == data && hook->hook == hookFunction) {
iterator.Remove();
delete hook;
transaction->listener_change++;
return B_OK;
}
}