Daemon threads keep running until they finish or until finalization starts. For the latter, there is a check right after the thread acquires the GIL which causes the thread to exit if runtime finalization has started. [1] However, there are functions in the C-API that facilitate acquiring the GIL, but do not cause the thread to exit during finalization:
PyEval_AcquireLock()
PyEval_AcquireThread()
Daemon threads that acquire the GIL through these can cause a deadlock during finalization. (See issue #36469.) They should probably be updated to match what PyEval_RestoreThread() does.
[1] see PyEval_RestoreThread() and the eval loop, in PyEval_EvalFrameEx()