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