diff --git a/src/spice2x/api/modules/keypads.cpp b/src/spice2x/api/modules/keypads.cpp index 0e20e4b..7d6319c 100644 --- a/src/spice2x/api/modules/keypads.cpp +++ b/src/spice2x/api/modules/keypads.cpp @@ -1,13 +1,14 @@ #include "keypads.h" +#include #include +#include #include #include "avs/game.h" #include "external/rapidjson/document.h" #include "misc/eamuse.h" -#include "util/precise_timer.h" using namespace std::placeholders; using namespace rapidjson; @@ -59,7 +60,6 @@ namespace api::modules { // get params auto keypad = req.params[0].GetUint(); auto input = std::string(req.params[1].GetString()); - timeutils::PreciseSleepTimer timer; // process all chars for (auto c : input) { @@ -93,11 +93,11 @@ namespace api::modules { // set eamuse_set_keypad_overrides(keypad, state); - timer.sleep(sleep_time); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time)); // unset eamuse_set_keypad_overrides(keypad, 0); - timer.sleep(sleep_time); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time)); } } diff --git a/src/spice2x/api/serial.cpp b/src/spice2x/api/serial.cpp index 70ba1b1..8869a52 100644 --- a/src/spice2x/api/serial.cpp +++ b/src/spice2x/api/serial.cpp @@ -1,11 +1,12 @@ #include "controller.h" #include "serial.h" +#include #include +#include #include #include "util/logging.h" -#include "util/precise_timer.h" #include "util/utils.h" @@ -17,7 +18,6 @@ namespace api { controller->init_state(this->state); this->thread = new std::thread([this] () { log_warning("api::serial", "listening on {} (baud: {})", this->port, this->baud); - timeutils::PreciseSleepTimer timer; // read buffer uint8_t read_buffer[16*1024]; @@ -162,7 +162,7 @@ namespace api { // slow down on reconnect if (this->running) { - timer.sleep(retry_time); + std::this_thread::sleep_for(std::chrono::milliseconds(retry_time)); } } }); diff --git a/src/spice2x/games/iidx/poke.cpp b/src/spice2x/games/iidx/poke.cpp index 62abc0c..d60a2c0 100644 --- a/src/spice2x/games/iidx/poke.cpp +++ b/src/spice2x/games/iidx/poke.cpp @@ -1,5 +1,6 @@ #include "poke.h" +#include #include #include "windows.h" @@ -11,7 +12,6 @@ #include "touch/native/inject.h" #include "touch/touch.h" #include "util/logging.h" -#include "util/precise_timer.h" namespace games::iidx::poke { @@ -125,8 +125,6 @@ namespace games::iidx::poke { // create new thread THREAD_RUNNING = true; THREAD = new std::thread([] { - timeutils::PreciseSleepTimer timer; - // log log_info("poke", "enabled"); @@ -198,7 +196,7 @@ namespace games::iidx::poke { } // slow down - timer.sleep(50); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } if (!touch_points.empty()) { diff --git a/src/spice2x/games/nost/poke.cpp b/src/spice2x/games/nost/poke.cpp index 49db8d7..1bdc7ec 100644 --- a/src/spice2x/games/nost/poke.cpp +++ b/src/spice2x/games/nost/poke.cpp @@ -1,6 +1,7 @@ #include "poke.h" #include +#include #include #include @@ -11,7 +12,6 @@ #include "touch/native/inject.h" #include "touch/native/nativetouchhook.h" #include "util/logging.h" -#include "util/precise_timer.h" namespace games::nost::poke { @@ -68,8 +68,6 @@ namespace games::nost::poke { // create new thread THREAD_RUNNING = true; THREAD = new std::thread([] { - timeutils::PreciseSleepTimer timer; - const int swipe_anim_total_frames = 6; const int swipe_anim_y = 300; @@ -194,7 +192,7 @@ namespace games::nost::poke { } // slow down - timer.sleep(30); + std::this_thread::sleep_for(std::chrono::milliseconds(30)); } if (contact_active) { diff --git a/src/spice2x/hooks/audio/backends/mmdevice/null_discard_backend.cpp b/src/spice2x/hooks/audio/backends/mmdevice/null_discard_backend.cpp index 42900b3..4c1c949 100644 --- a/src/spice2x/hooks/audio/backends/mmdevice/null_discard_backend.cpp +++ b/src/spice2x/hooks/audio/backends/mmdevice/null_discard_backend.cpp @@ -2,10 +2,10 @@ #include #include +#include #include "hooks/audio/util.h" #include "util/logging.h" -#include "util/precise_timer.h" NullDiscardBackend::~NullDiscardBackend() { this->running = false; @@ -125,8 +125,6 @@ HRESULT NullDiscardBackend::on_release_buffer(uint32_t, DWORD) { void NullDiscardBackend::pace_loop() { using namespace std::chrono; - timeutils::PreciseSleepTimer timer; - // audio is discarded, so timing precision and drift do not matter; just wake the // game once per buffer period to keep its render thread from blocking on the event. const auto period = duration_cast( @@ -136,6 +134,6 @@ void NullDiscardBackend::pace_loop() { if (this->relay_handle) { SetEvent(this->relay_handle); } - timer.sleep(period); + std::this_thread::sleep_for(period); } } diff --git a/src/spice2x/misc/eamuse.cpp b/src/spice2x/misc/eamuse.cpp index f40a222..a19c9c0 100644 --- a/src/spice2x/misc/eamuse.cpp +++ b/src/spice2x/misc/eamuse.cpp @@ -1,6 +1,7 @@ #include "eamuse.h" #include +#include #include #include @@ -10,7 +11,6 @@ #include "rawinput/rawinput.h" #include "games/sdvx/sdvx.h" #include "util/logging.h" -#include "util/precise_timer.h" #include "util/time.h" #include "util/utils.h" #include "overlay/overlay.h" @@ -335,7 +335,6 @@ void eamuse_coin_start_thread() { COIN_INPUT_THREAD = new std::thread([]() { auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game()); static bool COIN_INPUT_KEY_STATE = false; - timeutils::PreciseSleepTimer timer; while (COIN_INPUT_THREAD_ACTIVE) { // check input key @@ -355,7 +354,7 @@ void eamuse_coin_start_thread() { } // once every two frames - timer.sleep(1000 / 30); + std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 30)); } }); } @@ -409,7 +408,6 @@ void eamuse_pin_macro_start_thread() { size_t pin_index[2] = {PIN_MACRO_VALUES[0].length(), PIN_MACRO_VALUES[1].length()}; std::optional active_unit = std::nullopt; - timeutils::PreciseSleepTimer timer; while (PIN_MACRO_THREAD_ACTIVE) { // wait for key press or auto-trigger @@ -438,7 +436,7 @@ void eamuse_pin_macro_start_thread() { } if (!active_unit.has_value()) { - timer.sleep(20); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); continue; } } @@ -454,22 +452,22 @@ void eamuse_pin_macro_start_thread() { eamuse_set_keypad_overrides(unit, keypad_overrides[char_index]); } pin_index[unit]++; - timer.sleep(100); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // clear eamuse_set_keypad_overrides(unit, 0); - timer.sleep(50); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); // end of PIN if (pin_index[unit] == PIN_MACRO_VALUES[unit].length()) { active_unit = std::nullopt; - timer.sleep(120); + std::this_thread::sleep_for(std::chrono::milliseconds(120)); } continue; } - timer.sleep(200); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } }); } diff --git a/src/spice2x/rawinput/device.h b/src/spice2x/rawinput/device.h index a0eefa8..265c084 100644 --- a/src/spice2x/rawinput/device.h +++ b/src/spice2x/rawinput/device.h @@ -4,7 +4,6 @@ #include #include #include -#include #include @@ -103,6 +102,13 @@ namespace rawinput { std::vector touch_points; }; + struct HIDButtonInputGroup { + USAGE usage_page; + USHORT link_collection; + std::vector cap_indices; + std::vector usages; + }; + struct DeviceHIDInfo { HANDLE handle; _HIDP_CAPS caps; @@ -125,11 +131,12 @@ namespace rawinput { std::vector> button_states; std::vector> button_up, button_down; + std::vector> button_report_states; std::vector> button_output_states; - - // key: usage page, link collection - // value: number of buttons for that key (combine ranges and nonranges) - std::map, ULONG> button_usage_pages; + std::vector button_input_groups; + std::vector output_report; + std::vector button_output_usages; + std::vector button_output_usages_off; std::vector value_states; std::vector value_states_raw; diff --git a/src/spice2x/rawinput/rawinput.cpp b/src/spice2x/rawinput/rawinput.cpp index 81d3772..172f586 100644 --- a/src/spice2x/rawinput/rawinput.cpp +++ b/src/spice2x/rawinput/rawinput.cpp @@ -1,6 +1,10 @@ #include "rawinput.h" +#include +#include #include +#include +#include #include #include @@ -9,7 +13,6 @@ #include "util/logging.h" #include "external/robin_hood.h" -#include "util/precise_timer.h" #include "util/time.h" #include "util/utils.h" @@ -169,9 +172,8 @@ void rawinput::RawInputManager::input_hwnd_create() { }); // wait for window creation being done - timeutils::PreciseSleepTimer timer; while (!this->input_hwnd) { - timer.sleep(1); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } @@ -439,7 +441,9 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device std::vector button_caps_names; std::vector> button_states; std::vector> button_up, button_down; - std::map, ULONG> button_usage_pages; + std::vector> button_report_states; + std::vector button_input_groups; + std::map, size_t> button_input_group_indices; for (int button_cap_num = 0; button_cap_num < button_cap_length; button_cap_num++) { auto &button_caps = button_cap_data[button_cap_num]; @@ -458,7 +462,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1; // ignore bad ranges reported by bad devices - if (button_count >= 0xffff) { + if (button_count <= 0 || button_count >= 0xffff) { log_warning("rawinput", "skipping bad button cap range for device {}, range [{}, {}]", device_name, button_caps.Range.UsageMin, @@ -467,11 +471,30 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device } // fill vectors + const size_t cap_index = button_caps_list.size(); button_caps_list.emplace_back(button_caps); button_states.emplace_back(std::vector(static_cast(button_count), false)); button_up.emplace_back(std::vector(static_cast(button_count), 0.0)); button_down.emplace_back(std::vector(static_cast(button_count), 0.0)); - button_usage_pages[std::make_pair(button_caps.UsagePage, button_caps.LinkCollection)] += button_count; + button_report_states.emplace_back(static_cast(button_count), 0); + + const auto group_key = std::make_pair( + button_caps.UsagePage, + static_cast(button_caps.LinkCollection)); + auto [group_it, inserted] = button_input_group_indices.try_emplace( + group_key, + button_input_groups.size()); + if (inserted) { + button_input_groups.emplace_back(HIDButtonInputGroup { + .usage_page = button_caps.UsagePage, + .link_collection = button_caps.LinkCollection, + .cap_indices = {}, + .usages = {}, + }); + } + auto &input_group = button_input_groups[group_it->second]; + input_group.cap_indices.push_back(cap_index); + input_group.usages.resize(input_group.usages.size() + button_count); // names for (USAGE usg = button_caps.Range.UsageMin; usg <= button_caps.Range.UsageMax; usg++) { @@ -512,7 +535,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1; // ignore bad ranges reported by bad devices - if (button_count >= 0xffff) { + if (button_count <= 0 || button_count >= 0xffff) { log_warning("rawinput", "skipping bad button output cap range for device {}, range [{}, {}]", device_name, button_caps.Range.UsageMin, @@ -800,8 +823,18 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device new_device.hidInfo->button_states = std::move(button_states); new_device.hidInfo->button_up = std::move(button_up); new_device.hidInfo->button_down = std::move(button_down); + new_device.hidInfo->button_report_states = std::move(button_report_states); new_device.hidInfo->button_output_states = std::move(button_output_states); - new_device.hidInfo->button_usage_pages = std::move(button_usage_pages); + new_device.hidInfo->button_input_groups = std::move(button_input_groups); + new_device.hidInfo->output_report.resize(caps.OutputReportByteLength); + size_t max_button_output_count = 0; + for (const auto &button_output_state : new_device.hidInfo->button_output_states) { + if (button_output_state.size() > max_button_output_count) { + max_button_output_count = button_output_state.size(); + } + } + new_device.hidInfo->button_output_usages.reserve(max_button_output_count); + new_device.hidInfo->button_output_usages_off.reserve(max_button_output_count); new_device.hidInfo->value_states = std::move(value_states); new_device.hidInfo->value_states_raw = std::move(value_states_raw); new_device.hidInfo->value_output_states = std::move(value_output_states); @@ -1573,11 +1606,17 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc( if (!data_size) { break; } - std::shared_ptr data((RAWINPUT *) new char[data_size]{}); + thread_local std::vector data_buffer; + const size_t data_count = + (data_size + sizeof(RAWINPUT) - 1) / sizeof(RAWINPUT); + if (data_buffer.size() < data_count) { + data_buffer.resize(data_count); + } + auto data = data_buffer.data(); if (GetRawInputData( (HRAWINPUT) lParam, RID_INPUT, - data.get(), + data, &data_size, sizeof(RAWINPUTHEADER)) != data_size) { break; @@ -1791,17 +1830,13 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc( + (size_t) hid_report_index * data_hid.dwSizeHid; // parse reports - for (const auto &pair : device.hidInfo->button_usage_pages) { - const auto usage_page = pair.first.first; - const auto link_collection = pair.first.second; - const auto button_count = pair.second; - - ULONG usages_length = button_count; - std::vector usages(static_cast(usages_length)); + for (auto &input_group : device.hidInfo->button_input_groups) { + auto &usages = input_group.usages; + ULONG usages_length = static_cast(usages.size()); if (HidP_GetUsages( HidP_Input, - usage_page, - link_collection, + input_group.usage_page, + input_group.link_collection, usages.data(), &usages_length, reinterpret_cast(device.hidInfo->preparsed_data.get()), @@ -1819,29 +1854,22 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc( // log_info( // "rawinput", // "processing HID input for device {}, usage page {:x} and link collection {:x} with {} buttons, got {} reports", - // device.desc, - // usage_page, link_collection, button_count, usages_length); + // device.desc, input_group.usage_page, + // input_group.link_collection, usages.size(), usages_length); // buttons - for (size_t cap_num = 0; cap_num < device.hidInfo->button_caps_list.size(); cap_num++) { + for (const size_t cap_num : input_group.cap_indices) { auto &button_caps = device.hidInfo->button_caps_list[cap_num]; auto &button_states = device.hidInfo->button_states[cap_num]; auto &button_down = device.hidInfo->button_down[cap_num]; auto &button_up = device.hidInfo->button_up[cap_num]; - - // is this the right usage page and link collection? - if (button_caps.UsagePage != usage_page || button_caps.LinkCollection != link_collection) { - continue; - } + auto &new_states = device.hidInfo->button_report_states[cap_num]; // get button count int button_count = button_caps.Range.UsageMax - button_caps.Range.UsageMin + 1; - if (button_count <= 0) { - continue; - } // update buttons - std::vector new_states(button_count); + std::fill(new_states.begin(), new_states.end(), 0); for (ULONG usage_num = 0; usage_num < usages_length; usage_num++) { if (usages[usage_num] < button_caps.Range.UsageMin || usages[usage_num] > button_caps.Range.UsageMax) { @@ -1852,17 +1880,18 @@ LRESULT CALLBACK rawinput::RawInputManager::input_wnd_proc( // guard against some buggy device sending an event for a usage below UsageMin if (usage < button_count) { - new_states[usage] = true; + new_states[usage] = 1; } } for (int button_num = 0; button_num < button_count; button_num++) { - if (!new_states[button_num] && button_states[button_num]) { + const bool new_state = new_states[button_num] != 0; + if (!new_state && button_states[button_num]) { device.updated = true; - button_states[button_num] = new_states[button_num]; + button_states[button_num] = new_state; button_down[button_num] = input_time; - } else if (new_states[button_num] && !button_states[button_num]) { + } else if (new_state && !button_states[button_num]) { device.updated = true; - button_states[button_num] = new_states[button_num]; + button_states[button_num] = new_state; button_up[button_num] = input_time; } } @@ -2017,8 +2046,10 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up switch (hid->driver) { case HIDDriver::Default: { - // allocate report - CHAR *report_data = new CHAR[hid->caps.OutputReportByteLength] {}; + auto &report_data = hid->output_report; + auto &usage_list = hid->button_output_usages; + auto &usage_off_list = hid->button_output_usages_off; + std::fill(report_data.begin(), report_data.end(), 0); // set buttons for (size_t cap_no = 0; cap_no < hid->button_output_caps_list.size(); cap_no++) { @@ -2026,10 +2057,8 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up auto &button_state_list = hid->button_output_states[cap_no]; // determine which buttons to turn on - std::vector usage_list; - std::vector usage_off_list; - usage_list.reserve(button_state_list.size()); - usage_off_list.reserve(button_state_list.size()); + usage_list.clear(); + usage_off_list.clear(); for (size_t state_no = 0; state_no < button_state_list.size(); state_no++) { if (button_state_list[state_no]) { usage_list.push_back(button_cap.Range.UsageMin + (USAGE) state_no); @@ -2044,15 +2073,18 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up HidP_Output, button_cap.UsagePage, button_cap.LinkCollection, - &usage_list[0], + usage_list.data(), &usage_list_length, reinterpret_cast(hid->preparsed_data.get()), - report_data, + report_data.data(), hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) { // flush report - HidD_SetOutputReport(hid->handle, report_data, hid->caps.OutputReportByteLength); - memset(report_data, 0, hid->caps.OutputReportByteLength); + HidD_SetOutputReport( + hid->handle, + report_data.data(), + hid->caps.OutputReportByteLength); + std::fill(report_data.begin(), report_data.end(), 0); } // clear the buttons @@ -2061,22 +2093,22 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up HidP_Output, button_cap.UsagePage, button_cap.LinkCollection, - &usage_off_list[0], + usage_off_list.data(), &usage_off_list_length, reinterpret_cast(hid->preparsed_data.get()), - report_data, + report_data.data(), hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) { // flush report DWORD written_bytes = 0; WriteFile( hid->handle, - reinterpret_cast(report_data), + report_data.data(), hid->caps.OutputReportByteLength, &written_bytes, nullptr ); - memset(report_data, 0, hid->caps.OutputReportByteLength); + std::fill(report_data.begin(), report_data.end(), 0); } } @@ -2105,19 +2137,19 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up value_cap.NotRange.Usage, static_cast(usage_value), reinterpret_cast(hid->preparsed_data.get()), - report_data, + report_data.data(), hid->caps.OutputReportByteLength) == HIDP_STATUS_INCOMPATIBLE_REPORT_ID) { // flush report DWORD written_bytes = 0; WriteFile( hid->handle, - reinterpret_cast(report_data), + report_data.data(), hid->caps.OutputReportByteLength, &written_bytes, nullptr ); - memset(report_data, 0, hid->caps.OutputReportByteLength); + std::fill(report_data.begin(), report_data.end(), 0); } } @@ -2151,15 +2183,12 @@ void rawinput::RawInputManager::device_write_output(Device *device, bool only_up DWORD written_bytes = 0; WriteFile( hid->handle, - reinterpret_cast(report_data), + report_data.data(), hid->caps.OutputReportByteLength, &written_bytes, nullptr ); - // delete report - delete[] report_data; - break; } case HIDDriver::PacDrive: { diff --git a/src/spice2x/rawinput/touch.cpp b/src/spice2x/rawinput/touch.cpp index 44adf1f..6ab587a 100644 --- a/src/spice2x/rawinput/touch.cpp +++ b/src/spice2x/rawinput/touch.cpp @@ -319,7 +319,8 @@ namespace rawinput::touch { } // iterate all input data and get touch points - std::vector touch_points; + thread_local std::vector touch_points; + touch_points.clear(); touch_points.reserve(touch.elements_x.size()); for (size_t i = 0; i < touch.elements_x.size(); i++) { @@ -424,9 +425,15 @@ namespace rawinput::touch { } // process touch points - std::vector touch_removes; - std::vector touch_writes; - std::vector touch_modifications; + thread_local std::vector touch_removes; + thread_local std::vector touch_writes; + thread_local std::vector touch_modifications; + touch_removes.clear(); + touch_writes.clear(); + touch_modifications.clear(); + touch_removes.reserve(touch.touch_points.size() + touch_points.size()); + touch_writes.reserve(touch_points.size()); + touch_modifications.reserve(touch_points.size()); // drop every touch point with the given id (marking it as released) auto remove_touch_point = [&] (DWORD id) { @@ -581,7 +588,9 @@ namespace rawinput::touch { auto deadline = get_system_milliseconds() - 50; // check touch points - std::vector touch_removes; + thread_local std::vector touch_removes; + touch_removes.clear(); + touch_removes.reserve(touch.touch_points.size()); auto touch_it = touch.touch_points.begin(); while (touch_it != touch.touch_points.end()) { auto &hid_tp = *touch_it; diff --git a/src/spice2x/reader/reader.cpp b/src/spice2x/reader/reader.cpp index 690ad01..3eb3571 100644 --- a/src/spice2x/reader/reader.cpp +++ b/src/spice2x/reader/reader.cpp @@ -1,13 +1,13 @@ #include "reader.h" +#include +#include #include #include -#include #include #include "util/logging.h" #include "misc/eamuse.h" -#include "util/precise_timer.h" #include "util/utils.h" #include "structuredmessage.h" @@ -218,8 +218,6 @@ bool Reader::set_comm_state(DWORD BaudRate) { } bool Reader::wait_for_handshake() { - timeutils::PreciseSleepTimer timer; - // baud rates DWORD baud_rates[] = { CBR_57600, CBR_38400, CBR_19200, CBR_9600 }; @@ -270,7 +268,7 @@ bool Reader::wait_for_handshake() { } // sleep - timer.sleep(50); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } log_warning("reader", "{}: no handshake received for {} baud", this->port, baud_rates[i]); @@ -407,7 +405,6 @@ void start_reader_thread(const std::string &port, int id) { READER_THREAD_RUNNING = true; READER_THREADS.push_back(new std::thread([port, id]() { log_info("reader", "{}: starting reader thread", port); - timeutils::PreciseSleepTimer timer; while (READER_THREAD_RUNNING) { @@ -445,22 +442,21 @@ void start_reader_thread(const std::string &port, int id) { } if (did_read_card) { - timer.sleep(2500); + std::this_thread::sleep_for(std::chrono::milliseconds(2500)); } - timer.sleep(20); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); } } // sleep between reader connection retries if (READER_THREAD_RUNNING) - timer.sleep(5000); + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); } })); // wait for thread to start - timeutils::PreciseSleepTimer timer; - timer.sleep(10); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } void stop_reader_thread() {