summaryrefslogtreecommitdiffstats
path: root/include/comphelper/asyncnotification.hxx
blob: 5c2416488957d93e553f376708750120609f13d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_COMPHELPER_ASYNCNOTIFICATION_HXX
#define INCLUDED_COMPHELPER_ASYNCNOTIFICATION_HXX

#include <sal/config.h>

#include <comphelper/comphelperdllapi.h>
#include <rtl/ref.hxx>
#include <sal/types.h>
#include <salhelper/thread.hxx>
#include <salhelper/simplereferenceobject.hxx>
#include <memory>

namespace comphelper
{
    //= AnyEvent

    /** the very basic instance to hold a description of an event
    */
    class COMPHELPER_DLLPUBLIC AnyEvent : public salhelper::SimpleReferenceObject
    {
    public:
        AnyEvent();

    protected:
        virtual ~AnyEvent() override;

    private:
        AnyEvent( AnyEvent const & ) = delete;
        AnyEvent& operator=( AnyEvent const & ) = delete;
    };


    //= typedefs

    typedef ::rtl::Reference< AnyEvent >    AnyEventRef;


    //= IEventProcessor

    /** an event processor

        @see AsyncEventNotifier
    */
    class SAL_NO_VTABLE IEventProcessor
    {
    public:
        /** process a single event
        */
        virtual void processEvent( const AnyEvent& _rEvent ) = 0;

        virtual void SAL_CALL acquire() noexcept = 0;
        virtual void SAL_CALL release() noexcept = 0;

    protected:
        ~IEventProcessor() {}
    };


    //= AsyncEventNotifier

    struct EventNotifierImpl;

    /** a helper class for notifying events asynchronously

        If you need to notify certain events to external components, you usually should
        not do this while you have mutexes locked, to prevent multi-threading issues.

        However, you do not always have complete control over all mutex guards on the stack.
        If, in such a case, the listener notification is one-way, you can decide to do it
        asynchronously.

        The ->AsyncEventNotifier helps you to process such events asynchronously. Every
        event is tied to an ->IEventProcessor which is responsible for processing it.

        The AsyncEventNotifier is implemented as a thread itself, which sleeps as long as there are no
        events in the queue. As soon as you add an event, the thread is woken up, processes the event,
        and sleeps again.
    */
    class COMPHELPER_DLLPUBLIC AsyncEventNotifierBase
    {
        friend struct EventNotifierImpl;

    protected:
        std::unique_ptr<EventNotifierImpl>        m_xImpl;

        SAL_DLLPRIVATE virtual ~AsyncEventNotifierBase();

        // Thread
        SAL_DLLPRIVATE virtual void execute();

    public:
        AsyncEventNotifierBase();

        /** terminates the thread

            Note that this is a cooperative termination - if you call this from a thread different
            from the notification thread itself, then it will block until the notification thread
            finished processing the current event. If you call it from the notification thread
            itself, it will return immediately, and the thread will be terminated as soon as
            the current notification is finished.
        */
        virtual void SAL_CALL terminate();

        /** adds an event to the queue, together with the instance which is responsible for
            processing it

            @param _rEvent
                the event to add to the queue
            @param _xProcessor
                the processor for the event.<br/>
                Beware of life time issues here. If your event processor dies or becomes otherwise
                nonfunctional, you are responsible for removing all respective events from the queue.
                You can do this by calling ->removeEventsForProcessor
        */
        void addEvent( const AnyEventRef& _rEvent, const ::rtl::Reference< IEventProcessor >& _xProcessor );

        /** removes all events for the given event processor from the queue
        */
        void removeEventsForProcessor( const ::rtl::Reference< IEventProcessor >& _xProcessor );
    };

    /** This class is usable with rtl::Reference.
        As always, the thread must be joined somewhere.
     */
    class COMPHELPER_DLLPUBLIC AsyncEventNotifier final
        : public AsyncEventNotifierBase
        , public salhelper::Thread
    {

    private:
        SAL_DLLPRIVATE virtual ~AsyncEventNotifier() override;

        SAL_DLLPRIVATE virtual void execute() override;

    public:
        /** constructs a notifier thread

            @param name the thread name, see ::osl_setThreadName; must not be
            null
        */
        AsyncEventNotifier(char const* name);

        virtual void SAL_CALL terminate() override;
    };

    /** This is a hack (when proper joining is not possible), use of which
        should be avoided by good design.
     */
    class COMPHELPER_DLLPUBLIC AsyncEventNotifierAutoJoin final
        : public AsyncEventNotifierBase
        , private osl::Thread
    {

    private:
        SAL_DLLPRIVATE AsyncEventNotifierAutoJoin(char const* name);

        SAL_DLLPRIVATE virtual void SAL_CALL run() override;
        SAL_DLLPRIVATE virtual void SAL_CALL onTerminated() override;

    public:
        // only public so shared_ptr finds it
        SAL_DLLPRIVATE virtual ~AsyncEventNotifierAutoJoin() override;

        static std::shared_ptr<AsyncEventNotifierAutoJoin>
            newAsyncEventNotifierAutoJoin(char const* name);

        virtual void SAL_CALL terminate() override;

        using osl::Thread::join;
        using osl::Thread::operator new;
        using osl::Thread::operator delete; // clang really wants this?

        static void launch(std::shared_ptr<AsyncEventNotifierAutoJoin> const&);
    };


    //= EventHolder

    /** AnyEvent derivee holding a foreign event instance
    */
    template < typename EVENT_OBJECT >
    class SAL_DLLPUBLIC_RTTI EventHolder final : public AnyEvent
    {
    public:
        typedef EVENT_OBJECT    EventObjectType;

    private:
        EventObjectType const m_aEvent;

    public:
        EventHolder( EventObjectType _aEvent )
            :m_aEvent(std::move( _aEvent ))
        {
        }

        const EventObjectType& getEventObject() const { return m_aEvent; }
    };

    COMPHELPER_DLLPUBLIC void JoinAsyncEventNotifiers();

} // namespace comphelper


#endif // INCLUDED_COMPHELPER_ASYNCNOTIFICATION_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */