co_usb
Loading...
Searching...
No Matches
handlers.hpp
Go to the documentation of this file.
1
6#pragma once
7
10#include <atomic>
11#include <thread>
12
13namespace co_usb::ev
14{
24{
31 auto start (libusb_context *usb_ctx, std::stop_token stop) -> bool
32 {
33 auto handle_fn = [usb_ctx, stop]
34 {
35 const timeval ctv = {.tv_sec = 0, .tv_usec = 10'000};
36 while (!stop.stop_requested())
37 {
38 timeval tv = ctv;
39 auto r = libusb_handle_events_timeout(usb_ctx, &tv);
40 if (r != LIBUSB_SUCCESS)
41 {
42 throw std::system_error{make_usb_error_code(static_cast<usb_error>(r))};
43 }
44 }
45 };
46 m_thread = std::thread{std::move(handle_fn)};
47 return true;
48 }
49
55 auto ref () noexcept
56 {
57 // no-op, there is nothing to ref
58 }
59
65 auto unref () noexcept
66 {
67 // no-op, there is nothing to ref
68 }
69
75 auto stop ()
76 {
77 if (m_thread.joinable())
78 m_thread.join();
79 }
80
85 {
86 stop();
87 }
88
89 private:
90 std::thread m_thread;
91};
92
93static_assert(detail::EventHandler<trivial_event_handler>, "Not a proper usb event handler");
94static_assert(detail::EventHandler<trivial_event_handler>, "Not a proper usb event handler");
95
106{
113 auto start (libusb_context *usb_ctx, std::stop_token stop) -> bool
114 {
115 try
116 {
117 auto handle_fn = [this, usb_ctx, stop]
118 {
119 const timeval ctv = {.tv_sec = 0, .tv_usec = 10'000};
120 for (;;)
121 {
122 timeval tv = ctv;
123 auto r = libusb_handle_events_timeout(usb_ctx, &tv);
124 if (r != LIBUSB_SUCCESS) [[unlikely]]
125 {
126 throw std::system_error{
127 make_usb_error_code(static_cast<co_usb::usb_error>(r))};
128 }
129
130 if (stop.stop_requested() && m_counter.load(std::memory_order_acquire) == 0)
131 [[unlikely]]
132 {
133 break;
134 }
135 }
136 };
137 m_thread = std::thread{std::move(handle_fn)};
138 return true;
139 }
140 catch (...)
141 {
142 return false;
143 }
144 }
145
149 auto ref () noexcept
150 {
151 m_counter.fetch_add(1, std::memory_order_acquire);
152 }
153
157 auto unref () noexcept
158 {
159 m_counter.fetch_sub(1, std::memory_order_release);
160 }
161
167 auto stop ()
168 {
169 if (m_thread.joinable())
170 m_thread.join();
171 }
172
177 {
178 stop();
179 }
180
181 private:
182 std::atomic_size_t m_counter{0};
183 std::thread m_thread;
184};
185
186static_assert(detail::EventHandler<refcounted_event_handler>, "Not a proper usb event handler");
187static_assert(detail::EventHandler<refcounted_event_handler>, "Not a proper usb event handler");
188
189} // namespace co_usb::ev
Specification and implementation of EventHandler concept.
Definition any_event_handler.hpp:15
usb_error
USB error enumeration.
Definition usb_error.hpp:20
std::error_code make_usb_error_code(usb_error e) noexcept
Definition usb_error.hpp:85
libusb event handler with simple internal reference counting.
Definition handlers.hpp:106
~refcounted_event_handler()
Stop the event thread on destruction.
Definition handlers.hpp:176
auto unref() noexcept
Decrement the internal reference counter.
Definition handlers.hpp:157
auto ref() noexcept
Increment the internal reference counter.
Definition handlers.hpp:149
auto stop()
Stop the event loop and wait for the thread to finish.
Definition handlers.hpp:167
auto start(libusb_context *usb_ctx, std::stop_token stop) -> bool
Start the libusb event processing loop.
Definition handlers.hpp:113
Trivial single-threaded libusb event handler.
Definition handlers.hpp:24
auto unref() noexcept
Decrement internal reference count.
Definition handlers.hpp:65
auto start(libusb_context *usb_ctx, std::stop_token stop) -> bool
Start the libusb event processing loop.
Definition handlers.hpp:31
~trivial_event_handler()
Stop the event thread on destruction.
Definition handlers.hpp:84
auto stop()
Stop the event loop and wait for the thread to finish.
Definition handlers.hpp:75
auto ref() noexcept
Increment internal reference count.
Definition handlers.hpp:55
USB error enumeration.