From 0a42b1b26e1609225029f25d7e8bf4d9ad5e133f Mon Sep 17 00:00:00 2001 From: Helge Norberg Date: Fri, 13 Sep 2013 17:06:32 +0200 Subject: [PATCH] * Created custom decklink allocator for reducing memory footprint. * Made sure that more threads have the unstructured exception handler installed (avoids crashing the entire process in case of access violations), and thread naming for more threads. * Ensure that if an exception occurs while rendering the diagnostic window, the window is closed instead of it stopping to respond to window events. --- common/concurrency/executor.h | 4 +- common/diagnostics/graph.cpp | 21 ++- common/exception/win32_exception.cpp | 31 ++++ common/exception/win32_exception.h | 2 + common/memory/page_locked_allocator.h | 2 + .../consumer/blocking_decklink_consumer.cpp | 12 ++ .../decklink/consumer/decklink_consumer.cpp | 27 ++- modules/decklink/decklink.vcxproj | 1 + modules/decklink/decklink.vcxproj.filters | 3 + .../decklink/producer/decklink_producer.cpp | 13 +- modules/decklink/util/decklink_allocator.h | 155 ++++++++++++++++++ modules/decklink/util/util.h | 2 + modules/ffmpeg/ffmpeg.cpp | 3 + modules/flash/producer/FlashAxContainer.cpp | 2 + modules/image/consumer/image_consumer.cpp | 3 + modules/oal/consumer/oal_consumer.cpp | 5 +- modules/ogl/consumer/ogl_consumer.cpp | 5 + .../portaudio/consumer/portaudio_consumer.cpp | 3 + protocol/asio/io_service_manager.cpp | 11 +- protocol/osc/client.cpp | 2 + protocol/util/Thread.cpp | 9 +- protocol/util/Thread.h | 3 - shell/casparcg.config | 2 + shell/main.cpp | 7 +- 24 files changed, 300 insertions(+), 28 deletions(-) create mode 100644 modules/decklink/util/decklink_allocator.h diff --git a/common/concurrency/executor.h b/common/concurrency/executor.h index 7cdc742d6..27fd5caa7 100644 --- a/common/concurrency/executor.h +++ b/common/concurrency/executor.h @@ -251,8 +251,8 @@ private: void run() // noexcept { - win32_exception::install_handler(); - detail::SetThreadName(GetCurrentThreadId(), name_.c_str()); + win32_exception::ensure_handler_installed_for_thread(name_.c_str()); + while(is_running_) { try diff --git a/common/diagnostics/graph.cpp b/common/diagnostics/graph.cpp index 542008e3b..3c7da27c3 100644 --- a/common/diagnostics/graph.cpp +++ b/common/diagnostics/graph.cpp @@ -140,10 +140,23 @@ private: return; } } - glClear(GL_COLOR_BUFFER_BIT); - window_->Draw(*this); - window_->Display(); - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + try + { + glClear(GL_COLOR_BUFFER_BIT); + window_->Draw(*this); + window_->Display(); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + } + catch (...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + CASPAR_LOG(error) + << L"Closing diag window due to error during rendering"; + window_.reset(); + return; + } + executor_.begin_invoke([this]{tick();}); } diff --git a/common/exception/win32_exception.cpp b/common/exception/win32_exception.cpp index e0338c592..bd983c66d 100644 --- a/common/exception/win32_exception.cpp +++ b/common/exception/win32_exception.cpp @@ -21,19 +21,50 @@ #include "../stdafx.h" +#include + #include "win32_exception.h" #include "../log/log.h" +#include "../concurrency/executor.h" namespace caspar { +bool& installed_for_thread() +{ + static boost::thread_specific_ptr installed; + + auto for_thread = installed.get(); + + if (!for_thread) + { + for_thread = new bool(false); + installed.reset(for_thread); + } + + return *for_thread; +} + void win32_exception::install_handler() { //#ifndef _DEBUG _set_se_translator(win32_exception::Handler); + installed_for_thread() = true; //#endif } +void win32_exception::ensure_handler_installed_for_thread( + const char* thread_description) +{ + if (!installed_for_thread()) + { + install_handler(); + + if (thread_description) + detail::SetThreadName(GetCurrentThreadId(), thread_description); + } +} + void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo) { switch(errorCode) { diff --git a/common/exception/win32_exception.h b/common/exception/win32_exception.h index 8cfe515bd..2f9c85964 100644 --- a/common/exception/win32_exception.h +++ b/common/exception/win32_exception.h @@ -35,6 +35,8 @@ class win32_exception : public std::exception public: typedef const void* address; static void install_handler(); + static void ensure_handler_installed_for_thread( + const char* thread_description = nullptr); address location() const { return location_; } unsigned int error_code() const { return errorCode_; } diff --git a/common/memory/page_locked_allocator.h b/common/memory/page_locked_allocator.h index 44697f3a9..789679d59 100644 --- a/common/memory/page_locked_allocator.h +++ b/common/memory/page_locked_allocator.h @@ -84,6 +84,8 @@ public: pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } page_locked_allocator& operator=(const page_locked_allocator&) { return *this; } + bool operator!=(const page_locked_allocator&) const { return false; } + bool operator==(const page_locked_allocator&) const { return true; } void construct(pointer p, const T& val) { new ((T*) p) T(val); } void destroy(pointer p) { p->~T(); } diff --git a/modules/decklink/consumer/blocking_decklink_consumer.cpp b/modules/decklink/consumer/blocking_decklink_consumer.cpp index 573c171b2..b12ec63ca 100644 --- a/modules/decklink/consumer/blocking_decklink_consumer.cpp +++ b/modules/decklink/consumer/blocking_decklink_consumer.cpp @@ -24,6 +24,7 @@ #include "decklink_consumer.h" #include "../util/util.h" +#include "../util/decklink_allocator.h" #include "../interop/DeckLinkAPI_h.h" @@ -59,6 +60,7 @@ struct blocking_decklink_consumer : boost::noncopyable const int channel_index_; const configuration config_; + std::unique_ptr allocator_; CComPtr decklink_; CComQIPtr output_; CComQIPtr keyer_; @@ -142,6 +144,16 @@ public: void enable_video(BMDDisplayMode display_mode) { + if (config_.custom_allocator) + { + allocator_.reset(new thread_safe_decklink_allocator(print())); + + if (FAILED(output_->SetVideoOutputFrameMemoryAllocator(allocator_.get()))) + BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not set custom memory allocator.")); + + CASPAR_LOG(info) << print() << L" Using custom allocator."; + } + if(FAILED(output_->EnableVideoOutput(display_mode, bmdVideoOutputFlagDefault))) BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not enable video output.")); } diff --git a/modules/decklink/consumer/decklink_consumer.cpp b/modules/decklink/consumer/decklink_consumer.cpp index 11b6fd7f5..8b30bd257 100644 --- a/modules/decklink/consumer/decklink_consumer.cpp +++ b/modules/decklink/consumer/decklink_consumer.cpp @@ -24,6 +24,7 @@ #include "decklink_consumer.h" #include "../util/util.h" +#include "../util/decklink_allocator.h" #include "../interop/DeckLinkAPI_h.h" @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -50,10 +52,11 @@ namespace caspar { namespace decklink { struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable -{ +{ const int channel_index_; const configuration config_; + std::unique_ptr allocator_; CComPtr decklink_; CComQIPtr output_; CComQIPtr keyer_; @@ -172,6 +175,16 @@ public: void enable_video(BMDDisplayMode display_mode) { + if (config_.custom_allocator) + { + allocator_.reset(new thread_safe_decklink_allocator(print())); + + if (FAILED(output_->SetVideoOutputFrameMemoryAllocator(allocator_.get()))) + BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not set custom memory allocator.")); + + CASPAR_LOG(info) << print() << L" Using custom allocator."; + } + if(FAILED(output_->EnableVideoOutput(display_mode, bmdVideoOutputFlagDefault))) BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not enable video output.")); @@ -200,6 +213,7 @@ public: STDMETHOD(ScheduledFrameCompleted(IDeckLinkVideoFrame* completed_frame, BMDOutputFrameCompletionResult result)) { + win32_exception::ensure_handler_installed_for_thread("decklink-ScheduledFrameCompleted"); if(!is_running_) return E_FAIL; @@ -243,6 +257,8 @@ public: STDMETHOD(RenderAudioSamples(BOOL preroll)) { + win32_exception::ensure_handler_installed_for_thread("decklink-RenderAudioSamples"); + if(!is_running_) return E_FAIL; @@ -510,10 +526,11 @@ safe_ptr create_consumer(const boost::property_tree::wptre else if(latency == L"normal") config.latency = configuration::normal_latency; - config.key_only = ptree.get(L"key-only", config.key_only); - config.device_index = ptree.get(L"device", config.device_index); - config.embedded_audio = ptree.get(L"embedded-audio", config.embedded_audio); - config.base_buffer_depth = ptree.get(L"buffer-depth", config.base_buffer_depth); + config.key_only = ptree.get(L"key-only", config.key_only); + config.device_index = ptree.get(L"device", config.device_index); + config.embedded_audio = ptree.get(L"embedded-audio", config.embedded_audio); + config.base_buffer_depth = ptree.get(L"buffer-depth", config.base_buffer_depth); + config.custom_allocator = ptree.get(L"custom-allocator", config.custom_allocator); config.audio_layout = core::default_channel_layout_repository().get_by_name( boost::to_upper_copy(ptree.get(L"channel-layout", L"STEREO"))); diff --git a/modules/decklink/decklink.vcxproj b/modules/decklink/decklink.vcxproj index 1b5f9e818..7b93aaf92 100644 --- a/modules/decklink/decklink.vcxproj +++ b/modules/decklink/decklink.vcxproj @@ -259,6 +259,7 @@ + diff --git a/modules/decklink/decklink.vcxproj.filters b/modules/decklink/decklink.vcxproj.filters index 709b5cd17..94c91b2ef 100644 --- a/modules/decklink/decklink.vcxproj.filters +++ b/modules/decklink/decklink.vcxproj.filters @@ -58,5 +58,8 @@ source\consumer + + source\util + \ No newline at end of file diff --git a/modules/decklink/producer/decklink_producer.cpp b/modules/decklink/producer/decklink_producer.cpp index d88834d32..02a98663d 100644 --- a/modules/decklink/producer/decklink_producer.cpp +++ b/modules/decklink/producer/decklink_producer.cpp @@ -25,6 +25,7 @@ #include "../interop/DeckLinkAPI_h.h" #include "../util/util.h" +#include "../util/decklink_allocator.h" #include "../../ffmpeg/producer/filter/filter.h" #include "../../ffmpeg/producer/util/util.h" @@ -34,6 +35,7 @@ #include #include #include +#include #include #include @@ -86,6 +88,7 @@ class decklink_producer : boost::noncopyable, public IDeckLinkInputCallback boost::timer tick_timer_; boost::timer frame_timer_; + std::unique_ptr allocator_; CComPtr decklink_; CComQIPtr input_; CComQIPtr attributes_; @@ -148,7 +151,14 @@ public: diagnostics::register_graph(graph_); auto display_mode = get_display_mode(input_, format_desc_.format, bmdFormat8BitYUV, bmdVideoInputFlagDefault); - + + allocator_.reset(new thread_safe_decklink_allocator(print())); + + if(FAILED(input_->SetVideoInputFrameMemoryAllocator(allocator_.get()))) + BOOST_THROW_EXCEPTION(caspar_exception() + << msg_info(narrow(print()) + " Could not enable use of custom allocator.") + << boost::errinfo_api_function("SetVideoInputFrameMemoryAllocator")); + // NOTE: bmdFormat8BitARGB is currently not supported by any decklink card. (2011-05-08) if(FAILED(input_->EnableVideoInput(display_mode, bmdFormat8BitYUV, bmdVideoInputFlagDefault))) BOOST_THROW_EXCEPTION(caspar_exception() @@ -191,6 +201,7 @@ public: virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio) { + win32_exception::ensure_handler_installed_for_thread("decklink-VideoInputFrameArrived"); if(!video) return S_OK; diff --git a/modules/decklink/util/decklink_allocator.h b/modules/decklink/util/decklink_allocator.h new file mode 100644 index 000000000..35cc4886f --- /dev/null +++ b/modules/decklink/util/decklink_allocator.h @@ -0,0 +1,155 @@ +/* +* Copyright 2013 Sveriges Television AB http://casparcg.com/ +* +* This file is part of CasparCG (www.casparcg.com). +* +* CasparCG is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* CasparCG is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with CasparCG. If not, see . +* +* Author: Helge Norberg, helge.norberg@svt.se +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +//#include +#include + +#include "../interop/DeckLinkAPI_h.h" + +namespace caspar { namespace decklink { + +class thread_safe_decklink_allocator : public IDeckLinkMemoryAllocator +{ + typedef std::shared_ptr< + std::vector>> buffer; + + std::wstring print_; + tbb::concurrent_unordered_map> free_; + tbb::concurrent_unordered_map buffers_; + tbb::atomic total_allocated_; + tbb::atomic total_calls_; +public: + thread_safe_decklink_allocator(const std::wstring& print) + : print_(print) + { + total_allocated_ = 0; + total_calls_ = 0; + } + + ~thread_safe_decklink_allocator() + { + CASPAR_LOG(debug) + << print_ + << L" allocated a total of " << total_allocated_ << L" bytes" + << L" and was called " << total_calls_ << L" times" + << L" during playout"; + } + + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer( + unsigned long buffer_size, void** allocated_buffer) + { + win32_exception::ensure_handler_installed_for_thread( + "decklink-allocator"); + + try + { + *allocated_buffer = allocate_buffer(buffer_size); + } + catch (const std::bad_alloc&) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + + return E_OUTOFMEMORY; + } + + return S_OK; + } + + void* allocate_buffer(unsigned long buffer_size) + { + ++total_calls_; + void* result; + + if (!free_[buffer_size].try_pop(result)) + { + auto buf = std::make_shared>>(buffer_size); + result = buf->data(); + buffers_.insert(std::make_pair(result, buf)); + + total_allocated_ += buffer_size; + + CASPAR_LOG(debug) + << print_ + << L" allocated buffer of size: " << buffer_size + << L" for a total of " << total_allocated_; + } + + return result; + } + + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* b) + { + win32_exception::ensure_handler_installed_for_thread( + "decklink-allocator"); + + try + { + release_buffer(b); + } + catch (const std::bad_alloc&) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + } + + return S_OK; + } + + void release_buffer(void* b) + { + auto buf = buffers_[b]; + + CASPAR_VERIFY(buf); + + free_[buf->size()].push(b); + } + + virtual HRESULT STDMETHODCALLTYPE Commit() + { + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Decommit() + { + return S_OK; + } + + STDMETHOD (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;} + STDMETHOD_(ULONG, AddRef()) {return 1;} + STDMETHOD_(ULONG, Release()) {return 1;} +}; + +}} diff --git a/modules/decklink/util/util.h b/modules/decklink/util/util.h index 51865cb42..d4abe5cb6 100644 --- a/modules/decklink/util/util.h +++ b/modules/decklink/util/util.h @@ -317,6 +317,7 @@ struct configuration latency_t latency; bool key_only; size_t base_buffer_depth; + bool custom_allocator; configuration() : device_index(1) @@ -326,6 +327,7 @@ struct configuration , latency(default_latency) , key_only(false) , base_buffer_depth(3) + , custom_allocator(true) { } diff --git a/modules/ffmpeg/ffmpeg.cpp b/modules/ffmpeg/ffmpeg.cpp index ad9a1becc..68f51c3c9 100644 --- a/modules/ffmpeg/ffmpeg.cpp +++ b/modules/ffmpeg/ffmpeg.cpp @@ -25,6 +25,7 @@ #include "producer/ffmpeg_producer.h" #include +#include #include #include @@ -55,6 +56,7 @@ namespace caspar { namespace ffmpeg { int ffmpeg_lock_callback(void **mutex, enum AVLockOp op) { + win32_exception::ensure_handler_installed_for_thread("ffmpeg-thread"); if(!mutex) return 0; @@ -193,6 +195,7 @@ std::shared_ptr temporary_disable_logging_for_thread(bool disable) void log_for_thread(void* ptr, int level, const char* fmt, va_list vl) { + win32_exception::ensure_handler_installed_for_thread("ffmpeg-thread"); //if (get_disable_logging_for_thread().get() == nullptr) // It does not matter what the value of the bool is log_callback(ptr, level, fmt, vl); } diff --git a/modules/flash/producer/FlashAxContainer.cpp b/modules/flash/producer/FlashAxContainer.cpp index a08416ddc..40e35dcc6 100644 --- a/modules/flash/producer/FlashAxContainer.cpp +++ b/modules/flash/producer/FlashAxContainer.cpp @@ -453,6 +453,7 @@ DEFINE_GUID2(IID_IDirectDraw7,0x15e65ec0,0x3b9c,0x11d2,0xb9,0x2f,0x00,0x60,0x97, /////////////////// HRESULT STDMETHODCALLTYPE FlashAxContainer::QueryService( REFGUID rsid, REFIID riid, void** ppvObj) { + win32_exception::ensure_handler_installed_for_thread("flash-player-thread"); // ATLTRACE(_T("IServiceProvider::QueryService\n")); //the flashcontrol asks for an interface {618F8AD4-8B7A-11D0-8FCC-00C04FD9189D}, this is IID for a DirectDraw3 object @@ -600,6 +601,7 @@ void FlashAxContainer::EnterFullscreen() void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request) { + win32_exception::ensure_handler_installed_for_thread("flash-player-thread"); std::wstring str(request); if(str.find(TEXT("DisplayedTemplate")) != std::wstring::npos) { diff --git a/modules/image/consumer/image_consumer.cpp b/modules/image/consumer/image_consumer.cpp index 21fdafb0d..7c9b8215e 100644 --- a/modules/image/consumer/image_consumer.cpp +++ b/modules/image/consumer/image_consumer.cpp @@ -21,6 +21,7 @@ #include "image_consumer.h" +#include #include #include #include @@ -90,6 +91,8 @@ public: boost::thread async([format_desc, frame, filename] { + win32_exception::ensure_handler_installed_for_thread("image-consumer-thread"); + try { auto filename2 = filename; diff --git a/modules/oal/consumer/oal_consumer.cpp b/modules/oal/consumer/oal_consumer.cpp index 528176055..629598c4b 100644 --- a/modules/oal/consumer/oal_consumer.cpp +++ b/modules/oal/consumer/oal_consumer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -205,7 +206,9 @@ public: // oal_consumer virtual bool OnGetData(sf::SoundStream::Chunk& data) override - { + { + win32_exception::ensure_handler_installed_for_thread( + "sfml-audio-thread"); std::shared_ptr> audio_data; if (!input_.try_pop(audio_data)) diff --git a/modules/ogl/consumer/ogl_consumer.cpp b/modules/ogl/consumer/ogl_consumer.cpp index b4f950f7c..8e7277527 100644 --- a/modules/ogl/consumer/ogl_consumer.cpp +++ b/modules/ogl/consumer/ogl_consumer.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include @@ -273,6 +275,9 @@ public: void run() { + win32_exception::ensure_handler_installed_for_thread( + "ogl-consumer-thread"); + try { init(); diff --git a/modules/portaudio/consumer/portaudio_consumer.cpp b/modules/portaudio/consumer/portaudio_consumer.cpp index 2708f1257..bbb645498 100644 --- a/modules/portaudio/consumer/portaudio_consumer.cpp +++ b/modules/portaudio/consumer/portaudio_consumer.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -296,6 +297,8 @@ int callback( PaStreamCallbackFlags status_flags, void* user_data) { + win32_exception::ensure_handler_installed_for_thread( + "portaudio-callback-thread"); auto consumer = static_cast(user_data); consumer->write_samples( diff --git a/protocol/asio/io_service_manager.cpp b/protocol/asio/io_service_manager.cpp index 3261c1816..0845d8fb4 100644 --- a/protocol/asio/io_service_manager.cpp +++ b/protocol/asio/io_service_manager.cpp @@ -28,6 +28,8 @@ #include #include +#include + namespace caspar { namespace protocol { namespace asio { struct io_service_manager::impl @@ -40,10 +42,17 @@ struct io_service_manager::impl impl() : work_(new boost::asio::io_service::work(service_)) - , thread_(std::bind(&boost::asio::io_service::run, &service_)) + , thread_([this] { run(); }) { } + void run() + { + win32_exception::ensure_handler_installed_for_thread("asio-thread"); + + service_.run(); + } + ~impl() { work_.reset(); diff --git a/protocol/osc/client.cpp b/protocol/osc/client.cpp index 85723b706..0077756fb 100644 --- a/protocol/osc/client.cpp +++ b/protocol/osc/client.cpp @@ -27,6 +27,7 @@ #include "oscpack/oscOutboundPacketStream.h" #include +#include #include #include @@ -127,6 +128,7 @@ public: void on_next(const core::monitor::message& msg) { + win32_exception::ensure_handler_installed_for_thread("agents-thread"); auto data_ptr = make_safe>(write_osc_event(msg)); tbb::spin_mutex::scoped_lock lock(endpoints_mutex_); diff --git a/protocol/util/Thread.cpp b/protocol/util/Thread.cpp index 39199f6d8..763f2bbc8 100644 --- a/protocol/util/Thread.cpp +++ b/protocol/util/Thread.cpp @@ -51,8 +51,6 @@ Event::~Event() CloseHandle(handle_); } -bool Thread::static_bInstallWin32ExceptionHandler_ = true; - Thread::Thread() : pRunnable_(0), hThread_(0), stopEvent_(TRUE, FALSE), timeout_(10000) { } @@ -108,15 +106,10 @@ bool Thread::Stop(bool bWait) { return returnValue; } -void Thread::EnableWin32ExceptionHandler(bool bEnable) { - static_bInstallWin32ExceptionHandler_ = bEnable; -} - DWORD WINAPI Thread::ThreadEntrypoint(LPVOID pParam) { Thread* pThis = reinterpret_cast(pParam); - if(Thread::static_bInstallWin32ExceptionHandler_) - win32_exception::install_handler(); + win32_exception::install_handler(); _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); diff --git a/protocol/util/Thread.h b/protocol/util/Thread.h index 46a00dbc7..caaef1946 100644 --- a/protocol/util/Thread.h +++ b/protocol/util/Thread.h @@ -73,8 +73,6 @@ public: bool IsRunning(); - static void EnableWin32ExceptionHandler(bool bEnable); - void SetTimeout(DWORD timeout) { timeout_ = timeout; } @@ -92,7 +90,6 @@ private: Event stopEvent_; DWORD timeout_; - static bool static_bInstallWin32ExceptionHandler_; }; } \ No newline at end of file diff --git a/shell/casparcg.config b/shell/casparcg.config index 5bb8f6944..6b6db1f83 100644 --- a/shell/casparcg.config +++ b/shell/casparcg.config @@ -73,6 +73,7 @@ external [external|internal|default] false [true|false] 3 [1..] + true [true|false] [1..] @@ -80,6 +81,7 @@ stereo [mono|stereo|dts|dolbye|dolbydigital|smpte|passthru] external [external|internal|default] false [true|false] + true [true|false] [1..] diff --git a/shell/main.cpp b/shell/main.cpp index 36721b83e..382e3c307 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -211,7 +211,7 @@ int main(int argc, wchar_t* argv[]) SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); // Install structured exception handler. - caspar::win32_exception::install_handler(); + caspar::win32_exception::ensure_handler_installed_for_thread("main-thread"); // Increase time precision. This will increase accuracy of function like Sleep(1) from 10 ms to 1 ms. struct inc_prec @@ -226,8 +226,7 @@ int main(int argc, wchar_t* argv[]) tbb_thread_installer(){observe(true);} void on_scheduler_entry(bool is_worker) { - //caspar::detail::SetThreadName(GetCurrentThreadId(), "tbb-worker-thread"); - caspar::win32_exception::install_handler(); + caspar::win32_exception::ensure_handler_installed_for_thread("tbb-worker-thread"); } } tbb_thread_installer; @@ -274,6 +273,8 @@ int main(int argc, wchar_t* argv[]) // anyway when the main thread terminates. boost::thread stdin_thread([&caspar_server, &shutdown_server_now, &wait_for_keypress] { + caspar::win32_exception::ensure_handler_installed_for_thread("stdin-thread"); + // Create a amcp parser for console commands. caspar::protocol::amcp::AMCPProtocolStrategy amcp( caspar_server.get_channels(), -- 2.39.2