forked from premiere/premiere-libtorrent
close files in separate thread on systems where close() may block (Mac OS X for instance)
This commit is contained in:
parent
d4958c9286
commit
601443afd3
|
@ -1,3 +1,4 @@
|
|||
* close files in separate thread on systems where close() may block (Mac OS X for instance)
|
||||
* don't create all directories up front when adding torrents
|
||||
* support DHT scrape
|
||||
* added support for fadvise/F_RDADVISE for improved disk read performance
|
||||
|
|
|
@ -144,6 +144,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef TORRENT_USE_ICONV
|
||||
#define TORRENT_USE_ICONV 0
|
||||
#define TORRENT_USE_LOCALE 0
|
||||
#define TORRENT_CLOSE_MAY_BLOCK 1
|
||||
#endif
|
||||
#endif
|
||||
#define TORRENT_HAS_FALLOCATE 0
|
||||
|
@ -311,6 +312,14 @@ inline int snprintf(char* buf, int len, char const* fmt, ...)
|
|||
#define TORRENT_USE_LOCALE 0
|
||||
#endif
|
||||
|
||||
// set this to true if close() may block on your system
|
||||
// Mac OS X does this if the file being closed is not fully
|
||||
// allocated on disk yet for instance. When defined, the disk
|
||||
// I/O subsytem will use a separate thread for closing files
|
||||
#ifndef TORRENT_CLOSE_MAY_BLOCK
|
||||
#define TORRENT_CLOSE_MAY_BLOCK 0
|
||||
#endif
|
||||
|
||||
#ifndef TORRENT_BROKEN_UNIONS
|
||||
#define TORRENT_BROKEN_UNIONS 0
|
||||
#endif
|
||||
|
|
|
@ -53,7 +53,8 @@ namespace libtorrent
|
|||
{
|
||||
struct TORRENT_EXPORT file_pool : boost::noncopyable
|
||||
{
|
||||
file_pool(int size = 40): m_size(size), m_low_prio_io(true) {}
|
||||
file_pool(int size = 40);
|
||||
~file_pool();
|
||||
|
||||
boost::intrusive_ptr<file> open_file(void* st, std::string const& p
|
||||
, file_storage::iterator fe, file_storage const& fs, int m, error_code& ec);
|
||||
|
@ -64,7 +65,6 @@ namespace libtorrent
|
|||
void set_low_prio_io(bool b) { m_low_prio_io = b; }
|
||||
|
||||
private:
|
||||
file_pool(file_pool const&);
|
||||
|
||||
void remove_oldest();
|
||||
|
||||
|
@ -86,6 +86,16 @@ namespace libtorrent
|
|||
|
||||
file_set m_files;
|
||||
mutex m_mutex;
|
||||
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
void closer_thread_fun();
|
||||
mutex m_closer_mutex;
|
||||
std::vector<boost::intrusive_ptr<file> > m_queued_for_close;
|
||||
bool m_stop_thread;
|
||||
|
||||
// used to close files
|
||||
thread m_closer_thread;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,67 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
file_pool::file_pool(int size)
|
||||
: m_size(size)
|
||||
, m_low_prio_io(true)
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
, m_stop_thread(false)
|
||||
, m_closer_thread(boost::bind(&file_pool::closer_thread_fun, this))
|
||||
#endif
|
||||
{}
|
||||
|
||||
file_pool::~file_pool()
|
||||
{
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
mutex::scoped_lock l(m_closer_mutex);
|
||||
m_stop_thread = true;
|
||||
l.unlock();
|
||||
// wait for hte closer thread to finish closing all files
|
||||
m_closer_thread.join();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
void file_pool::closer_thread_fun()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
mutex::scoped_lock l(m_closer_mutex);
|
||||
if (m_stop_thread)
|
||||
{
|
||||
l.unlock();
|
||||
m_queued_for_close.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// find a file that doesn't have any other threads referencing
|
||||
// it. Since only those files can be closed in this thead
|
||||
std::vector<boost::intrusive_ptr<file> >::iterator i = std::find_if(
|
||||
m_queued_for_close.begin(), m_queued_for_close.end()
|
||||
, boost::bind(&file::refcount, boost::bind(&boost::intrusive_ptr<file>::get, _1)) == 1);
|
||||
|
||||
if (i == m_queued_for_close.end())
|
||||
{
|
||||
l.unlock();
|
||||
// none of the files are ready to be closet yet
|
||||
// because they're still in use by other threads
|
||||
// hold off for a while
|
||||
sleep(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ok, first pull the file out of the queue, release the mutex
|
||||
// (since closing the file may block) and then close it.
|
||||
boost::intrusive_ptr<file> f = *i;
|
||||
m_queued_for_close.erase(i);
|
||||
l.unlock();
|
||||
f->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
|
||||
, file_storage::iterator fe, file_storage const& fs, int m, error_code& ec)
|
||||
{
|
||||
|
@ -77,7 +138,15 @@ namespace libtorrent
|
|||
// close the file before we open it with
|
||||
// the new read/write privilages
|
||||
TORRENT_ASSERT(e.file_ptr->refcount() == 1);
|
||||
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
mutex::scoped_lock l(m_closer_mutex);
|
||||
m_queued_for_close.push_back(e.file_ptr);
|
||||
l.unlock();
|
||||
e.file_ptr = new file;
|
||||
#else
|
||||
e.file_ptr->close();
|
||||
#endif
|
||||
std::string full_path = combine_path(p, fs.file_path(*fe));
|
||||
if (!e.file_ptr->open(full_path, m, ec))
|
||||
{
|
||||
|
@ -133,6 +202,12 @@ namespace libtorrent
|
|||
, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
|
||||
< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
|
||||
if (i == m_files.end()) return;
|
||||
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
mutex::scoped_lock l(m_closer_mutex);
|
||||
m_queued_for_close.push_back(i->second.file_ptr);
|
||||
l.unlock();
|
||||
#endif
|
||||
m_files.erase(i);
|
||||
}
|
||||
|
||||
|
@ -140,7 +215,14 @@ namespace libtorrent
|
|||
{
|
||||
mutex::scoped_lock l(m_mutex);
|
||||
file_set::iterator i = m_files.find(std::make_pair(st, file_index));
|
||||
if (i != m_files.end()) m_files.erase(i);
|
||||
if (i == m_files.end()) return;
|
||||
|
||||
#if TORRENT_CLOSE_MAY_BLOCK
|
||||
mutex::scoped_lock l2(m_closer_mutex);
|
||||
m_queued_for_close.push_back(i->second.file_ptr);
|
||||
l2.unlock();
|
||||
#endif
|
||||
m_files.erase(i);
|
||||
}
|
||||
|
||||
// closes files belonging to the specified
|
||||
|
|
Loading…
Reference in New Issue