* Now uses TBB thread local instead of Boost thread local everywhere. Seems to clean up better at thread exit.
* FlashAxContainer.cpp: m_lpDD4 was never deleted.
* g_cef_executor now freed in html::uninit() instead of at CRT termination.
* Reduced leakage from Console thread when exiting server via KILL or RESTART instead of via q. Best would be if std::getline could be unblocked from another thread somehow.
\r
#include "../stdafx.h"\r
\r
-#include <boost/thread.hpp>\r
+#include <tbb/enumerable_thread_specific.h>\r
\r
#include "win32_exception.h"\r
\r
\r
bool& installed_for_thread()\r
{\r
- static boost::thread_specific_ptr<bool> installed;\r
+ static tbb::enumerable_thread_specific<bool> installed(false);\r
\r
- auto for_thread = installed.get();\r
- \r
- if (!for_thread)\r
- {\r
- for_thread = new bool(false);\r
- installed.reset(for_thread);\r
- }\r
-\r
- return *for_thread;\r
+ return installed.local();\r
}\r
\r
void win32_exception::install_handler() \r
\r
#include <boost/filesystem.hpp>\r
#include <boost/noncopyable.hpp>\r
-#include <boost/thread/future.hpp>\r
\r
#include "../memory/safe_ptr.h"\r
\r
\r
virtual ~filesystem_monitor() {}\r
\r
- /**\r
- * @return a future made available when the initially available files have been\r
- * processed.\r
- */\r
- virtual boost::unique_future<void> initial_files_processed() = 0;\r
-\r
/**\r
* Reemmit the already known files as MODIFIED events.\r
*/\r
boost::asio::deadline_timer timer_;\r
tbb::atomic<bool> running_;\r
int scan_interval_millis_;\r
- boost::promise<void> initial_scan_completion_;\r
tbb::concurrent_queue<boost::filesystem::wpath> to_reemmit_;\r
tbb::atomic<bool> reemmit_all_;\r
public:\r
executor_.begin_invoke([this]\r
{\r
scan();\r
- initial_scan_completion_.set_value();\r
schedule_next();\r
});\r
}\r
timer_.cancel(e);\r
}\r
\r
- virtual boost::unique_future<void> initial_files_processed()\r
- {\r
- return initial_scan_completion_.get_future();\r
- }\r
-\r
virtual void reemmit_all()\r
{\r
reemmit_all_ = true;\r
\r
#include <common/utility/assert.h>\r
\r
-#include <boost/thread.hpp>\r
+#include <tbb/enumerable_thread_specific.h>\r
\r
namespace caspar { namespace core {\r
\r
\r
namespace detail {\r
\r
-boost::thread_specific_ptr<double>& get_thread_local_aspect_ratio()\r
+double& get_thread_local_aspect_ratio()\r
{\r
- static boost::thread_specific_ptr<double> aspect_ratio;\r
+ static tbb::enumerable_thread_specific<double> aspect_ratio(1.0);\r
\r
- if (!aspect_ratio.get())\r
- aspect_ratio.reset(new double(1.0));\r
-\r
- return aspect_ratio;\r
+ return aspect_ratio.local();\r
}\r
\r
void set_current_aspect_ratio(double aspect_ratio)\r
{\r
- *get_thread_local_aspect_ratio() = aspect_ratio;\r
+ get_thread_local_aspect_ratio() = aspect_ratio;\r
}\r
\r
double get_current_aspect_ratio()\r
{\r
- return *get_thread_local_aspect_ratio();\r
+ return get_thread_local_aspect_ratio();\r
}\r
\r
}}}\r
graph_->auto_reset();\r
diagnostics::register_graph(graph_);\r
mixer_->set_mipmap(0, mipmap);\r
- //monitor_->initial_scan_completion().get();\r
- //output_->sleep_millis = 2000;\r
}\r
\r
void on_initial_files(const std::set<boost::filesystem::wpath>& initial_files)\r
#include <core/producer/media_info/media_info_repository.h>\r
\r
#include <tbb/recursive_mutex.h>\r
-\r
-#include <boost/thread.hpp>\r
+#include <tbb/enumerable_thread_specific.h>\r
\r
#if defined(_MSC_VER)\r
#pragma warning (disable : 4244)\r
//colored_fputs(av_clip(level>>3, 0, 6), line);\r
}\r
\r
-boost::thread_specific_ptr<bool>& get_disable_logging_for_thread()\r
+bool& get_disable_logging_for_thread()\r
{\r
- static boost::thread_specific_ptr<bool> disable_logging_for_thread;\r
+ static tbb::enumerable_thread_specific<bool> disable_logging_for_thread(false);\r
\r
- return disable_logging_for_thread;\r
+ return disable_logging_for_thread.local();\r
}\r
\r
void disable_logging_for_thread()\r
{\r
- if (get_disable_logging_for_thread().get() == nullptr)\r
- get_disable_logging_for_thread().reset(new bool); // bool value does not matter\r
+ get_disable_logging_for_thread() = true;\r
}\r
\r
bool is_logging_disabled_for_thread()\r
{\r
- return get_disable_logging_for_thread().get() != nullptr;\r
+ return get_disable_logging_for_thread();\r
}\r
\r
std::shared_ptr<void> temporary_disable_logging_for_thread(bool disable)\r
\r
return std::shared_ptr<void>(nullptr, [] (void*)\r
{\r
- get_disable_logging_for_thread().release(); // Only works correctly if destructed in same thread as original caller.\r
+ get_disable_logging_for_thread() = false; // Only works correctly if destructed in same thread as original caller.\r
});\r
}\r
\r
void log_for_thread(void* ptr, int level, const char* fmt, va_list vl)\r
{\r
win32_exception::ensure_handler_installed_for_thread("ffmpeg-thread");\r
- if (get_disable_logging_for_thread().get() == nullptr) // It does not matter what the value of the bool is\r
+ if (!get_disable_logging_for_thread()) // It does not matter what the value of the bool is\r
log_callback(ptr, level, fmt, vl);\r
}\r
\r
if(m_lpDD4)\r
{\r
m_lpDD4->Release();\r
- m_lpDD4 = nullptr;\r
+ delete m_lpDD4;\r
}\r
\r
if(pTimerHelper != 0)\r
{
CefQuitMessageLoop();
});
- g_cef_executor->begin_invoke([&]
+ g_cef_executor->invoke([&]
{
CefShutdown();
});
+ g_cef_executor.reset();
}
class cef_task : public CefTask
void SetMediaInfoRepo(const safe_ptr<core::media_info_repository>& media_info_repo) {media_info_repo_ = media_info_repo;}\r
std::shared_ptr<core::media_info_repository> GetMediaInfoRepo() { return media_info_repo_; }\r
\r
- void SetShutdownServerNow(boost::promise<bool>& shutdown_server_now) {shutdown_server_now_ = &shutdown_server_now;}\r
- boost::promise<bool>& GetShutdownServerNow() { return *shutdown_server_now_; }\r
+ void SetShutdownServerNow(const std::function<void (bool)>& shutdown_server_now) {shutdown_server_now_ = shutdown_server_now;}\r
+ const std::function<void (bool)>& GetShutdownServerNow() { return shutdown_server_now_; }\r
\r
void SetChannelIndex(unsigned int channelIndex){channelIndex_ = channelIndex;}\r
unsigned int GetChannelIndex(){return channelIndex_;}\r
std::vector<safe_ptr<core::video_channel>> channels_;\r
std::shared_ptr<core::thumbnail_generator> thumb_gen_;\r
std::shared_ptr<core::media_info_repository> media_info_repo_;\r
- boost::promise<bool>* shutdown_server_now_;\r
+ std::function<void (bool)> shutdown_server_now_;\r
AMCPCommandScheduling scheduling_;\r
std::wstring replyString_;\r
};\r
\r
bool KillCommand::DoExecute()\r
{\r
- GetShutdownServerNow().set_value(false); // False for not attempting to restart.\r
+ GetShutdownServerNow()(false); // False for not attempting to restart.\r
return true;\r
}\r
\r
bool RestartCommand::DoExecute()\r
{\r
- GetShutdownServerNow().set_value(true); // True for attempting to restart\r
+ GetShutdownServerNow()(true); // True for attempting to restart\r
return true;\r
}\r
\r
const std::shared_ptr<core::thumbnail_generator>& thumb_gen,\r
const safe_ptr<core::media_info_repository>& media_info_repo,\r
const safe_ptr<core::ogl_device>& ogl_device,\r
- boost::promise<bool>& shutdown_server_now)\r
+ const std::function<void (bool)>& shutdown_server_now)\r
: channels_(channels)\r
, thumb_gen_(thumb_gen)\r
, media_info_repo_(media_info_repo)\r
const std::shared_ptr<core::thumbnail_generator>& thumb_gen,\r
const safe_ptr<core::media_info_repository>& media_info_repo,\r
const safe_ptr<core::ogl_device>& ogl_device,\r
- boost::promise<bool>& shutdown_server_now);\r
+ const std::function<void (bool)>& shutdown_server_now);\r
virtual ~AMCPProtocolStrategy();\r
\r
virtual void Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo);\r
std::shared_ptr<core::thumbnail_generator> thumb_gen_;\r
safe_ptr<core::media_info_repository> media_info_repo_;\r
safe_ptr<core::ogl_device> ogl_;\r
- boost::promise<bool>& shutdown_server_now_;\r
+ std::function<void (bool)> shutdown_server_now_;\r
std::vector<AMCPCommandQueuePtr> commandQueues_;\r
static const std::wstring MessageDelimiter;\r
};\r
#define _CRTDBG_MAP_ALLOC\r
#include <stdlib.h>\r
#include <crtdbg.h>\r
+ //#include <vld.h>\r
#else\r
#include <tbb/tbbmalloc_proxy.h>\r
#endif\r
#include <boost/thread/future.hpp>\r
#include <boost/locale.hpp>\r
#include <boost/algorithm/string/case_conv.hpp>\r
+#include <boost/logic/tribool.hpp>\r
\r
#include <functional>\r
\r
}\r
} tbb_thread_installer;\r
\r
- bool restart = false;\r
+ boost::tribool restart = false;\r
tbb::task_scheduler_init init;\r
std::wstring config_file_name(L"casparcg.config");\r
\r
{\r
init_t html_init(L"html", nullptr, caspar::html::uninit);\r
\r
- boost::promise<bool> shutdown_server_now;\r
- boost::unique_future<bool> shutdown_server = shutdown_server_now.get_future();\r
+ boost::promise<boost::tribool> shutdown_server_now;\r
+ std::function<void (bool)> shutdown_server_now_func =\r
+ [&shutdown_server_now](bool restart)\r
+ {\r
+ shutdown_server_now.set_value(restart);\r
+ };\r
+ auto shutdown_server = shutdown_server_now.get_future();\r
\r
// Create server object which initializes channels, protocols and controllers.\r
- caspar::server caspar_server(shutdown_server_now);\r
+ caspar::server caspar_server(shutdown_server_now_func);\r
+\r
+ // Create a amcp parser for console commands.\r
+ caspar::protocol::amcp::AMCPProtocolStrategy amcp(\r
+ L"Console",\r
+ caspar_server.get_channels(),\r
+ caspar_server.get_thumbnail_generator(),\r
+ caspar_server.get_media_info_repo(),\r
+ caspar_server.get_ogl_device(),\r
+ shutdown_server_now_func);\r
+\r
+ // Create a dummy client which prints amcp responses to console.\r
+ auto console_client = std::make_shared<caspar::IO::ConsoleClientInfo>();\r
+ std::wstring wcmd;\r
+ std::wstring upper_cmd;\r
\r
// Use separate thread for the blocking console input, will be terminated \r
// anyway when the main thread terminates.\r
- boost::thread stdin_thread([&caspar_server, &shutdown_server_now, &wait_for_keypress]\r
+ boost::thread stdin_thread([&]\r
{\r
caspar::win32_exception::ensure_handler_installed_for_thread("stdin-thread");\r
\r
- // Create a amcp parser for console commands.\r
- caspar::protocol::amcp::AMCPProtocolStrategy amcp(\r
- L"Console",\r
- caspar_server.get_channels(),\r
- caspar_server.get_thumbnail_generator(),\r
- caspar_server.get_media_info_repo(),\r
- caspar_server.get_ogl_device(),\r
- shutdown_server_now);\r
-\r
- // Create a dummy client which prints amcp responses to console.\r
- auto console_client = std::make_shared<caspar::IO::ConsoleClientInfo>();\r
- std::wstring wcmd;\r
- \r
while(true)\r
{\r
std::getline(std::wcin, wcmd); // TODO: It's blocking...\r
\r
//boost::to_upper(wcmd); // TODO COMPILER crashes on this line, Strange!\r
- auto upper_cmd = make_upper_case(wcmd);\r
+ upper_cmd = make_upper_case(wcmd);\r
\r
if(upper_cmd == L"EXIT" || upper_cmd == L"Q" || upper_cmd == L"QUIT" || upper_cmd == L"BYE")\r
{\r
wait_for_keypress = true;\r
- shutdown_server_now.set_value(false); // False to not restart server\r
+ shutdown_server_now.set_value(boost::indeterminate);\r
break;\r
}\r
\r
\r
wcmd += L"\r\n";\r
amcp.Parse(wcmd.c_str(), wcmd.length(), console_client);\r
+\r
+ if (shutdown_server.is_ready())\r
+ {\r
+ break;\r
+ }\r
} \r
});\r
stdin_thread.detach();\r
restart = shutdown_server.get();\r
+\r
+ if (restart == boost::indeterminate)\r
+ Sleep(200); // Give the console thread a chance to finish amcp.Parse if a KILL or RESTART was issued via the console.\r
}\r
Sleep(500);\r
CASPAR_LOG(info) << "Successfully shutdown CasparCG Server.";\r
\r
if (wait_for_keypress)\r
- system("pause"); \r
+ system("pause");\r
}\r
catch(boost::property_tree::file_parser_error&)\r
{\r
{\r
std::shared_ptr<boost::asio::io_service> io_service_;\r
safe_ptr<core::monitor::subject> monitor_subject_;\r
- boost::promise<bool>& shutdown_server_now_;\r
+ std::function<void (bool)> shutdown_server_now_;\r
safe_ptr<ogl_device> ogl_;\r
std::vector<safe_ptr<IO::AsyncEventServer>> async_servers_; \r
std::shared_ptr<IO::AsyncEventServer> primary_amcp_server_;\r
tbb::atomic<bool> running_;\r
std::shared_ptr<thumbnail_generator> thumbnail_generator_;\r
\r
- implementation(boost::promise<bool>& shutdown_server_now)\r
+ implementation(const std::function<void (bool)>& shutdown_server_now)\r
: io_service_(create_running_io_service())\r
, shutdown_server_now_(shutdown_server_now)\r
, ogl_(ogl_device::create())\r
}\r
};\r
\r
-server::server(boost::promise<bool>& shutdown_server_now) : impl_(new implementation(shutdown_server_now)){}\r
+server::server(const std::function<void (bool)>& shutdown_server_now) : impl_(new implementation(shutdown_server_now)){}\r
\r
const std::vector<safe_ptr<video_channel>> server::get_channels() const\r
{\r
class server : boost::noncopyable\r
{\r
public:\r
- server(boost::promise<bool>& shutdown_server_now);\r
+ server(const std::function<void (bool)>& shutdown_server_now);\r
const std::vector<safe_ptr<core::video_channel>> get_channels() const;\r
std::shared_ptr<core::thumbnail_generator> get_thumbnail_generator() const;\r
safe_ptr<core::media_info_repository> get_media_info_repo() const;\r