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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <comphelper/asyncnotification.hxx>
31 #include <osl/diagnose.h>
32 #include <osl/mutex.hxx>
33 #include <osl/conditn.hxx>
34 #include <comphelper/guarding.hxx>
35 
36 #include <deque>
37 #include <set>
38 #include <functional>
39 #include <algorithm>
40 
41 //........................................................................
42 namespace comphelper
43 {
44 //........................................................................
45 
46     //====================================================================
47     //= AnyEvent
48     //====================================================================
49     //--------------------------------------------------------------------
50     AnyEvent::AnyEvent()
51         :m_refCount( 0 )
52     {
53     }
54 
55     //--------------------------------------------------------------------
56     AnyEvent::~AnyEvent()
57     {
58     }
59 
60     //--------------------------------------------------------------------
61     oslInterlockedCount SAL_CALL AnyEvent::acquire()
62     {
63         return osl_incrementInterlockedCount( &m_refCount );
64     }
65 
66     //--------------------------------------------------------------------
67     oslInterlockedCount SAL_CALL AnyEvent::release()
68     {
69         if ( 0 == osl_decrementInterlockedCount( &m_refCount ) )
70         {
71             delete this;
72             return 0;
73         }
74         return m_refCount;
75     }
76 
77     //====================================================================
78     //= ProcessableEvent
79     //====================================================================
80     struct ProcessableEvent
81     {
82         AnyEventRef                         aEvent;
83         ::rtl::Reference< IEventProcessor > xProcessor;
84 
85         ProcessableEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor )
86             :aEvent( _rEvent )
87             ,xProcessor( _xProcessor )
88         {
89         }
90 
91         ProcessableEvent( const ProcessableEvent& _rRHS )
92             :aEvent( _rRHS.aEvent )
93             ,xProcessor( _rRHS.xProcessor )
94         {
95         }
96 
97         ProcessableEvent& operator=( const ProcessableEvent& _rRHS )
98         {
99             aEvent = _rRHS.aEvent;
100             xProcessor = _rRHS.xProcessor;
101             return *this;
102         }
103     };
104 
105     //====================================================================
106     typedef ::std::deque< ProcessableEvent >    EventQueue;
107 
108     //====================================================================
109     struct EqualProcessor : public ::std::unary_function< ProcessableEvent, bool >
110     {
111         const ::rtl::Reference< IEventProcessor >&  rProcessor;
112         EqualProcessor( const ::rtl::Reference< IEventProcessor >& _rProcessor ) :rProcessor( _rProcessor ) { }
113 
114         bool operator()( const ProcessableEvent& _rEvent )
115         {
116             return _rEvent.xProcessor.get() == rProcessor.get();
117         }
118     };
119 
120     //====================================================================
121     //= EventNotifierImpl
122     //====================================================================
123     struct EventNotifierImpl
124     {
125         ::osl::Mutex        aMutex;
126         oslInterlockedCount m_refCount;
127         ::osl::Condition    aPendingActions;
128         EventQueue          aEvents;
129         ::std::set< ::rtl::Reference< IEventProcessor > >
130                             m_aDeadProcessors;
131 
132         EventNotifierImpl()
133             :m_refCount( 0 )
134         {
135         }
136 
137     private:
138         EventNotifierImpl( const EventNotifierImpl& );              // never implemented
139         EventNotifierImpl& operator=( const EventNotifierImpl& );   // never implemented
140     };
141 
142     //====================================================================
143     //= AsyncEventNotifier
144     //====================================================================
145     //--------------------------------------------------------------------
146     AsyncEventNotifier::AsyncEventNotifier()
147         :m_pImpl( new EventNotifierImpl )
148     {
149     }
150 
151     //--------------------------------------------------------------------
152     AsyncEventNotifier::~AsyncEventNotifier()
153     {
154     }
155 
156     //--------------------------------------------------------------------
157     void AsyncEventNotifier::removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor )
158     {
159         ::osl::MutexGuard aGuard( m_pImpl->aMutex );
160 
161         // remove all events for this processor
162         ::std::remove_if( m_pImpl->aEvents.begin(), m_pImpl->aEvents.end(), EqualProcessor( _xProcessor ) );
163 
164         // and just in case that an event for exactly this processor has just been
165         // popped from the queue, but not yet processed: remember it:
166         m_pImpl->m_aDeadProcessors.insert( _xProcessor );
167     }
168 
169     //--------------------------------------------------------------------
170     void SAL_CALL AsyncEventNotifier::terminate()
171     {
172         ::osl::MutexGuard aGuard( m_pImpl->aMutex );
173 
174         // remember the termination request
175         AsyncEventNotifier_TBASE::terminate();
176 
177         // awake the thread
178         m_pImpl->aPendingActions.set();
179     }
180 
181     //--------------------------------------------------------------------
182     void AsyncEventNotifier::addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor )
183     {
184         ::osl::MutexGuard aGuard( m_pImpl->aMutex );
185 
186         OSL_TRACE( "AsyncEventNotifier(%p): adding %p\n", this, _rEvent.get() );
187         // remember this event
188         m_pImpl->aEvents.push_back( ProcessableEvent( _rEvent, _xProcessor ) );
189 
190         // awake the thread
191         m_pImpl->aPendingActions.set();
192     }
193 
194     //--------------------------------------------------------------------
195     void AsyncEventNotifier::run()
196     {
197         acquire();
198 
199         // keep us alive, in case we're terminated in the mid of the following
200         ::rtl::Reference< AsyncEventNotifier > xKeepAlive( this );
201 
202         do
203         {
204             AnyEventRef aNextEvent;
205             ::rtl::Reference< IEventProcessor > xNextProcessor;
206 
207             ::osl::ClearableMutexGuard aGuard( m_pImpl->aMutex );
208             while ( m_pImpl->aEvents.size() > 0 )
209             {
210                 ProcessableEvent aEvent( m_pImpl->aEvents.front() );
211                 aNextEvent = aEvent.aEvent;
212                 xNextProcessor = aEvent.xProcessor;
213                 m_pImpl->aEvents.pop_front();
214 
215                 OSL_TRACE( "AsyncEventNotifier(%p): popping %p\n", this, aNextEvent.get() );
216 
217                 if ( !aNextEvent.get() )
218                     continue;
219 
220                 // process the event, but only if it's processor did not die inbetween
221                 ::std::set< ::rtl::Reference< IEventProcessor > >::iterator deadPos = m_pImpl->m_aDeadProcessors.find( xNextProcessor );
222                 if ( deadPos != m_pImpl->m_aDeadProcessors.end() )
223                 {
224                     m_pImpl->m_aDeadProcessors.erase( xNextProcessor );
225                     xNextProcessor.clear();
226                     OSL_TRACE( "AsyncEventNotifier(%p): removing %p\n", this, aNextEvent.get() );
227                 }
228 
229                 // if there was a termination request (->terminate), respect it
230                 if ( !schedule() )
231                     return;
232 
233                 {
234                     ::comphelper::MutexRelease aReleaseOnce( m_pImpl->aMutex );
235                     if ( xNextProcessor.get() )
236                         xNextProcessor->processEvent( *aNextEvent.get() );
237                 }
238             }
239 
240             // if there was a termination request (->terminate), respect it
241             if ( !schedule() )
242                 return;
243 
244             // wait for new events to process
245             aGuard.clear();
246             m_pImpl->aPendingActions.reset();
247             m_pImpl->aPendingActions.wait();
248         }
249         while ( sal_True );
250     }
251 
252     //--------------------------------------------------------------------
253     void SAL_CALL AsyncEventNotifier::onTerminated()
254     {
255         AsyncEventNotifier_TBASE::onTerminated();
256         // when we were started (->run), we aquired ourself. Release this now
257         // that we were finally terminated
258         release();
259     }
260 
261     //--------------------------------------------------------------------
262 	oslInterlockedCount SAL_CALL AsyncEventNotifier::acquire()
263     {
264         return osl_incrementInterlockedCount( &m_pImpl->m_refCount );
265     }
266 
267     //--------------------------------------------------------------------
268 	oslInterlockedCount SAL_CALL AsyncEventNotifier::release()
269     {
270         if ( 0 == osl_decrementInterlockedCount( &m_pImpl->m_refCount ) )
271         {
272             delete this;
273             return 0;
274         }
275         return m_pImpl->m_refCount;
276     }
277 
278 //........................................................................
279 } // namespace comphelper
280 //........................................................................
281 
282