Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <osl/conditn.h>
30 : : #include <osl/thread.h>
31 : : #include <tools/link.hxx>
32 : : #include <vcl/dllapi.h>
33 : :
34 : : #include "cppuhelper/exc_hlp.hxx"
35 : : #include "boost/optional.hpp"
36 : : #include <memory>
37 : :
38 : : namespace vcl
39 : : {
40 : : class VCL_DLLPUBLIC SolarThreadExecutor
41 : : {
42 : : oslCondition m_aStart;
43 : : oslCondition m_aFinish;
44 : : long m_nReturn;
45 : : bool m_bTimeout;
46 : :
47 : : DECL_DLLPRIVATE_LINK( worker, void* );
48 : :
49 : : public:
50 : : SolarThreadExecutor();
51 : : virtual ~SolarThreadExecutor();
52 : :
53 : : virtual long doIt() = 0;
54 : 0 : long execute() { return impl_execute( NULL ); }
55 : : // caution: timeout for getting the solar mutex, not for ending
56 : : // the operation of doIt(). If doIt actually gets called within
57 : : // the specified timeout, execute will only return after
58 : : // doIt() completed
59 : : long execute( const TimeValue& _rTimeout ) { return impl_execute( &_rTimeout ); }
60 : :
61 : : public:
62 : : bool didTimeout() const { return m_bTimeout; }
63 : :
64 : : private:
65 : : long impl_execute( const TimeValue* _pTimeout );
66 : : };
67 : :
68 : : namespace solarthread {
69 : :
70 : : /// @internal
71 : : namespace detail {
72 : :
73 : : template <typename FuncT, typename ResultT>
74 : 0 : class GenericSolarThreadExecutor : public SolarThreadExecutor
75 : : {
76 : : public:
77 : 0 : static ResultT exec( FuncT const& func )
78 : : {
79 : : typedef GenericSolarThreadExecutor<FuncT, ResultT> ExecutorT;
80 : 0 : ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
81 : 0 : pExecutor->execute();
82 : : #if ! defined(EXCEPTIONS_OFF)
83 : 0 : if (pExecutor->m_exc.hasValue())
84 : 0 : ::cppu::throwException( pExecutor->m_exc );
85 : : #endif
86 : 0 : return *pExecutor->m_result;
87 : : }
88 : :
89 : : private:
90 : 0 : explicit GenericSolarThreadExecutor( FuncT const& func )
91 : 0 : : m_exc(), m_func(func), m_result() {}
92 : :
93 : 0 : virtual long doIt()
94 : : {
95 : : #if defined(EXCEPTIONS_OFF)
96 : : m_result.reset( m_func() );
97 : : #else
98 : : try {
99 : 0 : m_result.reset( m_func() );
100 : : }
101 : 0 : catch (::com::sun::star::uno::Exception &) {
102 : : // only UNO exceptions can be dispatched:
103 : 0 : m_exc = ::cppu::getCaughtException();
104 : : }
105 : : #endif
106 : 0 : return 0;
107 : : }
108 : :
109 : : ::com::sun::star::uno::Any m_exc;
110 : : FuncT const m_func;
111 : : // using boost::optional here omits the need that ResultT is default
112 : : // constructable:
113 : : ::boost::optional<ResultT> m_result;
114 : : };
115 : :
116 : : template <typename FuncT>
117 : : class GenericSolarThreadExecutor<FuncT, void> : public SolarThreadExecutor
118 : : {
119 : : public:
120 : : static void exec( FuncT const& func )
121 : : {
122 : : typedef GenericSolarThreadExecutor<FuncT, void> ExecutorT;
123 : : ::std::auto_ptr<ExecutorT> const pExecutor( new ExecutorT(func) );
124 : : pExecutor->execute();
125 : : #if ! defined(EXCEPTIONS_OFF)
126 : : if (pExecutor->m_exc.hasValue())
127 : : ::cppu::throwException( pExecutor->m_exc );
128 : : #endif
129 : : }
130 : :
131 : : private:
132 : : explicit GenericSolarThreadExecutor( FuncT const& func )
133 : : : m_exc(), m_func(func) {}
134 : :
135 : : virtual long doIt()
136 : : {
137 : : #if defined(EXCEPTIONS_OFF)
138 : : m_func();
139 : : #else
140 : : try {
141 : : m_func();
142 : : }
143 : : catch (::com::sun::star::uno::Exception &) {
144 : : // only UNO exceptions can be dispatched:
145 : : m_exc = ::cppu::getCaughtException();
146 : : }
147 : : #endif
148 : : return 0;
149 : : }
150 : :
151 : : ::com::sun::star::uno::Any m_exc;
152 : : FuncT const m_func;
153 : : };
154 : :
155 : : template <typename T>
156 : : class copy_back_wrapper
157 : : {
158 : : public:
159 : : operator T *() const { return &m_holder->m_value; }
160 : : operator T &() const { return m_holder->m_value; }
161 : :
162 : : explicit copy_back_wrapper( T * p ) : m_holder( new data_holder(p) ) {}
163 : :
164 : : // no thread-safe counting needed here, because calling thread blocks
165 : : // until solar thread has executed the functor.
166 : : copy_back_wrapper( copy_back_wrapper<T> const& r )
167 : : : m_holder(r.m_holder) { ++m_holder->m_refCount; }
168 : : ~copy_back_wrapper() {
169 : : --m_holder->m_refCount;
170 : : if (m_holder->m_refCount == 0) {
171 : : delete m_holder;
172 : : }
173 : : }
174 : : private:
175 : : struct data_holder {
176 : : T m_value;
177 : : T * const m_ptr;
178 : : sal_Int32 m_refCount;
179 : : data_holder( T * p ) : m_value(*p), m_ptr(p), m_refCount(1) {}
180 : : ~data_holder() { *m_ptr = m_value; }
181 : : };
182 : : data_holder * const m_holder;
183 : : };
184 : :
185 : : } // namespace detail
186 : :
187 : : /** Makes a copy back reference wrapper to be used for inout parameters.
188 : : Only use for syncExecute(), the returned wrapper relies on its
189 : : implemenation, i.e. the function object is stored in free store.
190 : : Type T needs to be copy constructable assignable.
191 : :
192 : : @see syncExecute()
193 : : @param r reference to a stack variable
194 : : @return reference wrapper
195 : : */
196 : : template <typename T>
197 : : inline detail::copy_back_wrapper<T> inout_by_ref( T & r )
198 : : {
199 : : return detail::copy_back_wrapper<T>(&r);
200 : : }
201 : :
202 : : /** Makes a copy back ptr wrapper to be used for inout parameters.
203 : : Only use for syncExecute(), the returned wrapper relies on its
204 : : implemenation, i.e. the function object is stored in free store.
205 : : Type T needs to be copy constructable assignable.
206 : :
207 : : @see syncExecute()
208 : : @param p pointer to a stack variable
209 : : @return ptr wrapper
210 : : */
211 : : template <typename T>
212 : : inline detail::copy_back_wrapper<T> inout_by_ptr( T * p )
213 : : {
214 : : return detail::copy_back_wrapper<T>(p);
215 : : }
216 : :
217 : : /** This function will execute the passed functor synchronously in the
218 : : solar thread, thus the calling thread will (eventually) be blocked until
219 : : the functor has been called.
220 : : Any UNO exception that came up calling the functor in the solar thread
221 : : will be caught and rethrown in the calling thread. Any non-UNO
222 : : exception needs to be handled by the called functor.
223 : : The result type of this function needs to be default constructable.
224 : : Please keep in mind not to pass addresses to stack variables
225 : : (e.g. for out parameters) to foreign threads, use inout_by_ref()
226 : : for this purpose. For in parameters, this may not affect you, because
227 : : the functor object is copy constructed into free store. This way
228 : : you must not use boost::cref()/boost::ref() or similar for objects on
229 : : your thread's stack.
230 : : Use inout_by_ref() or inout_by_ptr() for this purpose, e.g.
231 : :
232 : : <pre>
233 : : using namespace vcl::solarthread;
234 : :
235 : : long n = 3;
236 : : // calling foo( long & r ):
237 : : syncExecute( boost::bind( &foo, inout_by_ref(n) ) );
238 : : // calling foo( long * p ):
239 : : syncExecute( boost::bind( &foo, inout_by_ptr(&n) ) );
240 : :
241 : : char const* pc = "default";
242 : : // calling foo( char const** ppc ):
243 : : syncExecute( boost::bind( &foo, inout_by_ptr(&pc) ) );
244 : : // calling foo( char const*& rpc ):
245 : : syncExecute( boost::bind( &foo, inout_by_ref(pc) ) );
246 : : </pre>
247 : :
248 : : @tpl ResultT result type, defaults to FuncT::result_type to seamlessly
249 : : support mem_fn and bind
250 : : @tpl FuncT functor type, let your compiler deduce this type
251 : : @param func functor object to be executed in solar thread
252 : : @return return value of functor
253 : : */
254 : : template <typename ResultT, typename FuncT>
255 : : inline ResultT syncExecute( FuncT const& func )
256 : : {
257 : : return detail::GenericSolarThreadExecutor<FuncT, ResultT>::exec(func);
258 : : }
259 : :
260 : : template <typename FuncT>
261 : 0 : inline typename FuncT::result_type syncExecute( FuncT const& func )
262 : : {
263 : : return detail::GenericSolarThreadExecutor<
264 : 0 : FuncT, typename FuncT::result_type>::exec(func);
265 : : }
266 : :
267 : : } // namespace solarthread
268 : : } // namespace vcl
269 : :
270 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|