]> git.sesse.net Git - casparcg/commitdiff
Spotted and fixed some memory leaks using Visual Leak Detector:
authorHelge Norberg <helge.norberg@svt.se>
Thu, 6 Nov 2014 19:37:54 +0000 (20:37 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Thu, 6 Nov 2014 19:37:54 +0000 (20:37 +0100)
* 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.

15 files changed:
common/exception/win32_exception.cpp
common/filesystem/filesystem_monitor.h
common/filesystem/polling_filesystem_monitor.cpp
core/producer/frame/frame_transform.cpp
core/thumbnail_generator.cpp
modules/ffmpeg/ffmpeg.cpp
modules/flash/producer/FlashAxContainer.cpp
modules/html/html.cpp
protocol/amcp/AMCPCommand.h
protocol/amcp/AMCPCommandsImpl.cpp
protocol/amcp/AMCPProtocolStrategy.cpp
protocol/amcp/AMCPProtocolStrategy.h
shell/main.cpp
shell/server.cpp
shell/server.h

index bd983c66dcc95322e90a99d320a3e61dd026a883..6adb8a612bdee206cd62c6ca4a25aef20913f4ad 100644 (file)
@@ -21,7 +21,7 @@
 \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
@@ -32,17 +32,9 @@ namespace caspar {
 \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
index 92ad3c6d612ddd944407b21c34b034955ad072ab..e71fcf0e309587d11ccc72031c96bb458524cdaa 100644 (file)
@@ -26,7 +26,6 @@
 \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
@@ -42,12 +41,6 @@ public:
 \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
index d025789e463251731240171fa708421d8718b36f..e77fafa89da9b8999d3ffda1d8e70bbf995f1331 100644 (file)
@@ -209,7 +209,6 @@ class polling_filesystem_monitor : public filesystem_monitor
        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
@@ -237,7 +236,6 @@ public:
                executor_.begin_invoke([this]\r
                {\r
                        scan();\r
-                       initial_scan_completion_.set_value();\r
                        schedule_next();\r
                });\r
        }\r
@@ -249,11 +247,6 @@ public:
                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
index d7987bf020579f2fb55beae0e1183a6426380795..f5122103764005a28a4dde5bfe447e9acdae9e67 100644 (file)
@@ -25,7 +25,7 @@
 \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
@@ -212,24 +212,21 @@ bool operator!=(const frame_transform& lhs, const frame_transform& rhs)
 \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
index e3aaa1bb0d066f860b56aaf1581ae0bb7663a829..b06c5aa98657f4ef51ddf4b763482ab60bd70fc2 100644 (file)
@@ -151,8 +151,6 @@ public:
                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
index 348c08f7781a987a49bde39d2de87fe162ce36c3..e657c32f92eeb66d4a1b50694d264a480f90fec4 100644 (file)
@@ -36,8 +36,7 @@
 #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
@@ -166,22 +165,21 @@ void log_callback(void* ptr, int level, const char* fmt, va_list vl)
     //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
@@ -193,14 +191,14 @@ std::shared_ptr<void> temporary_disable_logging_for_thread(bool disable)
 \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
index 2c2a55634181067d6c65ac107909df9b43aa394d..64e8c2cc68431a0494322c8bfccea72303bd5848 100644 (file)
@@ -47,7 +47,7 @@ FlashAxContainer::~FlashAxContainer()
        if(m_lpDD4)\r
        {\r
                m_lpDD4->Release();\r
-               m_lpDD4 = nullptr;\r
+               delete m_lpDD4;\r
        }\r
 \r
        if(pTimerHelper != 0)\r
index 9c54959d30585836ff21e7970b3a6999dd7dcab2..930528340007c85ca98694e4480c35ace6886465 100644 (file)
@@ -296,10 +296,11 @@ void uninit()
        {
                CefQuitMessageLoop();
        });
-       g_cef_executor->begin_invoke([&]
+       g_cef_executor->invoke([&]
        {
                CefShutdown();
        });
+       g_cef_executor.reset();
 }
 
 class cef_task : public CefTask
index dde4d8ca9b193f3a04e3263b988aa59907444069..0e1a63330ee69dfa3829780461985c7828b0bf11 100644 (file)
@@ -77,8 +77,8 @@ namespace caspar { namespace protocol { namespace amcp {
                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
@@ -113,7 +113,7 @@ namespace caspar { namespace protocol { namespace amcp {
                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
index 563accdfc4b91c2b8ee34910d43b3a6ee3b943a1..7dc452d9a2dde4e0dda20152399748f2496b9d87 100644 (file)
@@ -2439,13 +2439,13 @@ bool GlCommand::DoExecuteInfo()
 \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
index 64fb28a983d67433879e43bcedc78ada8e655050..6b956ea5a8db090675451b95eff32cdd2607ba98 100644 (file)
@@ -59,7 +59,7 @@ AMCPProtocolStrategy::AMCPProtocolStrategy(
                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
index 1c72b1a0b0fe1fc52b1aef28624a64d11d184828..6222f3b713863ede1cdfa14b6b381cbfe55a230f 100644 (file)
@@ -55,7 +55,7 @@ public:
                        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
@@ -78,7 +78,7 @@ private:
        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
index 1f5193e24e623af67c0e7e4247b15d63feb38ab6..de29e2898c4860093ea336a28d2bd32cbd152239 100644 (file)
@@ -27,6 +27,7 @@
        #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
@@ -73,6 +74,7 @@
 #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
@@ -260,7 +262,7 @@ int main(int argc, char* argv[])
                }\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
@@ -301,42 +303,48 @@ int main(int argc, char* argv[])
                {\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
@@ -398,16 +406,24 @@ int main(int argc, char* argv[])
 \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
index 602f7d83edf44b8e435c8ae46898b65e7dc1671c..96a0587607d27d83866a45b77b2769489aafbcf9 100644 (file)
@@ -107,7 +107,7 @@ struct server::implementation : boost::noncopyable
 {\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
@@ -119,7 +119,7 @@ struct server::implementation : boost::noncopyable
        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
@@ -421,7 +421,7 @@ struct server::implementation : boost::noncopyable
        }\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
index d7538a53ef039cb16fb276eeb8327725b89fe495..008797ad632d039a6f62273dfeb7c57eb9d2845f 100644 (file)
@@ -43,7 +43,7 @@ namespace core {
 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