diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 198915588..68bb8a61a 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -83,6 +83,7 @@ namespace libtorrent , check_files , save_resume_data , rename_file + , abort_thread }; action_t action; @@ -206,6 +207,12 @@ namespace libtorrent int num_blocks; // the pointers to the block data boost::shared_array blocks; +#ifndef NDEBUG + ~cached_piece_entry() + { + TORRENT_ASSERT(storage == 0); + } +#endif }; typedef boost::recursive_mutex mutex_t; diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 1c27388f7..a1fbdc2ba 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -252,6 +252,7 @@ namespace libtorrent no_error = 0, need_full_check = -1, fatal_disk_error = -2, + disk_check_aborted = -3 }; private: diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 57aa52877..bd0cd49fb 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -79,7 +79,9 @@ namespace libtorrent void disk_io_thread::join() { mutex_t::scoped_lock l(m_mutex); - m_abort = true; + disk_io_job j; + j.action = disk_io_job::abort_thread; + m_jobs.insert(m_jobs.begin(), j); m_signal.notify_all(); l.unlock(); @@ -146,6 +148,13 @@ namespace libtorrent m_jobs.erase(i++); continue; } + if (i->action == disk_io_job::check_files) + { + if (i->callback) m_ios.post(bind(i->callback + , piece_manager::disk_check_aborted, *i)); + m_jobs.erase(i++); + continue; + } ++i; } m_signal.notify_all(); @@ -223,6 +232,9 @@ namespace libtorrent --m_cache_stats.cache_size; --m_cache_stats.read_cache_size; } + l.unlock(); + p.storage = 0; + l.lock(); } bool disk_io_thread::clear_oldest_read_piece( @@ -331,6 +343,9 @@ namespace libtorrent for (int i = 0; i < blocks_in_piece; ++i) TORRENT_ASSERT(p.blocks[i] == 0); #endif + l.unlock(); + p.storage = 0; + l.lock(); } void disk_io_thread::cache_block(disk_io_job& j, mutex_t::scoped_lock& l) @@ -353,6 +368,9 @@ namespace libtorrent p.blocks[block] = j.buffer; ++m_cache_stats.cache_size; m_pieces.push_back(p); +#ifndef NDEBUG + p.storage = 0; +#endif } // fills a piece with data from disk, returns the total number of bytes @@ -466,6 +484,9 @@ namespace libtorrent else m_read_pieces.push_back(p); +#ifndef NDEBUG + p.storage = 0; +#endif return ret; } @@ -479,6 +500,7 @@ namespace libtorrent cached_piece_entry const& p = *i; TORRENT_ASSERT(p.blocks); + if (!p.storage) continue; int piece_size = p.storage->info()->piece_size(p.piece); int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; int blocks = 0; @@ -727,7 +749,21 @@ namespace libtorrent while (m_jobs.empty() && !m_abort) m_signal.wait(l); - if (m_abort && m_jobs.empty()) return; + if (m_abort && m_jobs.empty()) + { + // flush all disk caches + for (cache_t::iterator i = m_pieces.begin() + , end(m_pieces.end()); i != end; ++i) + flush(i, l); + for (cache_t::iterator i = m_read_pieces.begin() + , end(m_read_pieces.end()); i != end; ++i) + free_piece(*i, l); + l.unlock(); + m_pieces.clear(); + m_read_pieces.clear(); + l.lock(); + return; + } // if there's a buffer in this job, it will be freed // when this holder is destructed, unless it has been @@ -741,6 +777,32 @@ namespace libtorrent disk_io_job j = m_jobs.front(); m_jobs.pop_front(); + + if (j.action == disk_io_job::abort_thread) + { + m_abort = true; + + for (std::list::iterator i = m_jobs.begin(); + i != m_jobs.end();) + { + if (i->action == disk_io_job::read) + { + if (i->callback) m_ios.post(bind(i->callback, -1, *i)); + m_jobs.erase(i++); + continue; + } + if (i->action == disk_io_job::check_files) + { + if (i->callback) m_ios.post(bind(i->callback + , piece_manager::disk_check_aborted, *i)); + m_jobs.erase(i++); + continue; + } + ++i; + } + continue; + } + m_queue_buffer_size -= j.buffer_size; flush_expired_pieces(l); diff --git a/src/torrent.cpp b/src/torrent.cpp index 73c89404a..b3a81fdfc 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -675,6 +675,12 @@ namespace libtorrent { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + if (ret == piece_manager::disk_check_aborted) + { + m_error = "aborted"; + m_ses.done_checking(shared_from_this()); + return; + } if (ret == piece_manager::fatal_disk_error) { if (m_ses.m_alerts.should_post(alert::fatal))