-
- Notifications
You must be signed in to change notification settings - Fork 546
CRT: make termination signal handler async signal safe #1839
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| | @@ -96,6 +96,9 @@ const char* const* CRT_treeStr = CRT_treeStrAscii; | |
| | ||
| static const Settings* CRT_settings; | ||
| | ||
| static volatile sig_atomic_t CRT_terminateRequested = 0; | ||
| static volatile sig_atomic_t CRT_terminateSignal = 0; | ||
| | ||
| #ifdef HAVE_LIBNCURSESW | ||
| # if MB_LEN_MAX >= 3 // Minimum required to support UTF-8 BMP subset | ||
| char CRT_degreeSign[MB_LEN_MAX * 2] = "\xc2\xb0"; | ||
| | @@ -957,8 +960,22 @@ int CRT_scrollWheelVAmount = 10; | |
| | ||
| ColorScheme CRT_colorScheme = COLORSCHEME_DEFAULT; | ||
| | ||
| ATTR_NORETURN | ||
| | ||
| static void CRT_handleSIGTERM(int sgn) { | ||
| CRT_terminateSignal = (sig_atomic_t)sgn; | ||
| CRT_terminateRequested = 1; | ||
| Comment on lines +965 to +966 Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only thread/async-safe if you guarantee write order with a memory barrier. Does not handle re-entrance … | ||
| } | ||
| Comment on lines 964 to +967 Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This causes things like That these handlers were Furthermore moving the actual signal execution away from the signal handler causes the reported backtrace to become useless, as it now will report the (known) call path to the central user code handler … Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understood. I’ll rework this to keep the existing handler-driven structure and instead remove/rewrite the non–async-signal-safe calls used by the handler(s), so termination and reporting still happen in the signal context. You can close this PR and I'll rework and resubmit. Author There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @BenBE Quick question for the rework: CRT_done() is curses-based (endwin(), refresh(), etc.), so it can’t be made async-signal-safe in a meaningful way. For SIGINT/SIGTERM/SIGQUIT, would you prefer (a) dropping CRT_done() from the handler and accepting that the terminal may be left in a bad state, or (b) keeping the current cleanup despite not being signal-safe? I’ll follow the project’s preferred behavior. Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While we can't fully avoid the signal nesting, and thus catching a signal inside our handler, we may be able to apply to mitigations:
So to answer your question: (c) leaving the console in a somewhat bad state is acceptable, although it should be avoided for common cases where reasonably possible. | ||
| | ||
| static void CRT_tryTermExit(void) { | ||
| | ||
| if (!CRT_terminateRequested) { | ||
| return; | ||
| } | ||
| | ||
| int sgn = (int)CRT_terminateSignal; | ||
| signal(SIGINT, SIG_DFL); | ||
| signal(SIGTERM, SIG_DFL); | ||
| signal(SIGQUIT, SIG_DFL); | ||
| Comment on lines +976 to +978 Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those LOC are the only ones in this PR that got me at least partially convinced. | ||
| CRT_done(); | ||
| | ||
| if (!CRT_settings->changed) | ||
| | @@ -970,12 +987,13 @@ static void CRT_handleSIGTERM(int sgn) { | |
| | ||
| char err_buf[512]; | ||
| snprintf(err_buf, sizeof(err_buf), | ||
| "A signal %d (%s) was received, exiting without persisting settings to htoprc.\n", | ||
| sgn, signal_str); | ||
| "A signal %d (%s) was received, exiting without persisting settings to htoprc.\n", | ||
| sgn, signal_str); | ||
| Comment on lines -973 to +991 Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why change the indentation? | ||
| full_write_str(STDERR_FILENO, err_buf); | ||
| _exit(0); | ||
| } | ||
| | ||
| | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary whitespace change | ||
| #ifndef NDEBUG | ||
| | ||
| static int stderrRedirectNewFd = -1; | ||
| | @@ -1311,9 +1329,11 @@ void CRT_fatalError(const char* note) { | |
| } | ||
| | ||
| int CRT_readKey(void) { | ||
| | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary whitespace change | ||
| nocbreak(); | ||
| cbreak(); | ||
| nodelay(stdscr, FALSE); | ||
| CRT_tryTermExit(); | ||
| Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See note above for why this breaks more than it repairs. | ||
| int ret = getch(); | ||
| halfdelay(CRT_settings->delay); | ||
| return ret; | ||
| | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a small idea that I'm not sure you would experiment on.
The
CRT_terminateSignalvariable andCRT_terminateRequestedflag may be merged to one variable. Since the signal number would be likely zero if there's no signal received.