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 
41  namespace {
42 
43  struct ProcessableEvent
44  {
47 
48  ProcessableEvent()
49  {
50  }
51 
52  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;
68  explicit EqualProcessor( const ::rtl::Reference< IEventProcessor >& _rProcessor ) :rProcessor( _rProcessor ) { }
69 
70  bool operator()( const ProcessableEvent& _rEvent )
71  {
72  return _rEvent.xProcessor.get() == rProcessor.get();
73  }
74  };
75 
76  }
77 
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 
89  : bTerminate(false)
90  , name(nullptr)
91  {
92  }
93  };
94 
96  : m_xImpl(new EventNotifierImpl)
97  {
98  }
99 
100 
102  {
103  }
104 
105 
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 
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 
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 
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 
169  : salhelper::Thread(name)
170  {
171  }
172 
174  {
175  }
176 
178  {
180  }
181 
183  {
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 
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 
217  {
218  m_xImpl->name = name;
219  }
220 
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>
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 
245  {
247  }
248 
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 
264  {
265  // see salhelper::Thread::run
266  try {
267  setName(m_xImpl->name);
268  execute();
269  } catch (...) {
270  onTerminated();
271  throw;
272  }
273  }
274 
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: */
::rtl::Reference< AnyEvent > AnyEventRef
void JoinAsyncEventNotifiers()
virtual SAL_DLLPRIVATE ~AsyncEventNotifier() override
static std::shared_ptr< AsyncEventNotifierAutoJoin > newAsyncEventNotifierAutoJoin(char const *name)
virtual SAL_DLLPRIVATE ~AsyncEventNotifierBase()
std::deque< ProcessableEvent > EventQueue
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
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
void removeEventsForProcessor(const ::rtl::Reference< IEventProcessor > &_xProcessor)
removes all events for the given event processor from the queue
const ::rtl::Reference< IEventProcessor > & rProcessor
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
AnyEventRef aEvent
SAL_DLLPRIVATE AsyncEventNotifierAutoJoin(char const *name)
virtual ~AnyEvent() override
::rtl::Reference< IEventProcessor > xProcessor