diff --git a/src/audio.cpp b/src/audio.cpp index a24fd4d7..db50dec4 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -91,6 +91,7 @@ namespace audio { } // Encoding takes place on this thread + platf::set_thread_name("audio::encode"); platf::adjust_thread_priority(platf::thread_priority_e::high); opus_t opus {opus_multistream_encoder_create( diff --git a/src/confighttp.cpp b/src/confighttp.cpp index f7dc1f1a..197fcf51 100644 --- a/src/confighttp.cpp +++ b/src/confighttp.cpp @@ -1172,6 +1172,7 @@ namespace confighttp { } void start() { + platf::set_thread_name("confighttp"); auto shutdown_event = mail::man->event(mail::shutdown); auto port_https = net::map_port(PORT_HTTPS); @@ -1224,6 +1225,7 @@ namespace confighttp { auto accept_and_run = [&](auto *server) { try { + platf::set_thread_name("confighttp::tcp"); server->start([](unsigned short port) { BOOST_LOG(info) << "Configuration UI available at [https://localhost:"sv << port << "]"; }); diff --git a/src/main.cpp b/src/main.cpp index 79e770c1..20a733d8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -207,6 +207,7 @@ int main(int argc, char *argv[]) { auto session_monitor_join_thread_future = session_monitor_join_thread_promise.get_future(); std::thread session_monitor_thread([&]() { + platf::set_thread_name("session_monitor"); session_monitor_join_thread_promise.set_value_at_thread_exit(); WNDCLASSA wnd_class {}; diff --git a/src/nvhttp.cpp b/src/nvhttp.cpp index bf88c922..4d8a87b4 100644 --- a/src/nvhttp.cpp +++ b/src/nvhttp.cpp @@ -1056,6 +1056,7 @@ namespace nvhttp { } void start() { + platf::set_thread_name("nvhttp"); auto shutdown_event = mail::man->event(mail::shutdown); auto port_http = net::map_port(PORT_HTTP); @@ -1173,6 +1174,8 @@ namespace nvhttp { auto accept_and_run = [&](auto *http_server) { try { + std::string name = "nvhttp::" + std::to_string(http_server->config.port); + platf::set_thread_name(name); http_server->start(); } catch (boost::system::system_error &err) { // It's possible the exception gets thrown after calling http_server->stop() from a different thread diff --git a/src/platform/common.h b/src/platform/common.h index 168f0804..274bbbdc 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -613,6 +613,12 @@ namespace platf { }; void adjust_thread_priority(thread_priority_e priority); + /** + * @brief Name the current thread for use with development tools. + * @note On Linux this will be truncated after 15 characters. + */ + void set_thread_name(const std::string &name); + void enable_mouse_keys(); // Allow OS-specific actions to be taken to prepare for streaming diff --git a/src/platform/linux/audio.cpp b/src/platform/linux/audio.cpp index a2df7bb0..9fefcc86 100644 --- a/src/platform/linux/audio.cpp +++ b/src/platform/linux/audio.cpp @@ -236,6 +236,7 @@ namespace platf { worker = std::thread { [](loop_t::pointer loop) { int retval; + platf::set_thread_name("audio::pulseaudio"); auto status = pa_mainloop_run(loop, &retval); if (status < 0) { diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index 485d7958..7d3810e5 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -327,6 +327,10 @@ namespace platf { // Unimplemented } + void set_thread_name(const std::string &name) { + pthread_setname_np(pthread_self(), name.c_str()); + } + void enable_mouse_keys() { // Unimplemented } diff --git a/src/platform/linux/publish.cpp b/src/platform/linux/publish.cpp index a2bac72f..4ea9a8bc 100644 --- a/src/platform/linux/publish.cpp +++ b/src/platform/linux/publish.cpp @@ -423,6 +423,8 @@ namespace platf::publish { return nullptr; } + platf::set_thread_name("publish::avahi"); + int avhi_error; poll.reset(avahi::simple_poll_new()); diff --git a/src/platform/macos/misc.mm b/src/platform/macos/misc.mm index 2e1c2870..c678d80c 100644 --- a/src/platform/macos/misc.mm +++ b/src/platform/macos/misc.mm @@ -19,6 +19,7 @@ #include #include #include +#include // lib includes #include @@ -211,7 +212,32 @@ namespace platf { } void adjust_thread_priority(thread_priority_e priority) { - // Unimplemented + qos_class_t mac_priority; + + switch (priority) { + case thread_priority_e::low: + mac_priority = QOS_CLASS_UTILITY; + break; + case thread_priority_e::normal: + mac_priority = QOS_CLASS_DEFAULT; + break; + case thread_priority_e::high: + mac_priority = QOS_CLASS_USER_INITIATED; + break; + case thread_priority_e::critical: + mac_priority = QOS_CLASS_USER_INTERACTIVE; + break; + default: + BOOST_LOG(error) << "Unknown thread priority: "sv << (int) priority; + return; + } + + // https://github.com/apple/darwin-libpthread/blob/main/include/sys/qos.h + pthread_set_qos_class_self_np(mac_priority, 0); + } + + void set_thread_name(const std::string &name) { + pthread_setname_np(name.c_str()); } void enable_mouse_keys() { diff --git a/src/platform/macos/publish.cpp b/src/platform/macos/publish.cpp index 0718b784..b962b1d2 100644 --- a/src/platform/macos/publish.cpp +++ b/src/platform/macos/publish.cpp @@ -43,6 +43,7 @@ namespace platf::publish { deinit_t(DNSServiceRef serviceRef): unique_ptr(serviceRef) { _thread = std::thread {[serviceRef, &_stopRequested = std::as_const(_stopRequested)]() { + platf::set_thread_name("publish::mdns"); const auto socket = DNSServiceRefSockFD(serviceRef); while (!_stopRequested) { auto fdset = fd_set {}; diff --git a/src/platform/windows/misc.cpp b/src/platform/windows/misc.cpp index 18b68f7a..63cf8ac1 100644 --- a/src/platform/windows/misc.cpp +++ b/src/platform/windows/misc.cpp @@ -1052,6 +1052,14 @@ namespace platf { } } + void set_thread_name(const std::string &name) { + std::wstring wname = utf_utils::from_utf8(name); + HRESULT hr = SetThreadDescription(GetCurrentThread(), wname.c_str()); + if (FAILED(hr)) { + BOOST_LOG(error) << "SetThreadDescription failed: " << hr; + } + } + void streaming_will_start() { static std::once_flag load_wlanapi_once_flag; std::call_once(load_wlanapi_once_flag, []() { diff --git a/src/rtsp.cpp b/src/rtsp.cpp index 7eda3515..754ada23 100644 --- a/src/rtsp.cpp +++ b/src/rtsp.cpp @@ -1121,6 +1121,7 @@ namespace rtsp_stream { } void start() { + platf::set_thread_name("rtsp"); auto shutdown_event = mail::man->event(mail::shutdown); server.map("OPTIONS"sv, &cmd_option); @@ -1138,6 +1139,7 @@ namespace rtsp_stream { } std::thread rtsp_thread {[&shutdown_event] { + platf::set_thread_name("rtsp::handler"); auto broadcast_shutdown_event = mail::man->event(mail::broadcast_shutdown); while (!shutdown_event->peek()) { diff --git a/src/stream.cpp b/src/stream.cpp index 9ad9b772..b92e579e 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1060,6 +1060,7 @@ namespace stream { }); // This thread handles latency-sensitive control messages + platf::set_thread_name("stream::controlBroadcast"); platf::adjust_thread_priority(platf::thread_priority_e::critical); // Check for both the full shutdown event and the shutdown event for this @@ -1189,6 +1190,8 @@ namespace stream { std::array buf[2]; std::function recv_func[2]; + platf::set_thread_name("stream::recv"); + auto populate_peer_to_session = [&]() { while (message_queue_queue->peek()) { auto message_queue_opt = message_queue_queue->pop(); @@ -1271,6 +1274,7 @@ namespace stream { auto video_epoch = std::chrono::steady_clock::now(); // Video traffic is sent on this thread + platf::set_thread_name("stream::videoBroadcast"); platf::adjust_thread_priority(platf::thread_priority_e::high); logging::min_max_avg_periodic_logger frame_processing_latency_logger(debug, "Frame processing latency", "ms"); @@ -1610,6 +1614,7 @@ namespace stream { audio_packet.rtp.ssrc = 0; // Audio traffic is sent on this thread + platf::set_thread_name("stream::audioBroadcast"); platf::adjust_thread_priority(platf::thread_priority_e::high); while (auto packet = packets->pop()) { @@ -1848,6 +1853,7 @@ namespace stream { } void videoThread(session_t *session) { + platf::set_thread_name("session::video"); auto fg = util::fail_guard([&]() { session::stop(*session); }); @@ -1869,6 +1875,7 @@ namespace stream { } void audioThread(session_t *session) { + platf::set_thread_name("session::audio"); auto fg = util::fail_guard([&]() { session::stop(*session); }); diff --git a/src/system_tray.cpp b/src/system_tray.cpp index 7d938bbb..78143704 100644 --- a/src/system_tray.cpp +++ b/src/system_tray.cpp @@ -305,6 +305,7 @@ namespace system_tray { // Threading functions available on all platforms static void tray_thread_worker() { + platf::set_thread_name("system_tray"); BOOST_LOG(info) << "System tray thread started"sv; // Initialize the tray in this thread diff --git a/src/thread_pool.h b/src/thread_pool.h index e6377b2a..46558ad8 100644 --- a/src/thread_pool.h +++ b/src/thread_pool.h @@ -8,6 +8,7 @@ #include // local includes +#include "platform/common.h" #include "task_pool.h" namespace thread_pool_util { @@ -98,6 +99,7 @@ namespace thread_pool_util { public: void _main() { + platf::set_thread_name("TaskPool::worker"); while (_continue) { if (auto task = this->pop()) { (*task)->run(); diff --git a/src/upnp.cpp b/src/upnp.cpp index 1071cfd9..7fd219c1 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -299,6 +299,7 @@ namespace upnp { * @brief Maintains UPnP port forwarding rules */ void upnp_thread_proc() { + platf::set_thread_name("upnp"); auto shutdown_event = mail::man->event(mail::shutdown); bool mapped = false; IGDdatas data; diff --git a/src/video.cpp b/src/video.cpp index 273c3623..0290fd95 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -1253,6 +1253,7 @@ namespace video { }; // Capture takes place on this thread + platf::set_thread_name("video::capture"); platf::adjust_thread_priority(platf::thread_priority_e::critical); while (capture_ctx_queue->running()) { @@ -2292,6 +2293,7 @@ namespace video { }); // Encoding and capture takes place on this thread + platf::set_thread_name("video::capture_sync"); platf::adjust_thread_priority(platf::thread_priority_e::high); std::vector display_names;