@@ -31,36 +31,56 @@ PyNotifier::PyNotifier(std::function<void()> handler) {
3131
3232 std::function<void ()> target ([this ] {
3333 py::gil_scoped_release release;
34- for (;;) {
35- int32_t status = 0 ;
36- HAL_NotifierHandle notifier = m_notifier.load ();
37- if (notifier == 0 ) {
38- break ;
39- }
40- uint64_t curTime = HAL_WaitForNotifierAlarm (notifier, &status);
41- if (curTime == 0 || status != 0 ) {
42- break ;
43- }
4434
45- std::function<void ()> handler;
46- {
47- std::scoped_lock lock (m_processMutex);
48- handler = m_handler;
49- if (m_periodic) {
50- m_expirationTime += m_period;
51- UpdateAlarm ();
52- } else {
53- // need to update the alarm to cause it to wait again
54- UpdateAlarm (UINT64_MAX);
35+ try {
36+ for (;;) {
37+ int32_t status = 0 ;
38+ HAL_NotifierHandle notifier = m_notifier.load ();
39+ if (notifier == 0 ) {
40+ break ;
41+ }
42+ uint64_t curTime = HAL_WaitForNotifierAlarm (notifier, &status);
43+ if (curTime == 0 || status != 0 ) {
44+ break ;
45+ }
46+
47+ std::function<void ()> handler;
48+ {
49+ std::scoped_lock lock (m_processMutex);
50+ handler = m_handler;
51+ if (m_periodic) {
52+ m_expirationTime += m_period;
53+ UpdateAlarm ();
54+ } else {
55+ // need to update the alarm to cause it to wait again
56+ UpdateAlarm (UINT64_MAX);
57+ }
58+ }
59+
60+ // call callback
61+ if (handler) {
62+ if (Py_IsFinalizing ()) {
63+ break ;
64+ }
65+
66+ handler ();
5567 }
5668 }
69+ } catch (...) {
70+ if (Py_IsFinalizing ()) {
71+ // Hang the thread since returning to the caller is going to crash
72+ // when we try to obtain the GIL again
73+ // - this is a daemon thread so it's fine?
74+ // - Python 3.14 does this too
75+ while (true ) {}
76+ }
5777
58- // call callback
59- if (handler)
60- handler ();
78+ throw ;
6179 }
80+
6281 if (Py_IsFinalizing ()) {
63- release.disarm ();
82+ // see above
83+ while (true ) {}
6484 }
6585 });
6686
0 commit comments