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 #ifndef COMPHELPER_ASYNCNOTIFICATION_HXX
25 #define COMPHELPER_ASYNCNOTIFICATION_HXX
26 
27 #include <osl/thread.hxx>
28 #include <rtl/ref.hxx>
29 #include <comphelper/comphelperdllapi.h>
30 #include <rtl/alloc.h>
31 
32 #include <memory>
33 
34 //........................................................................
35 namespace comphelper
36 {
37 //........................................................................
38 
39     //====================================================================
40     //= AnyEvent
41 	//====================================================================
42     /** the very basic instance to hold a description of an event
43     */
44     class COMPHELPER_DLLPUBLIC AnyEvent : ::rtl::IReference
45     {
46     private:
47         oslInterlockedCount m_refCount;
48 
49     public:
50         AnyEvent();
51 
52 	    virtual oslInterlockedCount SAL_CALL acquire();
53 	    virtual oslInterlockedCount SAL_CALL release();
54 
55     protected:
56         virtual ~AnyEvent();
57 
58     private:
59         AnyEvent( AnyEvent& ); // not defined
60         void operator=( AnyEvent& ); // not defined
61     };
62 
63     //====================================================================
64     //= typedefs
65 	//====================================================================
66     typedef ::rtl::Reference< AnyEvent >    AnyEventRef;
67 
68     //====================================================================
69     //= IEventProcessor
70     //====================================================================
71     /** an event processor
72 
73         @see AsyncEventNotifier
74     */
75     class SAL_NO_VTABLE IEventProcessor
76     {
77     public:
78         /** process a single event
79         */
80         virtual void processEvent( const AnyEvent& _rEvent ) = 0;
81 
82         virtual void SAL_CALL acquire() = 0;
83         virtual void SAL_CALL release() = 0;
84     };
85 
86     //====================================================================
87     //= AsyncEventNotifier
88     //====================================================================
89     typedef ::osl::Thread  AsyncEventNotifier_TBASE;
90     struct EventNotifierImpl;
91 
92     /** a helper class for notifying events asynchronously
93 
94         If you need to notify certain events to external components, you usually should
95         not do this while you have mutexes locked, to prevent multi-threading issues.
96 
97         However, you do not always have complete control over all mutex guards on the stack.
98         If, in such a case, the listener notification is one-way, you can decide to do it
99         asynchronously.
100 
101         The ->AsyncEventNotifier helps you to process such events asynchronously. Every
102         event is tied to an ->IEventProcessor which is responsible for processing it.
103 
104         The AsyncEventNotifier is implemented as a thread itself, which sleeps as long as there are no
105         events in the queue. As soon as you add an event, the thread is woken up, processes the event,
106         and sleeps again.
107     */
108     class COMPHELPER_DLLPUBLIC AsyncEventNotifier   :protected AsyncEventNotifier_TBASE
109                                                     ,public ::rtl::IReference
110     {
111         friend struct EventNotifierImpl;
112 
113     private:
114         ::std::auto_ptr< EventNotifierImpl >        m_pImpl;
115 
116     protected:
117         // Thread
118         virtual void SAL_CALL run();
119         virtual void SAL_CALL onTerminated();
120 
121     public:
122         /** constructs a notifier thread
123         */
124         AsyncEventNotifier();
125 
126         // IReference implementations
127 	    virtual oslInterlockedCount SAL_CALL acquire();
128 	    virtual oslInterlockedCount SAL_CALL release();
129 
130         using AsyncEventNotifier_TBASE::create;
131         using AsyncEventNotifier_TBASE::join;
132         using AsyncEventNotifier_TBASE::getIdentifier;
133 
134         using AsyncEventNotifier_TBASE::operator new;
135         using AsyncEventNotifier_TBASE::operator delete;
136 
137         /** terminates the thread
138 
139             Note that this is a cooporative termination - if you call this from a thread different
140             from the notification thread itself, then it will block until the notification thread
141             finished processing the current event. If you call it from the notification thread
142             itself, it will return immediately, and the thread will be terminated as soon as
143             the current notification is finished.
144         */
145 	    virtual void SAL_CALL terminate();
146 
147         /** adds an event to the queue, together with the instance which is responsible for
148             processing it
149 
150             @param _rEvent
151                 the event to add to the queue
152             @param _xProcessor
153                 the processor for the event.<br/>
154                 Beware of life time issues here. If your event processor dies or becomes otherwise
155                 nonfunctional, you are responsible for removing all respective events from the queue.
156                 You can do this by calling ->removeEventsForProcessor
157         */
158         void addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor );
159 
160         /** removes all events for the given event processor from the queue
161         */
162         void removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor );
163 
164     protected:
165         virtual ~AsyncEventNotifier();
166     };
167 
168     //====================================================================
169     //= EventHolder
170 	//====================================================================
171     /** AnyEvent derivee holding an foreign event instance
172     */
173     template < typename EVENT_OBJECT >
174     class EventHolder : public AnyEvent
175     {
176     public:
177         typedef EVENT_OBJECT    EventObjectType;
178 
179     private:
180         EventObjectType m_aEvent;
181 
182     public:
EventHolder(const EventObjectType & _rEvent)183         inline EventHolder( const EventObjectType& _rEvent )
184             :m_aEvent( _rEvent )
185         {
186         }
187 
getEventObject() const188         inline const EventObjectType& getEventObject() const { return m_aEvent; }
189     };
190 
191 //........................................................................
192 } // namespace comphelper
193 //........................................................................
194 
195 #endif // COMPHELPER_ASYNCNOTIFICATION_HXX
196