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 <comphelper/asyncnotification.hxx> 21 #include <osl/mutex.hxx> 22 #include <osl/conditn.hxx> 23 #include <rtl/instance.hxx> 24 25 #include <cassert> 26 #include <deque> 27 #include <stdexcept> 28 #include <vector> 29 #include <algorithm> 30 31 namespace comphelper 32 { AnyEvent()33 AnyEvent::AnyEvent() 34 { 35 } 36 ~AnyEvent()37 AnyEvent::~AnyEvent() 38 { 39 } 40 41 namespace { 42 43 struct ProcessableEvent 44 { 45 AnyEventRef aEvent; 46 ::rtl::Reference< IEventProcessor > xProcessor; 47 ProcessableEventcomphelper::__anona54325cc0111::ProcessableEvent48 ProcessableEvent() 49 { 50 } 51 ProcessableEventcomphelper::__anona54325cc0111::ProcessableEvent52 ProcessableEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor ) 53 :aEvent( _rEvent ) 54 ,xProcessor( _xProcessor ) 55 { 56 } 57 }; 58 59 } 60 61 typedef std::deque< ProcessableEvent > EventQueue; 62 63 namespace { 64 65 struct EqualProcessor 66 { 67 const ::rtl::Reference< IEventProcessor >& rProcessor; EqualProcessorcomphelper::__anona54325cc0211::EqualProcessor68 explicit EqualProcessor( const ::rtl::Reference< IEventProcessor >& _rProcessor ) :rProcessor( _rProcessor ) { } 69 operator ()comphelper::__anona54325cc0211::EqualProcessor70 bool operator()( const ProcessableEvent& _rEvent ) 71 { 72 return _rEvent.xProcessor.get() == rProcessor.get(); 73 } 74 }; 75 76 } 77 78 struct EventNotifierImpl 79 { 80 ::osl::Mutex aMutex; 81 ::osl::Condition aPendingActions; 82 EventQueue aEvents; 83 bool bTerminate; 84 // only used for AsyncEventNotifierAutoJoin 85 char const* name; 86 std::shared_ptr<AsyncEventNotifierAutoJoin> pKeepThisAlive; 87 EventNotifierImplcomphelper::EventNotifierImpl88 EventNotifierImpl() 89 : bTerminate(false) 90 , name(nullptr) 91 { 92 } 93 }; 94 AsyncEventNotifierBase()95 AsyncEventNotifierBase::AsyncEventNotifierBase() 96 : m_xImpl(new EventNotifierImpl) 97 { 98 } 99 100 ~AsyncEventNotifierBase()101 AsyncEventNotifierBase::~AsyncEventNotifierBase() 102 { 103 } 104 105 removeEventsForProcessor(const::rtl::Reference<IEventProcessor> & _xProcessor)106 void AsyncEventNotifierBase::removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor ) 107 { 108 ::osl::MutexGuard aGuard( m_xImpl->aMutex ); 109 110 // remove all events for this processor 111 m_xImpl->aEvents.erase(std::remove_if( m_xImpl->aEvents.begin(), m_xImpl->aEvents.end(), EqualProcessor( _xProcessor ) ), m_xImpl->aEvents.end()); 112 } 113 114 terminate()115 void SAL_CALL AsyncEventNotifierBase::terminate() 116 { 117 ::osl::MutexGuard aGuard( m_xImpl->aMutex ); 118 119 // remember the termination request 120 m_xImpl->bTerminate = true; 121 122 // awake the thread 123 m_xImpl->aPendingActions.set(); 124 } 125 126 addEvent(const AnyEventRef & _rEvent,const::rtl::Reference<IEventProcessor> & _xProcessor)127 void AsyncEventNotifierBase::addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor ) 128 { 129 ::osl::MutexGuard aGuard( m_xImpl->aMutex ); 130 131 // remember this event 132 m_xImpl->aEvents.emplace_back( _rEvent, _xProcessor ); 133 134 // awake the thread 135 m_xImpl->aPendingActions.set(); 136 } 137 138 execute()139 void AsyncEventNotifierBase::execute() 140 { 141 for (;;) 142 { 143 m_xImpl->aPendingActions.wait(); 144 ProcessableEvent aEvent; 145 { 146 osl::MutexGuard aGuard(m_xImpl->aMutex); 147 if (m_xImpl->bTerminate) 148 { 149 break; 150 } 151 if (!m_xImpl->aEvents.empty()) 152 { 153 aEvent = m_xImpl->aEvents.front(); 154 m_xImpl->aEvents.pop_front(); 155 } 156 if (m_xImpl->aEvents.empty()) 157 { 158 m_xImpl->aPendingActions.reset(); 159 } 160 } 161 if (aEvent.aEvent.is()) { 162 assert(aEvent.xProcessor.is()); 163 aEvent.xProcessor->processEvent(*aEvent.aEvent); 164 } 165 } 166 } 167 AsyncEventNotifier(char const * name)168 AsyncEventNotifier::AsyncEventNotifier(char const* name) 169 : salhelper::Thread(name) 170 { 171 } 172 ~AsyncEventNotifier()173 AsyncEventNotifier::~AsyncEventNotifier() 174 { 175 } 176 execute()177 void AsyncEventNotifier::execute() 178 { 179 return AsyncEventNotifierBase::execute(); 180 } 181 terminate()182 void AsyncEventNotifier::terminate() 183 { 184 return AsyncEventNotifierBase::terminate(); 185 } 186 187 namespace { 188 189 struct theNotifiersMutex : public rtl::Static<osl::Mutex, theNotifiersMutex> {}; 190 191 } 192 193 static std::vector<std::weak_ptr<AsyncEventNotifierAutoJoin>> g_Notifiers; 194 JoinAsyncEventNotifiers()195 void JoinAsyncEventNotifiers() 196 { 197 std::vector<std::weak_ptr<AsyncEventNotifierAutoJoin>> notifiers; 198 { 199 ::osl::MutexGuard g(theNotifiersMutex::get()); 200 notifiers = g_Notifiers; 201 } 202 for (std::weak_ptr<AsyncEventNotifierAutoJoin> const& wNotifier : notifiers) 203 { 204 std::shared_ptr<AsyncEventNotifierAutoJoin> const pNotifier( 205 wNotifier.lock()); 206 if (pNotifier) 207 { 208 pNotifier->terminate(); 209 pNotifier->join(); 210 } 211 } 212 // note it's possible that g_Notifiers isn't empty now in case of leaks, 213 // particularly since the UNO service manager isn't disposed yet 214 } 215 AsyncEventNotifierAutoJoin(char const * name)216 AsyncEventNotifierAutoJoin::AsyncEventNotifierAutoJoin(char const* name) 217 { 218 m_xImpl->name = name; 219 } 220 ~AsyncEventNotifierAutoJoin()221 AsyncEventNotifierAutoJoin::~AsyncEventNotifierAutoJoin() 222 { 223 ::osl::MutexGuard g(theNotifiersMutex::get()); 224 // note: this doesn't happen atomically with the refcount 225 // hence it's possible this deletes > 1 or 0 elements 226 g_Notifiers.erase( 227 std::remove_if(g_Notifiers.begin(), g_Notifiers.end(), 228 [](std::weak_ptr<AsyncEventNotifierAutoJoin> const& w) { 229 return w.expired(); 230 } ), 231 g_Notifiers.end()); 232 } 233 234 std::shared_ptr<AsyncEventNotifierAutoJoin> newAsyncEventNotifierAutoJoin(char const * name)235 AsyncEventNotifierAutoJoin::newAsyncEventNotifierAutoJoin(char const* name) 236 { 237 std::shared_ptr<AsyncEventNotifierAutoJoin> const ret( 238 new AsyncEventNotifierAutoJoin(name)); 239 ::osl::MutexGuard g(theNotifiersMutex::get()); 240 g_Notifiers.push_back(ret); 241 return ret; 242 } 243 terminate()244 void AsyncEventNotifierAutoJoin::terminate() 245 { 246 return AsyncEventNotifierBase::terminate(); 247 } 248 launch(std::shared_ptr<AsyncEventNotifierAutoJoin> const & xThis)249 void AsyncEventNotifierAutoJoin::launch(std::shared_ptr<AsyncEventNotifierAutoJoin> const& xThis) 250 { 251 // see salhelper::Thread::launch 252 xThis->m_xImpl->pKeepThisAlive = xThis; 253 try { 254 if (!xThis->create()) { 255 throw std::runtime_error("osl::Thread::create failed"); 256 } 257 } catch (...) { 258 xThis->m_xImpl->pKeepThisAlive.reset(); 259 throw; 260 } 261 } 262 run()263 void AsyncEventNotifierAutoJoin::run() 264 { 265 // see salhelper::Thread::run 266 try { 267 setName(m_xImpl->name); 268 execute(); 269 } catch (...) { 270 onTerminated(); 271 throw; 272 } 273 } 274 onTerminated()275 void AsyncEventNotifierAutoJoin::onTerminated() 276 { 277 // try to delete "this" 278 m_xImpl->pKeepThisAlive.reset(); 279 } 280 281 } // namespace comphelper 282 283 284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 285