]> git.sesse.net Git - casparcg/commitdiff
Fixed race-condition during server shut down where boost::asio::io_service was someti...
authorHelge Norberg <helge.norberg@gmail.com>
Fri, 8 Nov 2013 12:50:19 +0000 (13:50 +0100)
committerHelge Norberg <helge.norberg@gmail.com>
Fri, 8 Nov 2013 12:50:19 +0000 (13:50 +0100)
common/filesystem/polling_filesystem_monitor.cpp
common/filesystem/polling_filesystem_monitor.h
protocol/asio/io_service_manager.cpp [deleted file]
protocol/asio/io_service_manager.h [deleted file]
protocol/osc/client.cpp
protocol/osc/client.h
protocol/protocol.vcxproj
protocol/protocol.vcxproj.filters
shell/server.cpp

index 1037869d8d4b2a6200fd10463fa7e81eae08b945..d025789e463251731240171fa708421d8718b36f 100644 (file)
@@ -203,9 +203,9 @@ private:
 \r
 class polling_filesystem_monitor : public filesystem_monitor\r
 {\r
+       std::shared_ptr<boost::asio::io_service> scheduler_;\r
        directory_monitor root_monitor_;\r
        executor executor_;\r
-       boost::asio::io_service& scheduler_;\r
        boost::asio::deadline_timer timer_;\r
        tbb::atomic<bool> running_;\r
        int scan_interval_millis_;\r
@@ -218,18 +218,18 @@ public:
                        filesystem_event events_of_interest_mask,\r
                        bool report_already_existing,\r
                        int scan_interval_millis,\r
-                       boost::asio::io_service& scheduler,\r
+                       std::shared_ptr<boost::asio::io_service> scheduler,\r
                        const filesystem_monitor_handler& handler,\r
                        const initial_files_handler& initial_files_handler)\r
