Skip to content

Call the setdefault_with factory without holding the lock - #68

Merged
awolverp merged 1 commit into
awolverp:mainfrom
Malkiz223:setdefault_deadlock
Aug 9, 2026
Merged

Call the setdefault_with factory without holding the lock#68
awolverp merged 1 commit into
awolverp:mainfrom
Malkiz223:setdefault_deadlock

Conversation

@Malkiz223

Copy link
Copy Markdown
Contributor

Closes #67

The factory used to run while the internal lock was held, and __traverse__ takes that same lock, so a GC pass inside the factory froze the process. Now the key is looked up under the lock, the lock is dropped, the factory runs without it, and then the lock is taken again to re-check the key before inserting. Same change in all seven cache types, plus the doc strings.

One behaviour change: if two threads miss the same key at the same time, the factory can run twice. The value inserted first stays in the cache and is returned to both of them, so no caller ends up holding an object the cache does not have.

The test sits in the shared mixin, so it runs for all seven types. It does the call in a child process on purpose: a deadlock keeps the GIL, so a watchdog inside the same process would never fire. Without the patch the test fails with "never returned" instead of freezing the whole run.

1004 passed, 6 skipped. The suite also stopped hanging: 4 freezes in 9 runs before, 5 clean runs out of 5 after.

@awolverp

awolverp commented Aug 9, 2026

Copy link
Copy Markdown
Owner

I hadn’t thought of something like that
thank you for finding the problem and fixing it

@awolverp
awolverp merged commit c546547 into awolverp:main Aug 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

setdefault_with freezes the whole process when the factory triggers a GC pass

2 participants