cool#6580 sw: fix infinite loop when changing document language
[LibreOffice.git] / include / vcl / threadex.hxx
blob01d6170fbbe5a4a30f729eb59626eaca5b98fd08
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_VCL_THREADEX_HXX
21 #define INCLUDED_VCL_THREADEX_HXX
23 #include <osl/conditn.hxx>
24 #include <tools/link.hxx>
25 #include <vcl/dllapi.h>
27 #include <boost/optional.hpp>
28 #include <memory>
30 namespace vcl
32 class VCL_DLLPUBLIC SolarThreadExecutor
34 osl::Condition m_aStart;
35 osl::Condition m_aFinish;
36 bool m_bTimeout;
38 DECL_DLLPRIVATE_LINK( worker, void*, void );
40 public:
41 SolarThreadExecutor();
42 virtual ~SolarThreadExecutor();
44 virtual void doIt() = 0;
45 void execute();
48 namespace solarthread {
50 /// @internal
51 namespace detail {
53 template <typename FuncT, typename ResultT>
54 class GenericSolarThreadExecutor final : public SolarThreadExecutor
56 public:
57 static ResultT exec( FuncT const& func )
59 typedef GenericSolarThreadExecutor<FuncT, ResultT> ExecutorT;
60 ::std::unique_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
61 pExecutor->execute();
62 if (pExecutor->m_exc)
63 std::rethrow_exception(pExecutor->m_exc);
64 return *pExecutor->m_result;
67 private:
68 explicit GenericSolarThreadExecutor( FuncT const& func )
69 : m_func(func), m_result() {}
71 virtual void doIt() override
73 try {
74 m_result.reset( m_func() );
76 catch (...) {
77 m_exc = std::current_exception();
81 std::exception_ptr m_exc;
82 #ifdef _MSC_VER
83 FuncT m_func; // "const" and std::bind() results in Error C3848 expression would lose const-volatile qualifiers
84 #else
85 FuncT const m_func;
86 #endif
87 // using boost::optional here omits the need that ResultT is default
88 // constructable:
89 ::boost::optional<ResultT> m_result;
92 template <typename FuncT>
93 class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
95 public:
96 static void exec( FuncT const& func )
98 typedef GenericSolarThreadExecutor<FuncT, void> ExecutorT;
99 ::std::unique_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
100 pExecutor->execute();
101 if (pExecutor->m_exc)
102 std::rethrow_exception(pExecutor->m_exc);
105 private:
106 explicit GenericSolarThreadExecutor( FuncT const& func )
107 : m_func(func) {}
109 virtual void doIt() override
111 try {
112 m_func();
114 catch (...) {
115 m_exc = std::current_exception();
119 std::exception_ptr m_exc;
120 FuncT const m_func;
123 } // namespace detail
126 /** This function will execute the passed functor synchronously in the
127 solar thread, thus the calling thread will (eventually) be blocked until
128 the functor has been called.
129 Any exception that came up calling the functor in the solar thread
130 will be caught and rethrown in the calling thread.
131 The result type of this function needs to be default constructable.
132 Please keep in mind not to pass addresses to stack variables
133 (e.g. for out parameters) to foreign threads, use inout_by_ref()
134 for this purpose. For in parameters, this may not affect you, because
135 the functor object is copy constructed into free store. This way
136 you must not use \verbatim std::cref()/std::ref() \endverbatim or similar
137 for objects on your thread's stack.
138 Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
140 \code{.cpp}
141 using namespace vcl::solarthread;
143 long n = 3;
144 // calling foo( long & r ):
145 syncExecute( std::bind( &foo, inout_by_ref(n) ) );
146 // calling foo( long * p ):
147 syncExecute( std::bind( &foo, inout_by_ptr(&n) ) );
149 char const* pc = "default";
150 // calling foo( char const** ppc ):
151 syncExecute( std::bind( &foo, inout_by_ptr(&pc) ) );
152 // calling foo( char const*& rpc ):
153 syncExecute( std::bind( &foo, inout_by_ref(pc) ) );
154 \endcode
156 @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
157 support mem_fn and bind
158 @tpl FuncT functor type, let your compiler deduce this type
159 @param func functor object to be executed in solar thread
160 @return return value of functor
162 template <typename FuncT>
163 inline auto syncExecute(FuncT const& func) -> decltype(func())
165 return detail::GenericSolarThreadExecutor<
166 FuncT, decltype(func())>::exec(func);
169 } // namespace solarthread
170 } // namespace vcl
172 #endif // INCLUDED_VCL_THREADEX_HXX
174 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */