Skip to content

feat(macos): add actionable startup diagnostics and clean shutdown#2015

Merged
jtroo merged 1 commit intojtroo:mainfrom
FlameFlag:flameflag/push-xmmyszstkpqs
Apr 11, 2026
Merged

feat(macos): add actionable startup diagnostics and clean shutdown#2015
jtroo merged 1 commit intojtroo:mainfrom
FlameFlag:flameflag/push-xmmyszstkpqs

Conversation

@FlameFlag
Copy link
Copy Markdown
Contributor

Describe your changes. Use imperative present tense.

Install a SIGABRT handler at the top of KbdIn::new that writes a
static stderr hint after libc++abi's own message, enumerating the real
causes of a startup abort in order: not running as root (the number
1 cause, since the karabiner-driverkit IPC lives under the root-owned
/Library/Application Support/org.pqrs/tmp/rootonly/ and kanata itself
must run as root), driver not installed / system extension not approved,
or another exclusive grabber. Without this, the C++ dispatcher threads
throw an uncaught std::filesystem_error on a posix_stat of the
rootonly directory and libc++abi prints an unhelpful backtrace

Gate the hint on a startup-phase flag: set it on handler install and
clear it from the macOS event loop right after wait_until_ready
returns, so only startup aborts emit the hint. Silently re-raise
any later SIGABRT to avoid misleading users about unrelated teardown
races. Keep the handler body async-signal-safe (AtomicBool::load,
write(2), signal, raise)

Switch the macOS kill-chord path in check_for_exit from
std::process::exit to libc::_exit (after flushing stdio) so
exiting via lctl+spc+esc bypasses the pqrs shared dispatcher's C++
static destructors. That destructor kills its own worker threads while
they still hold a std::mutex, which makes pthread_mutex_destroy
return EINVAL, raise an uncaught std::system_error, and abort with
libc++abi: mutex lock failed: Invalid argument right after the user's
clean-exit log line. _exit jumps straight to the kernel exit syscall
and skips the entire buggy teardown

Address #1743

Checklist

  • Add documentation to docs/config.adoc
    • N/A
  • Add example and basic docs to cfg_samples/kanata.kbd
    • N/A
  • Update error messages
    • Yes
  • Added tests, or did manual testing
    • Yes + Manual

Install a `SIGABRT` handler at the top of `KbdIn::new` that writes a
static stderr hint after libc++abi's own message, enumerating the real
causes of a startup abort in order: not running as root (the number
1 cause, since the karabiner-driverkit IPC lives under the root-owned
`/Library/Application Support/org.pqrs/tmp/rootonly/` and kanata itself
must run as root), driver not installed / system extension not approved,
or another exclusive grabber. Without this, the C++ dispatcher threads
throw an uncaught `std::filesystem_error` on a posix_stat of the
rootonly directory and libc++abi prints an unhelpful backtrace

Gate the hint on a startup-phase flag: set it on handler install and
clear it from the macOS event loop right after `wait_until_ready`
returns, so only *startup* aborts emit the hint. Silently re-raise
any later `SIGABRT` to avoid misleading users about unrelated teardown
races. Keep the handler body async-signal-safe (`AtomicBool::load`,
`write(2)`, `signal`, `raise`)

Switch the macOS kill-chord path in `check_for_exit` from
`std::process::exit` to `libc::_exit` (after flushing stdio) so
exiting via `lctl+spc+esc` bypasses the pqrs shared dispatcher's C++
static destructors. That destructor kills its own worker threads while
they still hold a `std::mutex`, which makes `pthread_mutex_destroy`
return EINVAL, raise an uncaught `std::system_error`, and abort with
`libc++abi: mutex lock failed: Invalid argument` right after the user's
clean-exit log line. `_exit` jumps straight to the kernel exit syscall
and skips the entire buggy teardown

Address jtroo#1743
@FlameFlag FlameFlag force-pushed the flameflag/push-xmmyszstkpqs branch from 9f61786 to bdf022f Compare April 11, 2026 08:20
@FlameFlag
Copy link
Copy Markdown
Contributor Author

@jtroo I resolved the conflict

@jtroo jtroo merged commit b45bfe8 into jtroo:main Apr 11, 2026
5 checks passed
@FlameFlag FlameFlag deleted the flameflag/push-xmmyszstkpqs branch April 11, 2026 08:51
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