#ifndef CANCELLATION_H
#define CANCELLATION_H
#include <set>
#include <boost/thread/lock_guard.hpp>
#include <boost/thread/recursive_mutex.hpp>
namespace lsl {
class shutdown_error: public std::runtime_error {
public:
explicit shutdown_error(const std::string &msg): std::runtime_error(msg) {}
};
class cancellable_registry {
public:
cancellable_registry(): shutdown_issued_(false) {}
virtual ~cancellable_registry();
void cancel_all_registered();
void cancel_and_shutdown();
private:
friend class cancellable_obj;
void register_cancellable(class cancellable_obj *o) {
lslboost::lock_guard<lslboost::recursive_mutex> lock(state_mut_);
if (shutdown_issued_)
throw shutdown_error("The registry has begun to shut down; no new registrations possible.");
cancellables_.insert(o);
}
void unregister_cancellable(class cancellable_obj *o) {
lslboost::lock_guard<lslboost::recursive_mutex> lock(state_mut_);
cancellables_.erase(o);
}
bool shutdown_issued_; std::set<cancellable_obj*> cancellables_; lslboost::recursive_mutex state_mut_; };
class cancellable_obj {
public:
virtual void cancel() { }
virtual ~cancellable_obj();
void register_at(cancellable_registry *reg) {
reg->register_cancellable(this);
registered_at_.insert(reg);
}
void unregister_from_all();
private:
std::set<cancellable_registry*> registered_at_;
};
inline void cancellable_registry::cancel_all_registered() {
lslboost::lock_guard<lslboost::recursive_mutex> lock(state_mut_);
std::set<cancellable_obj*> copy(cancellables_);
for (std::set<cancellable_obj*>::iterator i=copy.begin(); i != copy.end(); i++)
if (cancellables_.find(*i) != cancellables_.end())
(*i)->cancel();
}
inline void cancellable_registry::cancel_and_shutdown() {
lslboost::lock_guard<lslboost::recursive_mutex> lock(state_mut_);
shutdown_issued_ = true;
cancel_all_registered();
}
}
#endif