merged RC_1_1 into master

This commit is contained in:
Arvid Norberg 2018-05-02 00:32:09 +02:00
commit 4b368e1cfc
3 changed files with 49 additions and 36 deletions

View File

@ -74,7 +74,7 @@ namespace libtorrent {
template <class T, typename... Args> template <class T, typename... Args>
void emplace_alert(Args&&... args) try void emplace_alert(Args&&... args) try
{ {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::recursive_mutex> lock(m_mutex);
// don't add more than this number of alerts, unless it's a // don't add more than this number of alerts, unless it's a
// high priority alert, in which case we try harder to deliver it // high priority alert, in which case we try harder to deliver it
@ -90,12 +90,12 @@ namespace libtorrent {
T& alert = m_alerts[m_generation].emplace_back<T>( T& alert = m_alerts[m_generation].emplace_back<T>(
m_allocations[m_generation], std::forward<Args>(args)...); m_allocations[m_generation], std::forward<Args>(args)...);
maybe_notify(&alert, lock); maybe_notify(&alert);
} }
catch (std::bad_alloc const&) catch (std::bad_alloc const&)
{ {
// record that we dropped an alert of this type // record that we dropped an alert of this type
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::recursive_mutex> lock(m_mutex);
m_dropped.set(T::alert_type); m_dropped.set(T::alert_type);
} }
@ -105,12 +105,7 @@ namespace libtorrent {
template <class T> template <class T>
bool should_post() const bool should_post() const
{ {
if (!(m_alert_mask.load(std::memory_order_relaxed) & T::static_category)) return bool(m_alert_mask.load(std::memory_order_relaxed) & T::static_category);
{
return false;
}
return should_post_impl(T::priority);
} }
alert* wait_for_alert(time_duration max_wait); alert* wait_for_alert(time_duration max_wait);
@ -136,11 +131,15 @@ namespace libtorrent {
private: private:
bool should_post_impl(int priority) const; void maybe_notify(alert* a);
void maybe_notify(alert* a, std::unique_lock<std::mutex>& lock);
mutable std::mutex m_mutex; // this mutex protects everything. Since it's held while executing user
std::condition_variable m_condition; // callbacks (the notify function and extension on_alert()) it must be
// recursive to post new alerts. This is implemented by storing the
// current thread-id in m_mutex_holder, if it matches ours, we don't need
// to lock
mutable std::recursive_mutex m_mutex;
std::condition_variable_any m_condition;
std::atomic<alert_category_t> m_alert_mask; std::atomic<alert_category_t> m_alert_mask;
int m_queue_size_limit; int m_queue_size_limit;

View File

@ -47,16 +47,9 @@ namespace libtorrent {
alert_manager::~alert_manager() = default; alert_manager::~alert_manager() = default;
bool alert_manager::should_post_impl(int const priority) const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_alerts[m_generation].size()
< m_queue_size_limit * (1 + priority);
}
alert* alert_manager::wait_for_alert(time_duration max_wait) alert* alert_manager::wait_for_alert(time_duration max_wait)
{ {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::recursive_mutex> lock(m_mutex);
if (!m_alerts[m_generation].empty()) if (!m_alerts[m_generation].empty())
return m_alerts[m_generation].front(); return m_alerts[m_generation].front();
@ -69,12 +62,10 @@ namespace libtorrent {
return nullptr; return nullptr;
} }
void alert_manager::maybe_notify(alert* a, std::unique_lock<std::mutex>& lock) void alert_manager::maybe_notify(alert* a)
{ {
if (m_alerts[m_generation].size() == 1) if (m_alerts[m_generation].size() == 1)
{ {
lock.unlock();
// we just posted to an empty queue. If anyone is waiting for // we just posted to an empty queue. If anyone is waiting for
// alerts, we need to notify them. Also (potentially) call the // alerts, we need to notify them. Also (potentially) call the
// user supplied m_notify callback to let the client wake up its // user supplied m_notify callback to let the client wake up its
@ -85,10 +76,6 @@ namespace libtorrent {
// > 0 notify them // > 0 notify them
m_condition.notify_all(); m_condition.notify_all();
} }
else
{
lock.unlock();
}
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (auto& e : m_ses_extensions) for (auto& e : m_ses_extensions)
@ -100,12 +87,10 @@ namespace libtorrent {
void alert_manager::set_notify_function(std::function<void()> const& fun) void alert_manager::set_notify_function(std::function<void()> const& fun)
{ {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::recursive_mutex> lock(m_mutex);
m_notify = fun; m_notify = fun;
if (!m_alerts[m_generation].empty()) if (!m_alerts[m_generation].empty())
{ {
// never call a callback with the lock held!
lock.unlock();
if (m_notify) m_notify(); if (m_notify) m_notify();
} }
} }
@ -119,9 +104,8 @@ namespace libtorrent {
void alert_manager::get_all(std::vector<alert*>& alerts) void alert_manager::get_all(std::vector<alert*>& alerts)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::recursive_mutex> lock(m_mutex);
alerts.clear();
if (m_alerts[m_generation].empty()) return; if (m_alerts[m_generation].empty()) return;
m_alerts[m_generation].get_pointers(alerts); m_alerts[m_generation].get_pointers(alerts);
@ -135,13 +119,13 @@ namespace libtorrent {
bool alert_manager::pending() const bool alert_manager::pending() const
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::recursive_mutex> lock(m_mutex);
return !m_alerts[m_generation].empty(); return !m_alerts[m_generation].empty();
} }
int alert_manager::set_alert_queue_size_limit(int queue_size_limit_) int alert_manager::set_alert_queue_size_limit(int queue_size_limit_)
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::recursive_mutex> lock(m_mutex);
std::swap(m_queue_size_limit, queue_size_limit_); std::swap(m_queue_size_limit, queue_size_limit_);
return queue_size_limit_; return queue_size_limit_;
@ -149,7 +133,7 @@ namespace libtorrent {
dropped_alerts_t alert_manager::dropped_alerts() dropped_alerts_t alert_manager::dropped_alerts()
{ {
std::unique_lock<std::mutex> lock(m_mutex); std::unique_lock<std::recursive_mutex> lock(m_mutex);
dropped_alerts_t const ret = m_dropped; dropped_alerts_t const ret = m_dropped;
m_dropped.reset(); m_dropped.reset();
return ret; return ret;

View File

@ -277,3 +277,33 @@ TORRENT_TEST(dropped_alerts)
// it should have been cleared now though // it should have been cleared now though
TEST_CHECK(mgr.dropped_alerts().none()); TEST_CHECK(mgr.dropped_alerts().none());
} }
#ifndef TORRENT_DISABLE_EXTENSIONS
struct post_plugin : lt::plugin
{
explicit post_plugin(alert_manager& m) : mgr(m) {}
void on_alert(alert const*)
{
if (++depth > 10) return;
mgr.emplace_alert<piece_finished_alert>(torrent_handle(), piece_index_t{0});
}
alert_manager& mgr;
int depth = 0;
};
// make sure the alert manager supports alerts being posted while executing a
// plugin handler
TORRENT_TEST(recursive_alerts)
{
alert_manager mgr(100, alert::all_categories);
auto pl = std::make_shared<post_plugin>(mgr);
mgr.add_extension(pl);
mgr.emplace_alert<piece_finished_alert>(torrent_handle(), piece_index_t{0});
TEST_EQUAL(pl->depth, 11);
}
#endif // TORRENT_DISABLE_EXTENSIONS