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 : #if ! defined(EXCEPTIONS_OFF)
74 0 : if (pExecutor->m_exc.hasValue())
75 0 : ::cppu::throwException( pExecutor->m_exc );
76 : #endif
77 0 : return *pExecutor->m_result;
78 : }
79 :
80 : private:
81 0 : explicit GenericSolarThreadExecutor( FuncT const& func )
82 0 : : m_exc(), m_func(func), m_result() {}
83 :
84 0 : virtual long doIt()
85 : {
86 : #if defined(EXCEPTIONS_OFF)
87 : m_result.reset( m_func() );
88 : #else
89 : try {
90 0 : m_result.reset( m_func() );
91 : }
92 0 : catch (::com::sun::star::uno::Exception &) {
93 : // only UNO exceptions can be dispatched:
94 0 : m_exc = ::cppu::getCaughtException();
95 : }
96 : #endif
97 0 : return 0;
98 : }
99 :
100 : ::com::sun::star::uno::Any m_exc;
101 : FuncT const m_func;
102 : // using boost::optional here omits the need that ResultT is default
103 : // constructable:
104 : ::boost::optional<ResultT> m_result;
105 : };
106 :
107 : template <typename FuncT>
108 : class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
109 : {
110 : public:
111 : static void exec( FuncT const& func )
112 : {
113 : typedef GenericSolarThreadExecutor<FuncT, void> ExecutorT;
114 : ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
115 : pExecutor->execute();
116 : #if ! defined(EXCEPTIONS_OFF)
117 : if (pExecutor->m_exc.hasValue())
118 : ::cppu::throwException( pExecutor->m_exc );
119 : #endif
120 : }
121 :
122 : private:
123 : explicit GenericSolarThreadExecutor( FuncT const& func )
124 : : m_exc(), m_func(func) {}
125 :
126 : virtual long doIt()
127 : {
128 : #if defined(EXCEPTIONS_OFF)
129 : m_func();
130 : #else
131 : try {
132 : m_func();
133 : }
134 : catch (::com::sun::star::uno::Exception &) {
135 : // only UNO exceptions can be dispatched:
136 : m_exc = ::cppu::getCaughtException();
137 : }
138 : #endif
139 : return 0;
140 : }
141 :
142 : ::com::sun::star::uno::Any m_exc;
143 : FuncT const m_func;
144 : };
145 :
146 : template <typename T>
147 : class copy_back_wrapper
148 : {
149 : public:
150 : operator T *() const { return &m_holder->m_value; }
151 : operator T &() const { return m_holder->m_value; }
152 :
153 : explicit copy_back_wrapper( T * p ) : m_holder( new data_holder(p) ) {}
154 :
155 : // no thread-safe counting needed here, because calling thread blocks
156 : // until solar thread has executed the functor.
157 : copy_back_wrapper( copy_back_wrapper<T> const& r )
158 : : m_holder(r.m_holder) { ++m_holder->m_refCount; }
159 : ~copy_back_wrapper() {
160 : --m_holder->m_refCount;
161 : if (m_holder->m_refCount == 0) {
162 : delete m_holder;
163 : }
164 : }
165 : private:
166 : struct data_holder {
167 : T m_value;
168 : T * const m_ptr;
169 : sal_Int32 m_refCount;
170 : data_holder( T * p ) : m_value(*p), m_ptr(p), m_refCount(1) {}
171 : ~data_holder() { *m_ptr = m_value; }
172 : };
173 : data_holder * const m_holder;
174 : };
175 :
176 : } // namespace detail
177 :
178 : /** Makes a copy back reference wrapper to be used for inout parameters.
179 : Only use for syncExecute(), the returned wrapper relies on its
180 : implemenation, i.e. the function object is stored in free store.
181 : Type T needs to be copy constructable assignable.
182 :
183 : @see syncExecute()
184 : @param r reference to a stack variable
185 : @return reference wrapper
186 : */
187 : template <typename T>
188 : inline detail::copy_back_wrapper<T> inout_by_ref( T & r )
189 : {
190 : return detail::copy_back_wrapper<T>(&r);
191 : }
192 :
193 : /** Makes a copy back ptr wrapper to be used for inout parameters.
194 : Only use for syncExecute(), the returned wrapper relies on its
195 : implemenation, i.e. the function object is stored in free store.
196 : Type T needs to be copy constructable assignable.
197 :
198 : @see syncExecute()
199 : @param p pointer to a stack variable
200 : @return ptr wrapper
201 : */
202 : template <typename T>
203 : inline detail::copy_back_wrapper<T> inout_by_ptr( T * p )
204 : {
205 : return detail::copy_back_wrapper<T>(p);
206 : }
207 :
208 : /** This function will execute the passed functor synchronously in the
209 : solar thread, thus the calling thread will (eventually) be blocked until
210 : the functor has been called.
211 : Any UNO exception that came up calling the functor in the solar thread
212 : will be caught and rethrown in the calling thread. Any non-UNO
213 : exception needs to be handled by the called functor.
214 : The result type of this function needs to be default constructable.
215 : Please keep in mind not to pass addresses to stack variables
216 : (e.g. for out parameters) to foreign threads, use inout_by_ref()
217 : for this purpose. For in parameters, this may not affect you, because
218 : the functor object is copy constructed into free store. This way
219 : you must not use boost::cref()/boost::ref() or similar for objects on
220 : your thread's stack.
221 : Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
222 :
223 : <pre>
224 : using namespace vcl::solarthread;
225 :
226 : long n = 3;
227 : // calling foo( long & r ):
228 : syncExecute( boost::bind( &foo, inout_by_ref(n) ) );
229 : // calling foo( long * p ):
230 : syncExecute( boost::bind( &foo, inout_by_ptr(&n) ) );
231 :
232 : char const* pc = "default";
233 : // calling foo( char const** ppc ):
234 : syncExecute( boost::bind( &foo, inout_by_ptr(&pc) ) );
235 : // calling foo( char const*& rpc ):
236 : syncExecute( boost::bind( &foo, inout_by_ref(pc) ) );
237 : </pre>
238 :
239 : @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
240 : support mem_fn and bind
241 : @tpl FuncT functor type, let your compiler deduce this type
242 : @param func functor object to be executed in solar thread
243 : @return return value of functor
244 : */
245 : template <typename ResultT, typename FuncT>
246 : inline ResultT syncExecute( FuncT const& func )
247 : {
248 : return detail::GenericSolarThreadExecutor<FuncT, ResultT>::exec(func);
249 : }
250 :
251 : template <typename FuncT>
252 0 : inline typename FuncT::result_type syncExecute( FuncT const& func )
253 : {
254 : return detail::GenericSolarThreadExecutor<
255 0 : FuncT, typename FuncT::result_type>::exec(func);
256 : }
257 :
258 : } // namespace solarthread
259 : } // namespace vcl
260 :
261 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|