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