Release retired document sources outside the cache lock

This commit is contained in:
ak47 committed 2026-11-04 19:24:52 -05:00
1 parent b4896a2eb4
commit 228271b43b
3 files changed
+124 -13

No files matched your search

+28 -13
View File
@@ -489,11 +489,30 @@ func (adapter *Adapter) retainedDocumentRoot(id ObjectID) ObjectID {
// calls this on the GLib thread once the capture root is known, before
// preparing the incremental-refresh cache.
func (adapter *Adapter) rotateDocumentSlots(root ObjectID) {
adapter.rotateDocumentSlotsAndRelease(root, releaseDocumentSources)
}
func releaseDocumentSources(document stashedDocument) {
for _, source := range document.sources {
C.g_object_unref(C.gpointer(source))
}
}
// libatspi disposal synchronously emits defunct events. Publish the new slots
// and unlock before releasing references, so reentrant invalidation sees a
// consistent cache and can acquire treeMutex.
func (adapter *Adapter) rotateDocumentSlotsAndRelease(root ObjectID, release func(stashedDocument)) {
if !root.Valid() {
return
}
var retired []stashedDocument
adapter.treeMutex.Lock()
defer adapter.treeMutex.Unlock()
defer func() {
adapter.treeMutex.Unlock()
for _, document := range retired {
release(document)
}
}()
if root == adapter.documentSlotRoot {
return
}
@@ -509,14 +528,12 @@ func (adapter *Adapter) rotateDocumentSlots(root ObjectID) {
}
if adapter.documentSlotRoot.Valid() &&
(adapter.documentTree != nil || adapter.documentTextTree != nil) {
adapter.stashDocumentLocked(adapter.documentSlotRoot, stashedDocument{
retired = adapter.stashDocumentLocked(adapter.documentSlotRoot, stashedDocument{
tree: adapter.documentTree, textTree: adapter.documentTextTree,
sources: adapter.nativeDocument,
})
} else {
for _, source := range adapter.nativeDocument {
C.g_object_unref(C.gpointer(source))
}
} else if len(adapter.nativeDocument) != 0 {
retired = append(retired, stashedDocument{sources: adapter.nativeDocument})
}
adapter.documentTree = stashed.tree
adapter.documentTextTree = stashed.textTree
@@ -524,14 +541,13 @@ func (adapter *Adapter) rotateDocumentSlots(root ObjectID) {
adapter.documentSlotRoot = root
}
func (adapter *Adapter) stashDocumentLocked(root ObjectID, document stashedDocument) {
func (adapter *Adapter) stashDocumentLocked(root ObjectID, document stashedDocument) []stashedDocument {
var retired []stashedDocument
if adapter.stashedDocuments == nil {
adapter.stashedDocuments = make(map[ObjectID]stashedDocument)
}
if old, ok := adapter.stashedDocuments[root]; ok {
for _, source := range old.sources {
C.g_object_unref(C.gpointer(source))
}
retired = append(retired, old)
for index, id := range adapter.stashedDocumentIDs {
if id == root {
adapter.stashedDocumentIDs = append(adapter.stashedDocumentIDs[:index], adapter.stashedDocumentIDs[index+1:]...)
@@ -543,12 +559,11 @@ func (adapter *Adapter) stashDocumentLocked(root ObjectID, document stashedDocum
adapter.stashedDocumentIDs = append(adapter.stashedDocumentIDs, root)
for len(adapter.stashedDocumentIDs) > maxStashedDocuments {
oldest := adapter.stashedDocumentIDs[0]
for _, source := range adapter.stashedDocuments[oldest].sources {
C.g_object_unref(C.gpointer(source))
}
retired = append(retired, adapter.stashedDocuments[oldest])
delete(adapter.stashedDocuments, oldest)
adapter.stashedDocumentIDs = adapter.stashedDocumentIDs[1:]
}
return retired
}
// clearStashedDocuments releases every stashed document's native sources.