Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */