Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mark watchdog thread daemonic #16

Merged
merged 1 commit into from
Jan 3, 2024
Merged

Mark watchdog thread daemonic #16

merged 1 commit into from
Jan 3, 2024

Conversation

ThirteenFish
Copy link
Contributor

A python application will only quit when all non-daemonic threads have stopped. The watchdog thread is non-daemonic and so oresat_c3 can only quit once the watchdog thread has stopped. The watchdog thread will only quit if event is set, and event only gets set if oresat_c3 successfully makes it to the end of main().

If oresat_c3 doesn't make it successfully to the end of main() (say an exception occurs during service initialization) then the watchdog thread will never stop, even though the main thread has, keeping the application running in a sort of unresponsive zombie mode. It is in fact so unresponsive that it ignores SIGINT (ctrl-c) so the only way to get it to stop is a SIGKILL, which is uncouth.

Daemonic threads on the other hand will stop abruptly when the last non-daemon thread stops. This can be bad if resources in the thread need finalization but the only resource in the watchdog thread is a UDP socket, which the kernel will helpfully close for us. Setting the daemonic flag on the watchdog thread allows oresat_c3 to stop gracefully in exceptional circumstances.

An alternative to daemonic threads would be to wrap everything after starting the thread in a try-finally block but I felt that would be a bit more intrusive.

A python application will only quit when all non-daemonic threads have
stopped. The watchdog thread is non-daemonic and so oresat_c3 can only
quit once the watchdog thread has stopped. The watchdog thread will only
quit if `event` is set, and `event` only gets set if oresat_c3
successfully makes it to the end of `main()`.

If oresat_c3 doesn't make it successfully to the end of `main()` (say an
exception occurs during service initialization) then the watchdog thread
will never stop, even though the main thread has, keeping the
application running in a sort of unresponsive zombie mode. It is in fact
so unresponsive that it ignores SIGINT (ctrl-c) so the only way to get
it to stop is a SIGKILL, which is uncouth.

Daemonic threads on the other hand will stop abruptly when the last
non-daemon thread stops. This can be bad if resources in the thread need
finalization but the only resource in the watchdog thread is a UDP
socket, which the kernel will helpfully close for us. Setting the
daemonic flag on the watchdog thread allows oresat_c3 to stop gracefully
in exceptional circumstances.

An alternative to daemonic threads would be to wrap everything after
starting the thread in a try-finally block but I felt that would be a
bit more intrusive.
Copy link
Member

@ryanpdx ryanpdx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome explanation!

@ryanpdx ryanpdx merged commit 7f26170 into master Jan 3, 2024
1 check failed
@ryanpdx ryanpdx deleted the daemonic-watchdog branch January 3, 2024 01:30
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.

2 participants