-               : root_monitor_(\r
+               : scheduler_(std::move(scheduler))\r
+               , root_monitor_(\r
                                report_already_existing,\r
                                folder_to_watch,\r
                                events_of_interest_mask,\r
                                handler,\r
                                initial_files_handler)\r
                , executor_(L"polling_filesystem_monitor")\r
-               , scheduler_(scheduler)\r
-               , timer_(scheduler)\r
+               , timer_(*scheduler_)\r
                , scan_interval_millis_(scan_interval_millis)\r
        {\r
                running_ = true;\r
@@ -272,6 +272,17 @@ private:
                timer_.expires_from_now(\r
                        boost::posix_time::milliseconds(scan_interval_millis_));\r
                timer_.async_wait([this](const boost::system::error_code& e)\r
+               {\r
+                       begin_scan();\r
+               });\r
+       }\r
+\r
+       void begin_scan()\r
+       {\r
+               if (!running_)\r
+                       return;\r
+\r
+               executor_.begin_invoke([this] ()\r
                {\r
                        scan();\r
                        schedule_next();\r
@@ -306,20 +317,22 @@ private:
 \r
 struct polling_filesystem_monitor_factory::implementation\r
 {\r
-       boost::asio::io_service& scheduler_;\r
+       std::shared_ptr<boost::asio::io_service> scheduler_;\r
        int scan_interval_millis;\r
 \r
        implementation(\r
-                       boost::asio::io_service& scheduler, int scan_interval_millis)\r
-               : scheduler_(scheduler), scan_interval_millis(scan_interval_millis)\r
+                       std::shared_ptr<boost::asio::io_service> scheduler,\r
+                       int scan_interval_millis)\r
+               : scheduler_(std::move(scheduler))\r
+               , scan_interval_millis(scan_interval_millis)\r
        {\r
        }\r
 };\r
 \r
 polling_filesystem_monitor_factory::polling_filesystem_monitor_factory(\r
-               boost::asio::io_service& scheduler,\r
+               std::shared_ptr<boost::asio::io_service> scheduler,\r
                int scan_interval_millis)\r
-       : impl_(new implementation(scheduler, scan_interval_millis))\r
+       : impl_(new implementation(std::move(scheduler), scan_interval_millis))\r
 {\r
 }\r
 \r
index fd3298ef7eda584cb17a7467815cccea9c3c359e..651d3a15e5f11b8b696506b4e02c0be0c0fdf0fe 100644 (file)
@@ -49,7 +49,7 @@ public:
         *                             reaction time but causes more I/O.\r
         */\r
        polling_filesystem_monitor_factory(\r
-                       boost::asio::io_service& scheduler,\r
+                       std::shared_ptr<boost::asio::io_service> scheduler,\r
                        int scan_interval_millis = 5000);\r
        virtual ~polling_filesystem_monitor_factory();\r
        virtual filesystem_monitor::ptr create(\r
diff --git a/protocol/asio/io_service_manager.cpp b/protocol/asio/io_service_manager.cpp
deleted file mode 100644 (file)
index 0845d8f..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-* 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 <http://www.gnu.org/licenses/>.
-*
-* Author: Helge Norberg, helge.norberg@svt.se
-*/
-
-#include "../StdAfx.h"
-
-#include "io_service_manager.h"
-
-#include <memory>
-
-#include <boost/asio/io_service.hpp>
-#include <boost/thread/thread.hpp>
-
-#include <common/exception/win32_exception.h>
-
-namespace caspar { namespace protocol { namespace asio {
-
-struct io_service_manager::impl
-{
-       boost::asio::io_service service_;
-       // To keep the io_service::run() running although no pending async
-       // operations are posted.
-       std::unique_ptr<boost::asio::io_service::work> work_;
-       boost::thread thread_;
-
-       impl()
-               : work_(new boost::asio::io_service::work(service_))
-               , thread_([this] { run(); })
-       {
-       }
-
-       void run()
-       {
-               win32_exception::ensure_handler_installed_for_thread("asio-thread");
-
-               service_.run();
-       }
-
-       ~impl()
-       {
-               work_.reset();
-               service_.stop();
-               thread_.join();
-       }
-};
-
-io_service_manager::io_service_manager()
-       : impl_(new impl)
-{
-}
-
-io_service_manager::~io_service_manager()
-{
-}
-
-boost::asio::io_service& io_service_manager::service()
-{
-       return impl_->service_;
-}
-
-}}}
diff --git a/protocol/asio/io_service_manager.h b/protocol/asio/io_service_manager.h
deleted file mode 100644 (file)
index cc6f253..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-* 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 <http://www.gnu.org/licenses/>.
-*
-* Author: Helge Norberg, helge.norberg@svt.se
-*/
-
-#pragma once
-
-#include <memory>
-
-#include <boost/noncopyable.hpp>
-
-namespace boost { namespace asio {
-       class io_service;
-}}
-
-namespace caspar { namespace protocol { namespace asio {
-
-class io_service_manager : boost::noncopyable
-{
-public:
-       io_service_manager();
-       ~io_service_manager();
-       boost::asio::io_service& service();
-private:
-       struct impl;
-       std::unique_ptr<impl> impl_;
-};
-
-}}}
index d87254c8cafe86dfb78ed776947b942d5d30dec2..16f1e9da23a502b3ba413a19ba35e7d9cfc00ea6 100644 (file)
@@ -129,6 +129,7 @@ void write_osc_bundle_element_start(byte_vector& destination, const byte_vector&
 
 struct client::impl : public std::enable_shared_from_this<client::impl>, core::monitor::sink
 {
+       std::shared_ptr<boost::asio::io_service>                service_;
        udp::socket socket_;
        tbb::spin_mutex                                                                 endpoints_mutex_;
        std::map<udp::endpoint, int>                                    reference_counts_by_endpoint_;
@@ -142,8 +143,9 @@ struct client::impl : public std::enable_shared_from_this<client::impl>, core::m
        boost::thread                                                                   thread_;
        
 public:
-       impl(boost::asio::io_service& service)
-               : socket_(service, udp::v4())
+       impl(std::shared_ptr<boost::asio::io_service> service)
+               : service_(std::move(service))
+               , socket_(*service_, udp::v4())
                , thread_(boost::bind(&impl::run, this))
        {
        }
@@ -291,8 +293,8 @@ private:
        }
 };
 
-client::client(boost::asio::io_service& service) 
-       : impl_(new impl(service))
+client::client(std::shared_ptr<boost::asio::io_service> service) 
+       : impl_(new impl(std::move(service)))
 {
 }
 
index 46e2179ca605f7036efa0ac1f561d470c0ff8014..672b7db787759cc34a8e09bdab19588fa26b4a6a 100644 (file)
@@ -40,7 +40,7 @@ public:
 
        // Constructors
 
-       client(boost::asio::io_service& service);
+       client(std::shared_ptr<boost::asio::io_service> service);
        
        client(client&&);
 
index 667a79ab25682afe1111bd67c8cc534031eaf1bb..0e87218c2478f8ef269f1304082486e4c7123597 100644 (file)
@@ -37,7 +37,6 @@
     <ClInclude Include="amcp\AMCPCommandQueue.h" />\r
     <ClInclude Include="amcp\AMCPCommandsImpl.h" />\r
     <ClInclude Include="amcp\AMCPProtocolStrategy.h" />\r
-    <ClInclude Include="asio\io_service_manager.h" />\r
     <ClInclude Include="cii\CIICommand.h" />\r
     <ClInclude Include="cii\CIICommandsImpl.h" />\r
     <ClInclude Include="cii\CIIProtocolStrategy.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
-    <ClCompile Include="asio\io_service_manager.cpp">\r
-      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
-      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
-      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
-      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
-    </ClCompile>\r
     <ClCompile Include="cii\CIICommandsImpl.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
index aa812837555e988e593d649124e2e82fb957984f..f786d17a6e2fc2f6fb103251c5e050fa1c8b5930 100644 (file)
@@ -22,9 +22,6 @@
     <Filter Include="source\osc\oscpack">\r
       <UniqueIdentifier>{6d9a82d4-6805-4de0-b400-6212fac06109}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="source\asio">\r
-      <UniqueIdentifier>{9c3a5197-d725-475d-ad5c-6b120e08022f}</UniqueIdentifier>\r
-    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="amcp\AMCPCommand.h">\r
     <ClInclude Include="osc\oscpack\OscOutboundPacketStream.h">\r
       <Filter>source\osc\oscpack</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="asio\io_service_manager.h">\r
-      <Filter>source\asio</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="osc\client.h">\r
       <Filter>source\osc</Filter>\r
     </ClInclude>\r
     <ClCompile Include="osc\oscpack\OscOutboundPacketStream.cpp">\r
       <Filter>source\osc\oscpack</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="asio\io_service_manager.cpp">\r
-      <Filter>source\asio</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="osc\client.cpp">\r
       <Filter>source\osc</Filter>\r
     </ClCompile>\r
index f13deb9f3a6a946ca1f84289744d5c1807beb42c..e43c4c710fa1cebc77205bff0ca7f393eb750315 100644 (file)
 #include <protocol/util/AsyncEventServer.h>\r
 #include <protocol/util/stateful_protocol_strategy_wrapper.h>\r
 #include <protocol/osc/client.h>\r
-#include <protocol/asio/io_service_manager.h>\r
 \r
 #include <boost/algorithm/string.hpp>\r
 #include <boost/lexical_cast.hpp>\r
 #include <boost/foreach.hpp>\r
 #include <boost/property_tree/ptree.hpp>\r
 #include <boost/property_tree/xml_parser.hpp>\r
+#include <boost/asio.hpp>\r
 \r
 namespace caspar {\r
 \r
 using namespace core;\r
 using namespace protocol;\r
 \r
+std::shared_ptr<boost::asio::io_service> create_running_io_service()\r
+{\r
+       auto service = std::make_shared<boost::asio::io_service>();\r
+       // To keep the io_service::run() running although no pending async\r
+       // operations are posted.\r
+       auto work = std::make_shared<boost::asio::io_service::work>(*service);\r
+       auto thread = std::make_shared<boost::thread>([service]\r
+       {\r
+               win32_exception::ensure_handler_installed_for_thread("asio-thread");\r
+\r
+               service->run();\r
+       });\r
+\r
+       return std::shared_ptr<boost::asio::io_service>(\r
+                       service.get(),\r
+                       [service, work, thread] (void*) mutable\r
+                       {\r
+                               work.reset();\r
+                               service->stop();\r
+                               thread->join();\r
+                       });\r
+}\r
+\r
 struct server::implementation : boost::noncopyable\r
 {\r
-       protocol::asio::io_service_manager                      io_service_manager_;\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
        safe_ptr<ogl_device>                                            ogl_;\r
@@ -90,9 +113,10 @@ struct server::implementation : boost::noncopyable
        std::shared_ptr<thumbnail_generator>            thumbnail_generator_;\r
 \r
        implementation(boost::promise<bool>& shutdown_server_now)\r
-               : shutdown_server_now_(shutdown_server_now)\r
+               : io_service_(create_running_io_service())\r
+               , shutdown_server_now_(shutdown_server_now)\r
                , ogl_(ogl_device::create())\r
-               , osc_client_(io_service_manager_.service())\r
+               , osc_client_(io_service_)\r
        {\r
                setup_audio(env::properties());\r
 \r
@@ -133,7 +157,7 @@ struct server::implementation : boost::noncopyable
        }\r
 \r
        ~implementation()\r
-       {               \r
+       {\r
                thumbnail_generator_.reset();\r
                primary_amcp_server_.reset();\r
                async_servers_.clear();\r
@@ -321,8 +345,7 @@ struct server::implementation : boost::noncopyable
                auto scan_interval_millis = pt.get(L"configuration.thumbnails.scan-interval-millis", 5000);\r
 \r
                polling_filesystem_monitor_factory monitor_factory(\r
-                               io_service_manager_.service(),\r
-                               scan_interval_millis);\r
+                               io_service_, scan_interval_millis);\r
                thumbnail_generator_.reset(new thumbnail_generator(\r
                                monitor_factory, \r
                                env::media_folder(),\r