3 #include <tbb/spin_rw_mutex.h>
4 #include "lock_container.h"
6 namespace caspar { namespace IO {
8 struct lock_container::impl
10 std::wstring lifecycle_key_;
12 std::set<std::weak_ptr<client_connection<wchar_t>>, std::owner_less<std::weak_ptr<client_connection<wchar_t>>>> locks_;
13 std::wstring lock_phrase_;
14 mutable tbb::spin_rw_mutex mutex_;
17 impl(const std::wstring& lifecycle_key) : lifecycle_key_(lifecycle_key) {}
19 bool check_access(client_connection<wchar_t>::ptr conn)
21 tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);
22 std::weak_ptr<client_connection<wchar_t>> weak_ptr(conn);
23 return locks_.empty() ? true : locks_.find(weak_ptr) != locks_.end();
26 bool try_lock(const std::wstring& lock_phrase, client_connection<wchar_t>::ptr conn)
28 tbb::spin_rw_mutex::scoped_lock lock(mutex_, false);
29 if(lock_phrase_.empty() || lock_phrase == lock_phrase_)
31 std::weak_ptr<client_connection<wchar_t>> weak_ptr(conn);
32 if(locks_.find(weak_ptr) == locks_.end())
35 lock.upgrade_to_writer();
36 lock_phrase_ = lock_phrase;
37 locks_.insert(weak_ptr);
40 lock.release(); //risk of reentrancy-deadlock if we don't release prior to trying to attach lifecycle-bound object to connection
42 CASPAR_LOG(info) << lifecycle_key_ << " acquired";
45 std::shared_ptr<void> obj(nullptr, [=](void*) { do_release_lock(weak_ptr); });
46 conn->add_lifecycle_bound_object(lifecycle_key_, obj);
55 void clear_locks() //TODO: add a function-object parameter to be called for each clients that has it's lock released
57 std::vector<std::weak_ptr<client_connection<wchar_t>>> clients;
59 { //copy the connections locally and then clear the set
60 tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);
61 clients.resize(locks_.size());
62 std::copy(locks_.begin(), locks_.end(), clients.begin());
68 //now we can take our time to inform the clients that their locks have been released.
69 BOOST_FOREACH(std::weak_ptr<client_connection<wchar_t>> conn, clients)
71 auto ptr = conn.lock();
74 ptr->remove_lifecycle_bound_object(lifecycle_key_); //this calls do_relase_lock, which takes a write-lock
75 //TODO: invoke callback
80 void release_lock(client_connection<wchar_t>::ptr conn)
82 conn->remove_lifecycle_bound_object(lifecycle_key_); //this calls do_relase_lock, which takes a write-lock
86 void do_release_lock(std::weak_ptr<client_connection<wchar_t>> conn)
89 tbb::spin_rw_mutex::scoped_lock lock(mutex_, true);
98 CASPAR_LOG(info) << lifecycle_key_ << " released";
103 lock_container::lock_container(const std::wstring& lifecycle_key) : impl_(spl::make_unique<impl>(lifecycle_key)) {}
104 lock_container::~lock_container() {}
106 bool lock_container::check_access(client_connection<wchar_t>::ptr conn) { return impl_->check_access(conn); }
107 bool lock_container::try_lock(const std::wstring& lock_phrase, client_connection<wchar_t>::ptr conn) { return impl_->try_lock(lock_phrase, conn); }
108 void lock_container::release_lock(client_connection<wchar_t>::ptr conn) { impl_->release_lock(conn); }
109 void lock_container::clear_locks() { return impl_->clear_locks(); }