/src/libreoffice/include/comphelper/asyncnotification.hxx
Line | Count | Source |
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 | | #pragma once |
21 | | |
22 | | #include <sal/config.h> |
23 | | #include <config_options.h> |
24 | | |
25 | | #include <com/sun/star/document/DocumentEvent.hpp> |
26 | | #include <comphelper/comphelperdllapi.h> |
27 | | #include <rtl/ref.hxx> |
28 | | #include <sal/types.h> |
29 | | #include <salhelper/thread.hxx> |
30 | | #include <salhelper/simplereferenceobject.hxx> |
31 | | #include <memory> |
32 | | |
33 | | namespace comphelper |
34 | | { |
35 | | //= AnyEvent |
36 | | |
37 | | /** the very basic instance to hold a description of an event |
38 | | */ |
39 | | class COMPHELPER_DLLPUBLIC AnyEvent : public salhelper::SimpleReferenceObject |
40 | | { |
41 | | public: |
42 | | AnyEvent(); |
43 | | |
44 | | protected: |
45 | | virtual ~AnyEvent() override; |
46 | | |
47 | | private: |
48 | | AnyEvent( AnyEvent const & ) = delete; |
49 | | AnyEvent& operator=( AnyEvent const & ) = delete; |
50 | | }; |
51 | | |
52 | | |
53 | | //= typedefs |
54 | | |
55 | | typedef ::rtl::Reference< AnyEvent > AnyEventRef; |
56 | | |
57 | | |
58 | | //= IEventProcessor |
59 | | |
60 | | /** an event processor |
61 | | |
62 | | @see AsyncEventNotifier |
63 | | */ |
64 | | class SAL_NO_VTABLE IEventProcessor |
65 | | { |
66 | | public: |
67 | | /** process a single event |
68 | | */ |
69 | | virtual void processEvent( const AnyEvent& _rEvent ) = 0; |
70 | | |
71 | | virtual void SAL_CALL acquire() noexcept = 0; |
72 | | virtual void SAL_CALL release() noexcept = 0; |
73 | | |
74 | | protected: |
75 | 0 | ~IEventProcessor() {} |
76 | | }; |
77 | | |
78 | | |
79 | | //= AsyncEventNotifier |
80 | | |
81 | | struct EventNotifierImpl; |
82 | | |
83 | | /** a helper class for notifying events asynchronously |
84 | | |
85 | | If you need to notify certain events to external components, you usually should |
86 | | not do this while you have mutexes locked, to prevent multi-threading issues. |
87 | | |
88 | | However, you do not always have complete control over all mutex guards on the stack. |
89 | | If, in such a case, the listener notification is one-way, you can decide to do it |
90 | | asynchronously. |
91 | | |
92 | | The ->AsyncEventNotifier helps you to process such events asynchronously. Every |
93 | | event is tied to an ->IEventProcessor which is responsible for processing it. |
94 | | |
95 | | The AsyncEventNotifier is implemented as a thread itself, which sleeps as long as there are no |
96 | | events in the queue. As soon as you add an event, the thread is woken up, processes the event, |
97 | | and sleeps again. |
98 | | */ |
99 | | class COMPHELPER_DLLPUBLIC AsyncEventNotifierBase |
100 | | { |
101 | | friend struct EventNotifierImpl; |
102 | | |
103 | | protected: |
104 | | std::unique_ptr<EventNotifierImpl> m_xImpl; |
105 | | |
106 | | SAL_DLLPRIVATE virtual ~AsyncEventNotifierBase(); |
107 | | |
108 | | // Thread |
109 | | SAL_DLLPRIVATE virtual void execute(); |
110 | | |
111 | | public: |
112 | | AsyncEventNotifierBase(); |
113 | | |
114 | | /** terminates the thread |
115 | | |
116 | | Note that this is a cooperative termination - if you call this from a thread different |
117 | | from the notification thread itself, then it will block until the notification thread |
118 | | finished processing the current event. If you call it from the notification thread |
119 | | itself, it will return immediately, and the thread will be terminated as soon as |
120 | | the current notification is finished. |
121 | | */ |
122 | | virtual void SAL_CALL terminate(); |
123 | | |
124 | | /** adds an event to the queue, together with the instance which is responsible for |
125 | | processing it |
126 | | |
127 | | @param _rEvent |
128 | | the event to add to the queue |
129 | | @param _xProcessor |
130 | | the processor for the event.<br/> |
131 | | Beware of life time issues here. If your event processor dies or becomes otherwise |
132 | | nonfunctional, you are responsible for removing all respective events from the queue. |
133 | | You can do this by calling ->removeEventsForProcessor |
134 | | */ |
135 | | void addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor ); |
136 | | |
137 | | /** removes all events for the given event processor from the queue |
138 | | */ |
139 | | void removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor ); |
140 | | }; |
141 | | |
142 | | /** This class is usable with rtl::Reference. |
143 | | As always, the thread must be joined somewhere. |
144 | | */ |
145 | | class COMPHELPER_DLLPUBLIC AsyncEventNotifier final |
146 | | : public AsyncEventNotifierBase |
147 | | , public salhelper::Thread |
148 | | { |
149 | | |
150 | | private: |
151 | | SAL_DLLPRIVATE virtual ~AsyncEventNotifier() override; |
152 | | |
153 | | SAL_DLLPRIVATE virtual void execute() override; |
154 | | |
155 | | public: |
156 | | /** constructs a notifier thread |
157 | | |
158 | | @param name the thread name, see ::osl_setThreadName; must not be |
159 | | null |
160 | | */ |
161 | | AsyncEventNotifier(char const* name); |
162 | | |
163 | | virtual void SAL_CALL terminate() override; |
164 | | }; |
165 | | |
166 | | /** This is a hack (when proper joining is not possible), use of which |
167 | | should be avoided by good design. |
168 | | */ |
169 | | class UNLESS_MERGELIBS_MORE(COMPHELPER_DLLPUBLIC) AsyncEventNotifierAutoJoin final |
170 | | : public AsyncEventNotifierBase |
171 | | , private osl::Thread |
172 | | { |
173 | | |
174 | | private: |
175 | | SAL_DLLPRIVATE AsyncEventNotifierAutoJoin(char const* name); |
176 | | |
177 | | SAL_DLLPRIVATE virtual void SAL_CALL run() override; |
178 | | SAL_DLLPRIVATE virtual void SAL_CALL onTerminated() override; |
179 | | |
180 | | public: |
181 | | // only public so shared_ptr finds it |
182 | | SAL_DLLPRIVATE virtual ~AsyncEventNotifierAutoJoin() override; |
183 | | |
184 | | static std::shared_ptr<AsyncEventNotifierAutoJoin> |
185 | | newAsyncEventNotifierAutoJoin(char const* name); |
186 | | |
187 | | virtual void SAL_CALL terminate() override; |
188 | | |
189 | | using osl::Thread::join; |
190 | | using osl::Thread::operator new; |
191 | | using osl::Thread::operator delete; // clang really wants this? |
192 | | |
193 | | static void launch(std::shared_ptr<AsyncEventNotifierAutoJoin> const&); |
194 | | }; |
195 | | |
196 | | |
197 | | //= EventHolder |
198 | | |
199 | | /** AnyEvent derivee holding a foreign event instance |
200 | | */ |
201 | | template < typename EVENT_OBJECT > |
202 | | class SAL_DLLPUBLIC_TEMPLATE EventHolder final : public AnyEvent |
203 | | { |
204 | | public: |
205 | | typedef EVENT_OBJECT EventObjectType; |
206 | | |
207 | | private: |
208 | | EventObjectType const m_aEvent; |
209 | | |
210 | | public: |
211 | | EventHolder( EventObjectType _aEvent ) |
212 | 0 | :m_aEvent(std::move( _aEvent )) |
213 | 0 | { |
214 | 0 | } |
215 | | |
216 | 0 | const EventObjectType& getEventObject() const { return m_aEvent; } |
217 | | }; |
218 | | |
219 | | extern template class EventHolder<css::document::DocumentEvent>; |
220 | | using DocumentEventHolder = EventHolder<css::document::DocumentEvent>; |
221 | | |
222 | | COMPHELPER_DLLPUBLIC void JoinAsyncEventNotifiers(); |
223 | | |
224 | | } // namespace comphelper |
225 | | |
226 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |