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