Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #ifndef INCLUDED_VCL_THREADEX_HXX
21 : #define INCLUDED_VCL_THREADEX_HXX
22 :
23 : #include <osl/conditn.h>
24 : #include <osl/thread.h>
25 : #include <tools/link.hxx>
26 : #include <vcl/dllapi.h>
27 :
28 : #include <cppuhelper/exc_hlp.hxx>
29 : #include <boost/optional.hpp>
30 : #include <memory>
31 :
32 : namespace vcl
33 : {
34 : class VCL_DLLPUBLIC SolarThreadExecutor
35 : {
36 : oslCondition m_aStart;
37 : oslCondition m_aFinish;
38 : long m_nReturn;
39 : bool m_bTimeout;
40 :
41 : DECL_DLLPRIVATE_LINK( worker, void* );
42 :
43 : public:
44 : SolarThreadExecutor();
45 : virtual ~SolarThreadExecutor();
46 :
47 : virtual long doIt() = 0;
48 0 : 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 ); }
54 :
55 : public:
56 : bool didTimeout() const { return m_bTimeout; }
57 :
58 : private:
59 : long impl_execute( const TimeValue* _pTimeout );
60 : };
61 :
62 : namespace solarthread {
63 :
64 : /// @internal
65 : namespace detail {
66 :
67 : template <typename FuncT, typename ResultT>
68 0 : class GenericSolarThreadExecutor : public SolarThreadExecutor
69 : {
70 : public:
71 0 : static ResultT exec( FuncT const& func )
72 : {
73 : typedef GenericSolarThreadExecutor<FuncT, ResultT> ExecutorT;
74 0 : ::std::unique_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
75 0 : pExecutor->execute();
76 0 : if (pExecutor->m_exc.hasValue())
77 0 : ::cppu::throwException( pExecutor->m_exc );
78 0 : return *pExecutor->m_result;
79 : }
80 :
81 : private:
82 0 : explicit GenericSolarThreadExecutor( FuncT const& func )
83 0 : : m_exc(), m_func(func), m_result() {}
84 :
85 0 : virtual long doIt() SAL_OVERRIDE
86 : {
87 : try {
88 0 : m_result.reset( m_func() );
89 : }
90 0 : catch (::com::sun::star::uno::Exception &) {
91 : // only UNO exceptions can be dispatched:
92 0 : m_exc = ::cppu::getCaughtException();
93 : }
94 0 : return 0;
95 : }
96 :
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;
102 : };
103 :
104 : template <typename FuncT>
105 : class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
106 : {
107 : public:
108 : static void exec( FuncT const& func )
109 : {
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 );
115 : }
116 :
117 : private:
118 : explicit GenericSolarThreadExecutor( FuncT const& func )
119 : : m_exc(), m_func(func) {}
120 :
121 : virtual long doIt() SAL_OVERRIDE
122 : {
123 : try {
124 : m_func();
125 : }
126 : catch (::com::sun::star::uno::Exception &) {
127 : // only UNO exceptions can be dispatched:
128 : m_exc = ::cppu::getCaughtException();
129 : }
130 : return 0;
131 : }
132 :
133 : ::com::sun::star::uno::Any m_exc;
134 : FuncT const m_func;
135 : };
136 :
137 : template <typename T>
138 : class copy_back_wrapper
139 : {
140 : public:
141 : operator T *() const { return &m_holder->m_value; }
142 : operator T &() const { return m_holder->m_value; }
143 :
144 : explicit copy_back_wrapper( T * p ) : m_holder( new data_holder(p) ) {}
145 :
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;
154 : }
155 : }
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; }
163 : };
164 : data_holder * const m_holder;
165 : };
166 :
167 : } // namespace detail
168 :
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.
173 :
174 : @see syncExecute()
175 : @param r reference to a stack variable
176 : @return reference wrapper
177 : */
178 : template <typename T>
179 : inline detail::copy_back_wrapper<T> inout_by_ref( T & r )
180 : {
181 : return detail::copy_back_wrapper<T>(&r);
182 : }
183 :
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.
188 :
189 : @see syncExecute()
190 : @param p pointer to a stack variable
191 : @return ptr wrapper
192 : */
193 : template <typename T>
194 : inline detail::copy_back_wrapper<T> inout_by_ptr( T * p )
195 : {
196 : return detail::copy_back_wrapper<T>(p);
197 : }
198 :
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.
213 :
214 : \code{.cpp}
215 : using namespace vcl::solarthread;
216 :
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) ) );
222 :
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
229 :
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
235 : */
236 : template <typename ResultT, typename FuncT>
237 : inline ResultT syncExecute( FuncT const& func )
238 : {
239 : return detail::GenericSolarThreadExecutor<FuncT, ResultT>::exec(func);
240 : }
241 :
242 : template <typename FuncT>
243 0 : inline typename FuncT::result_type syncExecute( FuncT const& func )
244 : {
245 : return detail::GenericSolarThreadExecutor<
246 0 : FuncT, typename FuncT::result_type>::exec(func);
247 : }
248 :
249 : } // namespace solarthread
250 : } // namespace vcl
251 :
252 : #endif // INCLUDED_VCL_THREADEX_HXX
253 :
254 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|