]> git.sesse.net Git - casparcg/blob - common/concurrency/com_context.h
Fixed potential race condition
[casparcg] / common / concurrency / com_context.h
1 /*\r
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\r
5 *\r
6 * CasparCG is free software: you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation, either version 3 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * CasparCG is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 * Author: Robert Nagy, ronag89@gmail.com\r
20 */\r
21 \r
22 #pragma once\r
23 \r
24 #include "executor.h"\r
25 \r
26 #include "../log/log.h"\r
27 #include "../exception/exceptions.h"\r
28 \r
29 #define NOMINMAX\r
30 #define WIN32_LEAN_AND_MEAN\r
31 \r
32 #include <Windows.h>\r
33 \r
34 #include <boost/noncopyable.hpp>\r
35 #include <boost/thread/future.hpp>\r
36 \r
37 #include <functional>\r
38 \r
39 namespace caspar {\r
40 \r
41 template<typename T>\r
42 class com_context : public executor\r
43 {\r
44         std::unique_ptr<T> instance_;\r
45 public:\r
46         com_context(const std::wstring& name) : executor(name)\r
47         {\r
48                 executor::begin_invoke([]\r
49                 {\r
50                         ::CoInitialize(nullptr);\r
51                 });\r
52         }\r
53 \r
54         ~com_context()\r
55         {\r
56                 if(!executor::begin_invoke([&]\r
57                 {\r
58                         instance_.reset(nullptr);\r
59                         ::CoUninitialize();\r
60                 }).timed_wait(boost::posix_time::milliseconds(500)))\r
61                 {\r
62                         CASPAR_LOG(error) << L"[com_contex] Timer expired, deadlock detected and released, leaking resources.";\r
63                 }\r
64         }\r
65         \r
66         void reset(const std::function<T*()>& factory = nullptr)\r
67         {\r
68                 executor::invoke([&]\r
69                 {\r
70                         instance_.reset();\r
71                         if(factory)\r
72                                 instance_.reset(factory());\r
73                 });\r
74         }\r
75 \r
76         T& operator*() const \r
77         {\r
78                 if(instance_ == nullptr)\r
79                         BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Tried to access null context."));\r
80 \r
81                 return *instance_.get();\r
82         }  // noexcept\r
83 \r
84         T* operator->() const \r
85         {\r
86                 if(instance_ == nullptr)\r
87                         BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Tried to access null context."));\r
88                 return instance_.get();\r
89         }  // noexcept\r
90 \r
91         T* get() const\r
92         {\r
93                 return instance_.get();\r
94         }  // noexcept\r
95 \r
96         operator bool() const {return get() != nullptr;}\r
97 };\r
98 \r
99 }