LibreOffice Module comphelper (master)  1
asyncnotification.cxx
Go to the documentation of this file.
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 
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 {
34  {
35  }
36 
38  {
39  }
40 
42  {
45 
47  {
48  }
49 
50  ProcessableEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor )
51  :aEvent( _rEvent )
52  ,xProcessor( _xProcessor )
53  {
54  }
55  };
56 
57 
58  typedef std::deque< ProcessableEvent > EventQueue;
59 
60 
62  {
63  const ::rtl::Reference< IEventProcessor >& rProcessor;
64  explicit EqualProcessor( const ::rtl::Reference< IEventProcessor >& _rProcessor ) :rProcessor( _rProcessor ) { }
65 
66  bool operator()( const ProcessableEvent& _rEvent )
67  {
68  return _rEvent.xProcessor.get() == rProcessor.get();
69  }
70  };
71 
73  {
74  ::osl::Mutex aMutex;
75  ::osl::Condition aPendingActions;
76  EventQueue aEvents;
77  bool bTerminate;
78  // only used for AsyncEventNotifierAutoJoin
79  char const* name;
80  std::shared_ptr<AsyncEventNotifierAutoJoin> pKeepThisAlive;
81 
83  : bTerminate(false)
84  , name(nullptr)
85  {
86  }
87  };
88 
90  : m_xImpl(new EventNotifierImpl)
91  {
92  }
93 
94 
96  {
97  }
98 
99 
100  void AsyncEventNotifierBase::removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor )
101  {
102  ::osl::MutexGuard aGuard( m_xImpl->aMutex );
103 
104  // remove all events for this processor
105  m_xImpl->aEvents.erase(std::remove_if( m_xImpl->aEvents.begin(), m_xImpl->aEvents.end(), EqualProcessor( _xProcessor ) ), m_xImpl->aEvents.end());
106  }
107 
108 
110  {
111  ::osl::MutexGuard aGuard( m_xImpl->aMutex );
112 
113  // remember the termination request
114  m_xImpl->bTerminate = true;
115 
116  // awake the thread
117  m_xImpl->aPendingActions.set();
118  }
119 
120 
121  void AsyncEventNotifierBase::addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor )
122  {
123  ::osl::MutexGuard aGuard( m_xImpl->aMutex );
124 
125  // remember this event
126  m_xImpl->aEvents.emplace_back( _rEvent, _xProcessor );
127 
128  // awake the thread
129  m_xImpl->aPendingActions.set();
130  }
131 
132 
134  {
135  for (;;)
136  {
137  m_xImpl->aPendingActions.wait();
138  ProcessableEvent aEvent;
139  {
140  osl::MutexGuard aGuard(m_xImpl->aMutex);
141  if (m_xImpl->bTerminate)
142  {
143  break;
144  }
145  if (!m_xImpl->aEvents.empty())
146  {
147  aEvent = m_xImpl->aEvents.front();
148  m_xImpl->aEvents.pop_front();
149  }
150  if (m_xImpl->aEvents.empty())
151  {
152  m_xImpl->aPendingActions.reset();
153  }
154  }
155  if (aEvent.aEvent.is()) {
156  assert(aEvent.xProcessor.is());
157  aEvent.xProcessor->processEvent(*aEvent.aEvent);
158  }
159  }
160  }
161 
163  : salhelper::Thread(name)
164  {
165  }
166 
168  {
169  }
170 
172  {
174  }
175 
177  {
179  }
180 
181  struct theNotifiersMutex : public rtl::Static<osl::Mutex, theNotifiersMutex> {};
182  static std::vector<std::weak_ptr<AsyncEventNotifierAutoJoin>> g_Notifiers;
183 
185  {
186  std::vector<std::weak_ptr<AsyncEventNotifierAutoJoin>> notifiers;
187  {
188  ::osl::MutexGuard g(theNotifiersMutex::get());
189  notifiers = g_Notifiers;
190  }
191  for (std::weak_ptr<AsyncEventNotifierAutoJoin> const& wNotifier : notifiers)
192  {
193  std::shared_ptr<AsyncEventNotifierAutoJoin> const pNotifier(
194  wNotifier.lock());
195  if (pNotifier)
196  {
197  pNotifier->terminate();
198  pNotifier->join();
199  }
200  }
201  // note it's possible that g_Notifiers isn't empty now in case of leaks,
202  // particularly since the UNO service manager isn't disposed yet
203  }
204 
206  {
207  m_xImpl->name = name;
208  }
209 
211  {
212  ::osl::MutexGuard g(theNotifiersMutex::get());
213  // note: this doesn't happen atomically with the refcount
214  // hence it's possible this deletes > 1 or 0 elements
215  g_Notifiers.erase(
216  std::remove_if(g_Notifiers.begin(), g_Notifiers.end(),
217  [](std::weak_ptr<AsyncEventNotifierAutoJoin> const& w) {
218  return w.expired();
219  } ),
220  g_Notifiers.end());
221  }
222 
223  std::shared_ptr<AsyncEventNotifierAutoJoin>
225  {
226  std::shared_ptr<AsyncEventNotifierAutoJoin> const ret(
227  new AsyncEventNotifierAutoJoin(name));
228  ::osl::MutexGuard g(theNotifiersMutex::get());
229  g_Notifiers.push_back(ret);
230  return ret;
231  }
232 
234  {
236  }
237 
238  void AsyncEventNotifierAutoJoin::launch(std::shared_ptr<AsyncEventNotifierAutoJoin> const& xThis)
239  {
240  // see salhelper::Thread::launch
241  xThis->m_xImpl->pKeepThisAlive = xThis;
242  try {
243  if (!xThis->create()) {
244  throw std::runtime_error("osl::Thread::create failed");
245  }
246  } catch (...) {
247  xThis->m_xImpl->pKeepThisAlive.reset();
248  throw;
249  }
250  }
251 
253  {
254  // see salhelper::Thread::run
255  try {
256  setName(m_xImpl->name);
257  execute();
258  } catch (...) {
259  onTerminated();
260  throw;
261  }
262  }
263 
265  {
266  // try to delete "this"
267  m_xImpl->pKeepThisAlive.reset();
268  }
269 
270 } // namespace comphelper
271 
272 
273 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool operator()(const ProcessableEvent &_rEvent)
void JoinAsyncEventNotifiers()
virtual SAL_DLLPRIVATE ~AsyncEventNotifier() override
static std::shared_ptr< AsyncEventNotifierAutoJoin > newAsyncEventNotifierAutoJoin(char const *name)
virtual SAL_DLLPRIVATE ~AsyncEventNotifierBase()
std::deque< ProcessableEvent > EventQueue
virtual SAL_DLLPRIVATE void SAL_CALL run() override
std::shared_ptr< AsyncEventNotifierAutoJoin > pKeepThisAlive
AsyncEventNotifier(char const *name)
constructs a notifier thread
static void launch(std::shared_ptr< AsyncEventNotifierAutoJoin > const &)
void addEvent(const AnyEventRef &_rEvent, const ::rtl::Reference< IEventProcessor > &_xProcessor)
adds an event to the queue, together with the instance which is responsible for processing it ...
sal_Int32 w
virtual void SAL_CALL terminate()
terminates the thread
virtual SAL_DLLPRIVATE void SAL_CALL onTerminated() override
ProcessableEvent(const AnyEventRef &_rEvent, const ::rtl::Reference< IEventProcessor > &_xProcessor)
void removeEventsForProcessor(const ::rtl::Reference< IEventProcessor > &_xProcessor)
removes all events for the given event processor from the queue
virtual SAL_DLLPRIVATE void execute()
virtual void SAL_CALL terminate() override
terminates the thread
static std::vector< std::weak_ptr< AsyncEventNotifierAutoJoin > > g_Notifiers
virtual SAL_DLLPRIVATE ~AsyncEventNotifierAutoJoin() override
virtual SAL_DLLPRIVATE void execute() override
virtual void SAL_CALL terminate() override
terminates the thread
std::unique_ptr< EventNotifierImpl > m_xImpl
EqualProcessor(const ::rtl::Reference< IEventProcessor > &_rProcessor)
const ::rtl::Reference< IEventProcessor > & rProcessor
SAL_DLLPRIVATE AsyncEventNotifierAutoJoin(char const *name)
virtual ~AnyEvent() override
::rtl::Reference< IEventProcessor > xProcessor