Thread-local storage global Arc CEC connection handling #4
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a bit of an overall refactor to use a singleton
CecConnectionwhich can be shared across threads.The rationale behind doing this is to be able to share the
CecConnectionacross the FFI boundary to any callback handlers (e.g. functions passed toCecConnectionCfg.command_received_callback()). These callback functions (e.g.on_command_received) were previously not able to utilize theCecConnectionattached to the shared hardware CEC adapter. So they could not use it to respond to any unhandled CEC commands (libcecdoes respond automatically to most, but there are some exceptions).In any case, the underlying lower level
libcec_sysandlibcecC code (used through FFI) will spawn any callback functions in separate threads. That poses the issue of how to share aCecConnectionobject in Rust across this boundary. Using this singleton pattern works and passes Rust's borrow and type checking, thanks toArcbeing a thread-safe reference-counting pointer.This should enable us to handle responding to CEC commands in the future within the
on_command_received()callback.Changes:
cargo: Add arrayvec 0.7.1
cargo fmt & Initial implementation of thread-local storage CecConnection handling
debug: Add global atomic thread counter
connection: Refactor
connhandling w/staticOnceLock<Option<Arc<CecConnection>>>Thread-local wasn't working to truly share the same connection across threads
because the mutable borrow was failing. To complicate matters,
CecConnectionand
CecConnectionCfgdon't implementCopyorClonetraits, nor are theySync.Option<Arc<..>>implements theClonetrait, so relying on this to store anArcto be shared across threads works. Add to this usingOnceLockfor theglobal
staticvariable to be initialized only once. Thus, we create a singletonpattern: the connection initialized in
main()once becomes the single sharedconnection instance, for use in the
on_command_received()handler functionacross
libcecthreads.Note:
LazyLockwas tried, but the initializer proc/closure was always failing toborrow and reliably access thread-local variables. Since initialization may have
been called from multiple threads, any dereferencing call will block the calling
thread if another initialization routine is currently running.
The way that lower-level
cec_rsandlibcec-syslibraries implement the callbackfunctions (e.g.
ICECCallbacks::commandReceived) is to execute them in anotherthread. However, due to the way that Rust type & borrow checked code is run,
we would otherwise lose access to the same
CecConnectionobject across the ffiboundary:
Using this
OnceLocksingleton pattern withOption<Arc<...>>seems to work.