// ================================================================================================
//
// sigslot.h/sigslot.cpp - Signal/Slot classes:
//
// Original siglsot implementation written by Sarah Thompson (sarah@telergy.com) 2002 and
// published under public domain.
//
// 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
// 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.
//
// ================================================================================================
#include
#include
#include "sigslot.h"
namespace sigslot {
signal_manager::signal_manager()
: _handlingMode(DEFAULT)
{
}
signal_manager::~signal_manager() {
_signalPool.recycle();
}
void signal_manager::triggerSignalImpl(_signal_handle_base* signal) {
if (_handlingMode == FORCE_QUEUE) {
queueSignalImpl(signal);
return;
}
signal->processSignal();
delete signal;
}
bool signal_manager::queueSignalImpl(_signal_handle_base* signal) {
if (_handlingMode == FORCE_DIRECT) {
triggerSignalImpl(signal);
return true;
}
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() {
_this_thread_id = std::this_thread::get_id();
std::unique_lock lock(_ecMutex);
while (! _stopExecution) {
// try pop the next event from the event queue
_signal_handle_base* signal;
if (_signalQueue.try_pop(signal)) {
signal->processSignal();
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();
}
bool signal_manager::isCurrentThreadSignalManagerThread() const {
return std::this_thread::get_id() == _this_thread_id;
}
signal_manager::SignalHandlingMode signal_manager::getSignalHandlingMode() const {
return _handlingMode;
}
void signal_manager::setSignalHandlingMode(SignalHandlingMode mode) {
_handlingMode = mode;
}
const std::string signal_manager::loggerCat_;
// 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)
std::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;
}
}