sigslot.cpp 5.32 KB
Newer Older
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
// ================================================================================================
// 
// sigslot.h/sigslot.cpp - Signal/Slot classes:
// 
// Original siglsot implementation written by Sarah Thompson (sarah@telergy.com) 2002 and 
// published under public domain. <http://sigslot.sourceforge.net/>
// 
// This version of the sigslot library is heavily modified, C++ compliant, inherently thread-safe,
// and offers a manager class that allows to queue and asynchronously dispatch signals.
// 
// Copyright (C) 2012-2014, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
// 
// Licensed 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
// 
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
// 
// ================================================================================================

29
#include <memory>
30
31
#include <new>

32
33
34
35
#include "sigslot.h"

namespace sigslot {

36
37
38
    signal_manager::signal_manager() 
        : _handlingMode(DEFAULT)
    {
39
40
41
42

    }

    signal_manager::~signal_manager() {
43
        _signalPool.recycle();
44
45
    }

46
    void signal_manager::triggerSignalImpl(_signal_handle_base* signal) {
47
        if (_handlingMode == FORCE_QUEUE) {
48
            queueSignalImpl(signal);
49
50
51
            return;
        }

52
        signal->processSignal();
53
54
55
        delete signal;
    }

56
    bool signal_manager::queueSignalImpl(_signal_handle_base* signal) {
57
        if (_handlingMode == FORCE_DIRECT) {
58
            triggerSignalImpl(signal);
59
60
61
            return true;
        }

62
        cgtAssert(signal != 0, "Signal must not be 0.");
63
64
65
66
67
68
69
70
71
        if (signal == 0)
            return false;

        _signalQueue.push(signal);
        _evaluationCondition.notify_all();
        return true;
    }

    void signal_manager::run() {
72
        _this_thread_id = std::this_thread::get_id();
73
        std::unique_lock<std::mutex> lock(_ecMutex);
74
75
76

        while (! _stopExecution) {
            // try pop the next event from the event queue
77
            _signal_handle_base* signal = nullptr;
78
            if (_signalQueue.try_pop(signal)) {
79
                signal->processSignal();
80
81
82
83
                delete signal;
            }
            else {
                // there currently is no event in this queue -> go sleep
84
                _evaluationCondition.wait(lock);
85
86
87
88
            }
        }
    }

89
90
91
92
    bool signal_manager::isCurrentThreadSignalManagerThread() const {
        return std::this_thread::get_id() == _this_thread_id;
    }

93
94
95
96
97
98
99
100
    signal_manager::SignalHandlingMode signal_manager::getSignalHandlingMode() const {
        return _handlingMode;
    }

    void signal_manager::setSignalHandlingMode(SignalHandlingMode mode) {
        _handlingMode = mode;
    }

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
    void signal_manager::waitForSignalQueueFlushed() {
        // nothing to wait for if current thread is signal_manager's thread.
        if (isCurrentThreadSignalManagerThread())
            return;

        // nothing to wait for if the signal queue is already empty.
        if (_signalQueue.empty())
            return;

        class SIGSLOT_API flushed_signal : public _signal_handle_base {
        public:
            flushed_signal(bool* ptr)
                : _ptr(ptr)
            {}

            ~flushed_signal() {}

            virtual void processSignal() const {
                *_ptr = true;
            }

        private:
            bool* _ptr;
        };

        bool signalVariable = false;
        this->queueSignalImpl(new flushed_signal(&signalVariable));
        while (! signalVariable)
            std::this_thread::yield(); // so we do some busy waiting here - hopefully not too long...
    }
131
132
133

    const std::string signal_manager::loggerCat_;

134
135
136
137
138
139
140
141
142
143
144
145
146

    // Implementation inspired by http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-new-and-delete-operators/7194149#7194149
    void* _signal_handle_base::operator new(std::size_t size) throw(std::bad_alloc) {
        if (size == 0)
            size = 1;

        while (true) {
            void* toReturn = signal_manager::getRef()._signalPool.malloc(size);

            if (toReturn != nullptr)
                return toReturn;

            //allocation was unsuccessful; find out what the current new-handling function is (see below)
147
            std::new_handler globalHandler = std::set_new_handler(0);
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
            std::set_new_handler(globalHandler);

            if (globalHandler)             //If new_hander is registered call it
                (*globalHandler)();
            else 
                throw std::bad_alloc();   //No handler is registered throw an exception
        }
    }

    void _signal_handle_base::operator delete(void* rawMemory, std::size_t size) throw() {
        if (rawMemory == nullptr)
            return;

        signal_manager::getRef()._signalPool.free(rawMemory);
        return;
    }

165
}