hold an owning reference to storage objects in try_flush_write_blocks
It is possible for all other references to a storage object to be destroyed while try_flush_write_blocks is running. If the storage is destroyed then find_piece will crash when trying to re-aquire the shared_ptr. To prevent this, keep the storage alive by holding a shared_ptr to it in try_flush_write_blocks. Normally the fence job when stopping a torrent would prevent the storage object from being destroyed until all flush jobs are complete. try_flush_write_blocks can be run after every disk job though so it has the potential to "stradle the fence". If the associated torrent does get unloaded then it is expected that find_piece will return NULL thus causing the entry to be ignored.
This commit is contained in:
parent
52ccad23b9
commit
621da10e60
|
@ -899,22 +899,22 @@ namespace libtorrent
|
|||
DLOG("try_flush_write_blocks: %d\n", num);
|
||||
|
||||
list_iterator<cached_piece_entry> range = m_disk_cache.write_lru_pieces();
|
||||
std::vector<std::pair<piece_manager*, int> > pieces;
|
||||
std::vector<std::pair<boost::shared_ptr<piece_manager>, int> > pieces;
|
||||
pieces.reserve(m_disk_cache.num_write_lru_pieces());
|
||||
|
||||
for (list_iterator<cached_piece_entry> p = range; p.get() && num > 0; p.next())
|
||||
{
|
||||
cached_piece_entry* e = p.get();
|
||||
if (e->num_dirty == 0) continue;
|
||||
pieces.push_back(std::make_pair(e->storage.get(), int(e->piece)));
|
||||
pieces.push_back(std::make_pair(e->storage, int(e->piece)));
|
||||
}
|
||||
|
||||
for (std::vector<std::pair<piece_manager*, int> >::iterator i = pieces.begin()
|
||||
for (std::vector<std::pair<boost::shared_ptr<piece_manager>, int> >::iterator i = pieces.begin()
|
||||
, end(pieces.end()); i != end; ++i)
|
||||
{
|
||||
// TODO: instead of doing a lookup each time through the loop, save
|
||||
// cached_piece_entry pointers with piece_refcount incremented to pin them
|
||||
cached_piece_entry* pe = m_disk_cache.find_piece(i->first, i->second);
|
||||
cached_piece_entry* pe = m_disk_cache.find_piece(i->first.get(), i->second);
|
||||
if (pe == NULL) continue;
|
||||
|
||||
// another thread may flush this piece while we're looping and
|
||||
|
@ -941,10 +941,10 @@ namespace libtorrent
|
|||
|
||||
// if we still need to flush blocks, start over and flush
|
||||
// everything in LRU order (degrade to lru cache eviction)
|
||||
for (std::vector<std::pair<piece_manager*, int> >::iterator i = pieces.begin()
|
||||
for (std::vector<std::pair<boost::shared_ptr<piece_manager>, int> >::iterator i = pieces.begin()
|
||||
, end(pieces.end()); i != end; ++i)
|
||||
{
|
||||
cached_piece_entry* pe = m_disk_cache.find_piece(i->first, i->second);
|
||||
cached_piece_entry* pe = m_disk_cache.find_piece(i->first.get(), i->second);
|
||||
if (pe == NULL) continue;
|
||||
if (pe->num_dirty == 0) continue;
|
||||
|
||||
|
|
Loading…
Reference in New Issue