2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

sigslot.cpp 4.5 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
32
33
#include "sigslot.h"

namespace sigslot {

34
35
36
    signal_manager::signal_manager() 
        : _handlingMode(DEFAULT)
    {
37
38
39
40

    }

    signal_manager::~signal_manager() {
41
        _signalPool.recycle();
42
43
    }

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

50
        signal->processSignal();
51
52
53
        delete signal;
    }

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

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

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

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

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

    void signal_manager::stop() {
        _evaluationCondition.notify_all(); 
        tgt::Runnable::stop();
    }

92
93
94
95
    bool signal_manager::isCurrentThreadSignalManagerThread() const {
        return std::this_thread::get_id() == _this_thread_id;
    }

96
97
98
99
100
101
102
103
    signal_manager::SignalHandlingMode signal_manager::getSignalHandlingMode() const {
        return _handlingMode;
    }

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

104
105
106

    const std::string signal_manager::loggerCat_;

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

    // 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)
            new_handler globalHandler = std::set_new_handler(0);
            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;
    }

138
}