mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-13 20:56:17 +00:00
Fixed dereferencing of potentially nullptr in SessionManager.
This commit is contained in:
@@ -90,6 +90,7 @@ Control::cleanup() {
|
|||||||
scgi_thread::thread()->stop_thread_wait();
|
scgi_thread::thread()->stop_thread_wait();
|
||||||
|
|
||||||
// Wait for all session files to be written.
|
// Wait for all session files to be written.
|
||||||
|
session_thread::manager()->flush_all_pending_builds();
|
||||||
session_thread::thread()->stop_thread_wait();
|
session_thread::thread()->stop_thread_wait();
|
||||||
|
|
||||||
m_ui->cleanup();
|
m_ui->cleanup();
|
||||||
|
|||||||
@@ -156,9 +156,9 @@ save_stream(const std::string& path, bool use_fsyncdisk, const std::stringstream
|
|||||||
|
|
||||||
void
|
void
|
||||||
DownloadStorer::save_and_move_streams(const std::string& path, bool use_fsyncdisk,
|
DownloadStorer::save_and_move_streams(const std::string& path, bool use_fsyncdisk,
|
||||||
const std::stringstream& torrent_stream,
|
const std::stringstream* torrent_stream,
|
||||||
const std::stringstream& rtorrent_stream,
|
const std::stringstream* rtorrent_stream,
|
||||||
const std::stringstream& libtorrent_stream) {
|
const std::stringstream* libtorrent_stream) {
|
||||||
// LT_LOG("saving download : download:%p path:%s", download, path.c_str());
|
// LT_LOG("saving download : download:%p path:%s", download, path.c_str());
|
||||||
|
|
||||||
auto torrent_path = path;
|
auto torrent_path = path;
|
||||||
@@ -166,14 +166,14 @@ DownloadStorer::save_and_move_streams(const std::string& path, bool use_fsyncdis
|
|||||||
auto rtorrent_path = path + ".rtorrent";
|
auto rtorrent_path = path + ".rtorrent";
|
||||||
|
|
||||||
if (torrent_stream) {
|
if (torrent_stream) {
|
||||||
if (!save_stream(torrent_path + ".new", use_fsyncdisk, torrent_stream))
|
if (!save_stream(torrent_path + ".new", use_fsyncdisk, *torrent_stream))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!save_stream(libtorrent_path + ".new", use_fsyncdisk, libtorrent_stream))
|
if (!save_stream(libtorrent_path + ".new", use_fsyncdisk, *libtorrent_stream))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!save_stream(rtorrent_path + ".new", use_fsyncdisk, rtorrent_stream))
|
if (!save_stream(rtorrent_path + ".new", use_fsyncdisk, *rtorrent_stream))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (torrent_stream) {
|
if (torrent_stream) {
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ public:
|
|||||||
auto libtorrent_stream() { return std::move(m_libtorrent_stream); }
|
auto libtorrent_stream() { return std::move(m_libtorrent_stream); }
|
||||||
|
|
||||||
static void save_and_move_streams(const std::string& path, bool use_fsyncdisk,
|
static void save_and_move_streams(const std::string& path, bool use_fsyncdisk,
|
||||||
const std::stringstream& torrent_stream,
|
const std::stringstream* torrent_stream,
|
||||||
const std::stringstream& rtorrent_stream,
|
const std::stringstream* rtorrent_stream,
|
||||||
const std::stringstream& libtorrent_stream);
|
const std::stringstream* libtorrent_stream);
|
||||||
|
|
||||||
static utils::Directory get_formated_entries(const std::string& session_path);
|
static utils::Directory get_formated_entries(const std::string& session_path);
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ SessionManager::save_resume_download(core::Download* download) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_pending_builds.empty())
|
if (m_pending_builds.empty())
|
||||||
torrent::main_thread::callback(this, [this]() { process_pending_resume_builds(); });
|
torrent::main_thread::callback(this, [this]() { process_pending_resume_builds(false); });
|
||||||
|
|
||||||
m_pending_builds.push_back(download);
|
m_pending_builds.push_back(download);
|
||||||
}
|
}
|
||||||
@@ -182,6 +182,13 @@ SessionManager::cleanup() {
|
|||||||
if (!m_active)
|
if (!m_active)
|
||||||
throw torrent::internal_error("SessionManager::cleanup() called while not active.");
|
throw torrent::internal_error("SessionManager::cleanup() called while not active.");
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> pending_lock(m_pending_builds_mutex);
|
||||||
|
|
||||||
|
if (!m_pending_builds.empty())
|
||||||
|
throw torrent::internal_error("SessionManager::cleanup() called with pending builds.");
|
||||||
|
}
|
||||||
|
|
||||||
m_active = false;
|
m_active = false;
|
||||||
|
|
||||||
if (m_path.empty()) {
|
if (m_path.empty()) {
|
||||||
@@ -207,48 +214,60 @@ SessionManager::cleanup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SessionManager::process_pending_resume_builds() {
|
SessionManager::process_pending_resume_builds(bool is_flushing) {
|
||||||
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
|
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
|
std::vector<SaveRequest> requests;
|
||||||
|
|
||||||
if (!m_active)
|
{
|
||||||
throw torrent::internal_error("SessionManager::process_pending_builds() called while not active.");
|
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
|
||||||
|
|
||||||
while (!m_pending_builds.empty() && m_pending_builds.size() < max_concurrent_requests) {
|
if (m_pending_builds.empty())
|
||||||
auto* download = m_pending_builds.front();
|
return;
|
||||||
m_pending_builds.pop_front();
|
|
||||||
|
|
||||||
LT_LOG("processing pending resume save : download:%p", download);
|
while (!m_pending_builds.empty()) {
|
||||||
|
if (!is_flushing && m_pending_builds.size() >= max_concurrent_requests)
|
||||||
|
break;
|
||||||
|
|
||||||
DownloadStorer storer(download);
|
auto* download = m_pending_builds.front();
|
||||||
|
m_pending_builds.pop_front();
|
||||||
|
|
||||||
storer.build_resume_streams();
|
LT_LOG("processing pending resume save : download:%p", download);
|
||||||
|
|
||||||
auto save_request = SaveRequest{
|
DownloadStorer storer(download);
|
||||||
download,
|
|
||||||
storer.build_path(m_path),
|
|
||||||
nullptr,
|
|
||||||
storer.rtorrent_stream(),
|
|
||||||
storer.libtorrent_stream()
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
storer.build_resume_streams();
|
||||||
std::unique_lock<std::mutex> save_lock(m_mutex);
|
|
||||||
|
|
||||||
if (!m_active)
|
auto save_request = SaveRequest{
|
||||||
throw torrent::internal_error("SessionManager::process_pending_builds() called while not active.");
|
download,
|
||||||
|
storer.build_path(m_path),
|
||||||
|
nullptr,
|
||||||
|
storer.rtorrent_stream(),
|
||||||
|
storer.libtorrent_stream()
|
||||||
|
};
|
||||||
|
|
||||||
|
requests.push_back(std::move(save_request));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> save_lock(m_mutex);
|
||||||
|
|
||||||
|
if (!m_active)
|
||||||
|
throw torrent::internal_error("SessionManager::process_pending_builds() called while not active.");
|
||||||
|
|
||||||
|
for (auto& save_request : requests) {
|
||||||
if (remove_or_replace_unsafe(save_request)) {
|
if (remove_or_replace_unsafe(save_request)) {
|
||||||
LT_LOG("updated pending resume save request : download:%p", download);
|
LT_LOG("updated pending resume save request : download:%p", save_request.download);
|
||||||
} else {
|
} else {
|
||||||
LT_LOG("queued new resume save request : download:%p", download);
|
LT_LOG("queued new resume save request : download:%p", save_request.download);
|
||||||
m_save_requests.push_back(std::move(save_request));
|
m_save_requests.push_back(std::move(save_request));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
session_thread::callback(this, [this]() { process_save_request_with_pending_callback(); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_flushing)
|
||||||
|
session_thread::callback(this, [this]() { process_save_request_with_pending_callback(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -279,7 +298,7 @@ SessionManager::process_save_request_with_pending_callback() {
|
|||||||
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
|
std::unique_lock<std::mutex> lock(m_pending_builds_mutex);
|
||||||
|
|
||||||
if (!m_pending_builds.empty())
|
if (!m_pending_builds.empty())
|
||||||
torrent::main_thread::callback(this, [this]() { process_pending_resume_builds(); });
|
torrent::main_thread::callback(this, [this]() { process_pending_resume_builds(false); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -295,9 +314,9 @@ SessionManager::process_next_save_request_unsafe() {
|
|||||||
// TODO: Consider adding a failed_saves with error info.
|
// TODO: Consider adding a failed_saves with error info.
|
||||||
|
|
||||||
DownloadStorer::save_and_move_streams(itr->second.path, m_use_fsyncdisk,
|
DownloadStorer::save_and_move_streams(itr->second.path, m_use_fsyncdisk,
|
||||||
*itr->second.torrent_stream,
|
itr->second.torrent_stream.get(),
|
||||||
*itr->second.rtorrent_stream,
|
itr->second.rtorrent_stream.get(),
|
||||||
*itr->second.libtorrent_stream);
|
itr->second.libtorrent_stream.get());
|
||||||
|
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_mutex);
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
@@ -330,7 +349,7 @@ SessionManager::process_finished_saves() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
SessionManager::wait_for_one_save_unsafe(std::unique_lock<std::mutex>& lock) {
|
SessionManager::wait_for_one_save_unsafe(std::unique_lock<std::mutex>& lock) {
|
||||||
assert(m_thread == torrent::this_thread::thread());
|
// Can be called in any thread.
|
||||||
|
|
||||||
if (m_processing_saves.empty())
|
if (m_processing_saves.empty())
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <torrent/common.h>
|
#include <torrent/common.h>
|
||||||
|
|
||||||
|
class Control;
|
||||||
|
|
||||||
namespace core {
|
namespace core {
|
||||||
class Download;
|
class Download;
|
||||||
}
|
}
|
||||||
@@ -63,7 +65,7 @@ public:
|
|||||||
void remove_download(core::Download* download);
|
void remove_download(core::Download* download);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Control;
|
friend class ::Control;
|
||||||
friend class ThreadSession;
|
friend class ThreadSession;
|
||||||
|
|
||||||
void save_download(core::Download* download, bool skip_static);
|
void save_download(core::Download* download, bool skip_static);
|
||||||
@@ -71,8 +73,10 @@ protected:
|
|||||||
void start();
|
void start();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
void flush_all_pending_builds();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void process_pending_resume_builds();
|
void process_pending_resume_builds(bool is_flushing);
|
||||||
void process_save_request();
|
void process_save_request();
|
||||||
void process_save_request_with_pending_callback();
|
void process_save_request_with_pending_callback();
|
||||||
void process_next_save_request_unsafe();
|
void process_next_save_request_unsafe();
|
||||||
@@ -110,10 +114,11 @@ private:
|
|||||||
std::deque<core::Download*> m_pending_builds;
|
std::deque<core::Download*> m_pending_builds;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool SessionManager::is_used() const { return !m_path.empty(); }
|
inline bool SessionManager::is_used() const { return !m_path.empty(); }
|
||||||
inline std::string SessionManager::path() const { return m_path; }
|
inline std::string SessionManager::path() const { return m_path; }
|
||||||
inline bool SessionManager::use_fsyncdisk() const { return true; }
|
inline bool SessionManager::use_fsyncdisk() const { return true; }
|
||||||
inline bool SessionManager::use_lock() const { return m_use_lock; }
|
inline bool SessionManager::use_lock() const { return m_use_lock; }
|
||||||
|
inline void SessionManager::flush_all_pending_builds() { process_pending_resume_builds(true); }
|
||||||
|
|
||||||
} // namespace session
|
} // namespace session
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user