Branch libreoffice-5-0-4
[LibreOffice.git] / include / vcl / threadex.hxx
blobb5122f60c5e9836b93efa9ddafe3710d256e2483
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.h>
24 #include <osl/thread.h>
25 #include <tools/link.hxx>
26 #include <vcl/dllapi.h>
28 #include <cppuhelper/exc_hlp.hxx>
29 #include <boost/optional.hpp>
30 #include <memory>
32 namespace vcl
34 class VCL_DLLPUBLIC SolarThreadExecutor
36 oslCondition m_aStart;
37 oslCondition m_aFinish;
38 long m_nReturn;
39 bool m_bTimeout;
41 DECL_DLLPRIVATE_LINK( worker, void* );
43 public:
44 SolarThreadExecutor();
45 virtual ~SolarThreadExecutor();
47 virtual long doIt() = 0;
48 long execute() { return impl_execute( NULL ); }
49 // caution: timeout for getting the solar mutex, not for ending
50 // the operation of doIt(). If doIt actually gets called within
51 // the specified timeout, execute will only return after
52 // doIt() completed
53 long execute( const TimeValue& _rTimeout ) { return impl_execute( &_rTimeout ); }
55 public:
56 bool didTimeout() const { return m_bTimeout; }
58 private:
59 long impl_execute( const TimeValue* _pTimeout );
62 namespace solarthread {
64 /// @internal
65 namespace detail {
67 template <typename FuncT, typename ResultT>
68 class GenericSolarThreadExecutor : public SolarThreadExecutor
70 public:
71 static ResultT exec( FuncT const& func )
73 typedef GenericSolarThreadExecutor<FuncT, ResultT> ExecutorT;
74 ::std::unique_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
75 pExecutor->execute();
76 if (pExecutor->m_exc.hasValue())
77 ::cppu::throwException( pExecutor->m_exc );
78 return *pExecutor->m_result;
81 private:
82 explicit GenericSolarThreadExecutor( FuncT const& func )
83 : m_exc(), m_func(func), m_result() {}
85 virtual long doIt() SAL_OVERRIDE
87 try {
88 m_result.reset( m_func() );
90 catch (::com::sun::star::uno::Exception &) {
91 // only UNO exceptions can be dispatched:
92 m_exc = ::cppu::getCaughtException();
94 return 0;
97 ::com::sun::star::uno::Any m_exc;
98 FuncT const m_func;
99 // using boost::optional here omits the need that ResultT is default
100 // constructable:
101 ::boost::optional<ResultT> m_result;
104 template <typename FuncT>
105 class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
107 public:
108 static void exec( FuncT const& func )
110 typedef GenericSolarThreadExecutor<FuncT, void> ExecutorT;
111 ::std::unique_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
112 pExecutor->execute();
113 if (pExecutor->m_exc.hasValue())
114 ::cppu::throwException( pExecutor->m_exc );
117 private:
118 explicit GenericSolarThreadExecutor( FuncT const& func )
119 : m_exc(), m_func(func) {}
121 virtual long doIt() SAL_OVERRIDE
123 try {
124 m_func();
126 catch (::com::sun::star::uno::Exception &) {
127 // only UNO exceptions can be dispatched:
128 m_exc = ::cppu::getCaughtException();
130 return 0;
133 ::com::sun::star::uno::Any m_exc;
134 FuncT const m_func;
137 template <typename T>
138 class copy_back_wrapper
140 public:
141 operator T *() const { return &m_holder->m_value; }
142 operator T &() const { return m_holder->m_value; }
144 explicit copy_back_wrapper( T * p ) : m_holder( new data_holder(p) ) {}
146 // no thread-safe counting needed here, because calling thread blocks
147 // until solar thread has executed the functor.
148 copy_back_wrapper( copy_back_wrapper<T> const& r )
149 : m_holder(r.m_holder) { ++m_holder->m_refCount; }
150 ~copy_back_wrapper() {
151 --m_holder->m_refCount;
152 if (m_holder->m_refCount == 0) {
153 delete m_holder;
156 private:
157 struct data_holder {
158 T m_value;
159 T * const m_ptr;
160 sal_Int32 m_refCount;
161 data_holder( T * p ) : m_value(*p), m_ptr(p), m_refCount(1) {}
162 ~data_holder() { *m_ptr = m_value; }
164 data_holder * const m_holder;
167 } // namespace detail
169 /** Makes a copy back reference wrapper to be used for inout parameters.
170 Only use for syncExecute(), the returned wrapper relies on its
171 implementation, i.e. the function object is stored in free store.
172 Type T needs to be copy constructable assignable.
174 @see syncExecute()
175 @param r reference to a stack variable
176 @return reference wrapper
178 template <typename T>
179 inline detail::copy_back_wrapper<T> inout_by_ref( T & r )
181 return detail::copy_back_wrapper<T>(&r);
184 /** Makes a copy back ptr wrapper to be used for inout parameters.
185 Only use for syncExecute(), the returned wrapper relies on its
186 implementation, i.e. the function object is stored in free store.
187 Type T needs to be copy constructable assignable.
189 @see syncExecute()
190 @param p pointer to a stack variable
191 @return ptr wrapper
193 template <typename T>
194 inline detail::copy_back_wrapper<T> inout_by_ptr( T * p )
196 return detail::copy_back_wrapper<T>(p);
199 /** This function will execute the passed functor synchronously in the
200 solar thread, thus the calling thread will (eventually) be blocked until
201 the functor has been called.
202 Any UNO exception that came up calling the functor in the solar thread
203 will be caught and rethrown in the calling thread. Any non-UNO
204 exception needs to be handled by the called functor.
205 The result type of this function needs to be default constructable.
206 Please keep in mind not to pass addresses to stack variables
207 (e.g. for out parameters) to foreign threads, use inout_by_ref()
208 for this purpose. For in parameters, this may not affect you, because
209 the functor object is copy constructed into free store. This way
210 you must not use \verbatim boost::cref()/boost::ref() \endverbatim or similar
211 for objects on your thread's stack.
212 Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
214 \code{.cpp}
215 using namespace vcl::solarthread;
217 long n = 3;
218 // calling foo( long & r ):
219 syncExecute( boost::bind( &foo, inout_by_ref(n) ) );
220 // calling foo( long * p ):
221 syncExecute( boost::bind( &foo, inout_by_ptr(&n) ) );
223 char const* pc = "default";
224 // calling foo( char const** ppc ):
225 syncExecute( boost::bind( &foo, inout_by_ptr(&pc) ) );
226 // calling foo( char const*& rpc ):
227 syncExecute( boost::bind( &foo, inout_by_ref(pc) ) );
228 \endcode
230 @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
231 support mem_fn and bind
232 @tpl FuncT functor type, let your compiler deduce this type
233 @param func functor object to be executed in solar thread
234 @return return value of functor
236 template <typename ResultT, typename FuncT>
237 inline ResultT syncExecute( FuncT const& func )
239 return detail::GenericSolarThreadExecutor<FuncT, ResultT>::exec(func);
242 template <typename FuncT>
243 inline typename FuncT::result_type syncExecute( FuncT const& func )
245 return detail::GenericSolarThreadExecutor<
246 FuncT, typename FuncT::result_type>::exec(func);
249 } // namespace solarthread
250 } // namespace vcl
252 #endif // INCLUDED_VCL_THREADEX_HXX
254 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */