From 4e576f93fdd7f57160ae064a58dc1ab922263653 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 14 Jul 2010 04:16:38 +0000 Subject: [PATCH] removed the session mutex for improved performance --- ChangeLog | 1 + docs/manual.html | 49 +-- docs/manual.rst | 28 +- docs/python_binding.html | 2 + include/libtorrent/alert.hpp | 8 +- include/libtorrent/aux_/session_impl.hpp | 46 ++- include/libtorrent/disk_io_thread.hpp | 1 + include/libtorrent/peer_connection.hpp | 2 - include/libtorrent/session.hpp | 26 +- include/libtorrent/torrent.hpp | 8 +- src/alert.cpp | 22 +- src/disk_io_thread.cpp | 8 +- src/peer_connection.cpp | 23 +- src/session.cpp | 416 +++++++++++------------ src/session_impl.cpp | 149 ++++---- src/smart_ban.cpp | 4 +- src/torrent.cpp | 129 +++++-- src/torrent_handle.cpp | 386 +++++++++++++-------- src/tracker_manager.cpp | 4 +- test/test_storage.cpp | 3 + test/test_transfer.cpp | 4 +- 21 files changed, 753 insertions(+), 566 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5c33f87fc..6ff5134f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * removed the session mutex for improved performance * added upload and download activity timer stats for torrents * made the reuse-address flag configurable on the listen socket * moved UDP trackers over to use a single socket diff --git a/docs/manual.html b/docs/manual.html index 22d322a79..5abff8163 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -480,23 +480,26 @@ class session: public boost::noncopyable int num_uploads() const; int num_connections() const; - bool load_asnum_db(char const* file); - bool load_asnum_db(wchar_t const* file); - bool load_country_db(char const* file); - bool load_country_db(wchar_t const* file); + void load_asnum_db(char const* file); + void load_asnum_db(wchar_t const* file); + void load_country_db(char const* file); + void load_country_db(wchar_t const* file); int as_for_ip(address const& adr); void set_ip_filter(ip_filter const& f); - ip_filter const& get_ip_filter() const; + ip_filter get_ip_filter() const; session_status status() const; cache_status get_cache_status() const; bool is_listening() const; unsigned short listen_port() const; + + enum { listen_reuse_address = 1 }; bool listen_on( std::pair<int, int> const& port_range - , char const* interface = 0); + , char const* interface = 0 + , int flags = 0); std::auto_ptr<alert> pop_alert(); alert const* wait_for_alert(time_duration max_wait); @@ -706,12 +709,9 @@ There are 3 different modes:

All pieces will be written to the place where they belong and sparse files will be used. This is the recommended, and default mode.
storage_mode_allocate
-
Same as storage_mode_sparse except that files will be ftruncated on -startup (SetEndOfFile() on windows). For filesystem that supports sparse -files, this is in all practical aspects identical to sparse mode. For -filesystems that don't, it will allocate the data for the files. The mac -filesystem HFS+ doesn't support sparse files, it will allocate the files -with zeroes.
+
All pieces will be written to their final position, all files will be +allocated in full when the torrent is first started. This is done with +fallocate() and similar calls. This mode minimizes fragmentation.
storage_mode_compact
The storage will grow as more pieces are downloaded, and pieces are rearranged to finally be in their correct places once the entire torrent has been @@ -892,10 +892,10 @@ to 8 on windows.

load_asnum_db() load_country_db() int as_for_ip()

-bool load_asnum_db(char const* file);
-bool load_asnum_db(wchar_t const* file);
-bool load_country_db(char const* file);
-bool load_country_db(wchar_t const* file);
+void load_asnum_db(char const* file);
+void load_asnum_db(wchar_t const* file);
+void load_country_db(char const* file);
+void load_country_db(wchar_t const* file);
 int as_for_ip(address const& adr);
 
@@ -925,7 +925,7 @@ generated.

::
-
ip_filter const& get_ip_filter() const;
+
ip_filter get_ip_filter() const;

Returns the ip_filter currently in the session. See ip_filter.

@@ -1130,7 +1130,8 @@ bool is_listening() const; unsigned short listen_port() const; bool listen_on( std::pair<int, int> const& port_range - , char const* interface = 0); + , char const* interface = 0 + , int flags = 0);

is_listening() will tell you whether or not the session has successfully @@ -1156,6 +1157,10 @@ want to listen on. If you don't specify an interface, libtorrent may attempt to listen on multiple interfaces (typically 0.0.0.0 and ::). This means that if your IPv6 interface doesn't work, you may still see a listen_failed_alert, even though the IPv4 port succeeded.

+

The flags parameter can either be 0 or session::listen_reuse_address, which +will set the reuse address socket option on the listen socket(s). By default, the +listen socket does not use reuse address. If you're running a service that needs +to run on a specific port no matter if it's in use, set this flag.

If you're also starting the DHT, it is a good idea to do that after you've called listen_on(), since the default listen port for the DHT is the same as the tcp listen socket. If you start the DHT first, it will assume the tcp port is free and @@ -1298,10 +1303,10 @@ it only has any effect if the proxy supports UDP.

peer_proxy() web_seed_proxy() tracker_proxy() dht_proxy()

-proxy_settings const& peer_proxy() const;
-proxy_settings const& web_seed_proxy() const;
-proxy_settings const& tracker_proxy() const;
-proxy_settings const& dht_proxy() const;
+proxy_settings peer_proxy() const;
+proxy_settings web_seed_proxy() const;
+proxy_settings tracker_proxy() const;
+proxy_settings dht_proxy() const;
 

These functions returns references to their respective current settings.

diff --git a/docs/manual.rst b/docs/manual.rst index 75274d1a1..adf3365ee 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -193,14 +193,14 @@ The ``session`` class has the following synopsis:: int num_uploads() const; int num_connections() const; - bool load_asnum_db(char const* file); - bool load_asnum_db(wchar_t const* file); - bool load_country_db(char const* file); - bool load_country_db(wchar_t const* file); + void load_asnum_db(char const* file); + void load_asnum_db(wchar_t const* file); + void load_country_db(char const* file); + void load_country_db(wchar_t const* file); int as_for_ip(address const& adr); void set_ip_filter(ip_filter const& f); - ip_filter const& get_ip_filter() const; + ip_filter get_ip_filter() const; session_status status() const; cache_status get_cache_status() const; @@ -647,10 +647,10 @@ load_asnum_db() load_country_db() int as_for_ip() :: - bool load_asnum_db(char const* file); - bool load_asnum_db(wchar_t const* file); - bool load_country_db(char const* file); - bool load_country_db(wchar_t const* file); + void load_asnum_db(char const* file); + void load_asnum_db(wchar_t const* file); + void load_country_db(char const* file); + void load_country_db(wchar_t const* file); int as_for_ip(address const& adr); These functions are not available if ``TORRENT_DISABLE_GEO_IP`` is defined. They @@ -684,7 +684,7 @@ get_ip_filter() --------------- :: - ip_filter const& get_ip_filter() const; + ip_filter get_ip_filter() const; Returns the ip_filter currently in the session. See ip_filter_. @@ -1114,10 +1114,10 @@ peer_proxy() web_seed_proxy() tracker_proxy() dht_proxy() :: - proxy_settings const& peer_proxy() const; - proxy_settings const& web_seed_proxy() const; - proxy_settings const& tracker_proxy() const; - proxy_settings const& dht_proxy() const; + proxy_settings peer_proxy() const; + proxy_settings web_seed_proxy() const; + proxy_settings tracker_proxy() const; + proxy_settings dht_proxy() const; These functions returns references to their respective current settings. diff --git a/docs/python_binding.html b/docs/python_binding.html index 09b5a7d72..3d80b0e85 100644 --- a/docs/python_binding.html +++ b/docs/python_binding.html @@ -126,6 +126,8 @@ a list of entries.

  • torrent_handle::get_download_queue
  • torrent_handle::piece_availability
  • +

    create_torrent::add_node() takes two arguments, one string and one integer, +instead of a pair. The string is the address and the integer is the port.

    For an example python program, see client.py in the bindings/python directory.

    A very simple example usage of the module would be something like this:

    diff --git a/include/libtorrent/alert.hpp b/include/libtorrent/alert.hpp index 1c04820d3..fb62c3c76 100644 --- a/include/libtorrent/alert.hpp +++ b/include/libtorrent/alert.hpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_ALERT_HPP_INCLUDED #include -#include +#include #include #ifdef _MSC_VER @@ -145,15 +145,15 @@ namespace libtorrent { size_t alert_queue_size_limit() const { return m_queue_size_limit; } size_t set_alert_queue_size_limit(size_t queue_size_limit_); - void set_dispatch_function(boost::function const&); + void set_dispatch_function(boost::function)> const&); private: - std::queue m_alerts; + std::deque m_alerts; mutable mutex m_mutex; condition m_condition; int m_alert_mask; size_t m_queue_size_limit; - boost::function m_dispatch; + boost::function)> m_dispatch; io_service& m_ios; }; diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 2b61a151c..37434a459 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -177,9 +177,18 @@ namespace libtorrent void incoming_connection(boost::shared_ptr const& s); - // must be locked to access the data - // in this struct - mutable mutex m_mutex; +#ifdef TORRENT_DEBUG +#if defined BOOST_HAS_PTHREADS + pthread_t m_network_thread; +#endif + bool is_network_thread() const + { +#if defined BOOST_HAS_PTHREADS + return m_network_thread == pthread_self(); +#endif + return true; + } +#endif boost::weak_ptr find_torrent(const sha1_hash& info_hash); peer_id const& get_peer_id() const { return m_peer_id; } @@ -190,7 +199,7 @@ namespace libtorrent session_settings const& settings() const { return m_settings; } #ifndef TORRENT_DISABLE_DHT - void add_dht_node(std::pair const& node); + void add_dht_node_name(std::pair const& node); void add_dht_node(udp::endpoint n); void add_dht_router(std::pair const& node); void set_dht_settings(dht_settings const& s); @@ -200,7 +209,7 @@ namespace libtorrent void start_dht(entry const& startup_state); #ifndef TORRENT_NO_DEPRECATE - entry dht_state(mutex::scoped_lock& l) const; + entry dht_state() const; #endif void maybe_update_udp_mapping(int nat, int local_port, int external_port); @@ -252,7 +261,7 @@ namespace libtorrent void set_alert_mask(int m); size_t set_alert_queue_size_limit(size_t queue_size_limit_); std::auto_ptr pop_alert(); - void set_alert_dispatch(boost::function const&); + void set_alert_dispatch(boost::function)> const&); alert const* wait_for_alert(time_duration max_wait); @@ -292,8 +301,8 @@ namespace libtorrent void announce_lsd(sha1_hash const& ih); - void save_state(entry& e, boost::uint32_t flags, mutex::scoped_lock& l) const; - void load_state(lazy_entry const& e); + void save_state(entry* e, boost::uint32_t flags) const; + void load_state(lazy_entry const* e); void set_peer_proxy(proxy_settings const& s) { @@ -323,6 +332,7 @@ namespace libtorrent } proxy_settings const& dht_proxy() const { return m_dht_proxy; } + bool is_dht_running() const { return m_dht; } #endif #if TORRENT_USE_I2P @@ -343,22 +353,22 @@ namespace libtorrent std::string as_name_for_ip(address const& a); int as_for_ip(address const& a); std::pair* lookup_as(int as); - bool load_asnum_db(char const* file); + void load_asnum_db(std::string file); bool has_asnum_db() const { return m_asnum_db; } - bool load_country_db(char const* file); + void load_country_db(std::string file); bool has_country_db() const { return m_country_db; } char const* country_for_ip(address const& a); #if TORRENT_USE_WSTRING - bool load_asnum_db(wchar_t const* file); - bool load_country_db(wchar_t const* file); + void load_asnum_db(std::wstring file); + void load_country_db(std::wstring file); #endif // TORRENT_USE_WSTRING #endif // TORRENT_DISABLE_GEO_IP void start_lsd(); - void start_natpmp(natpmp* n); - void start_upnp(upnp* u); + natpmp* start_natpmp(); + upnp* start_upnp(); void stop_lsd(); void stop_natpmp(); @@ -387,11 +397,14 @@ namespace libtorrent void set_external_address(address const& ip); address const& external_address() const { return m_external_address; } + // used when posting synchronous function + // calls to session_impl and torrent objects + mutable libtorrent::mutex mut; + mutable libtorrent::condition cond; + // private: void update_disk_thread_settings(); - void on_dht_state_callback(condition& c - , entry& e, bool& done) const; void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih); void setup_socket_buffers(socket_type& s); @@ -794,6 +807,7 @@ namespace libtorrent std::string m_logpath; public: boost::shared_ptr m_logger; + private: #endif diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index a26fffbba..55fa22a23 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -289,6 +289,7 @@ namespace libtorrent , int block_size = 16 * 1024); ~disk_io_thread(); + void abort(); void join(); // aborts read operations diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index b4bb2e517..227a8e497 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -642,8 +642,6 @@ namespace libtorrent , std::size_t bytes_transferred); void on_receive_data(error_code const& error , std::size_t bytes_transferred); - void on_receive_data_nolock(error_code const& error - , std::size_t bytes_transferred); // this is the limit on the number of outstanding requests // we have to this peer. This is initialized to the settings diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 37f820fd3..c00ad46b4 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -275,7 +275,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_ENCRYPTION void set_pe_settings(pe_settings const& settings); - pe_settings const& get_pe_settings() const; + pe_settings get_pe_settings() const; #endif #ifndef TORRENT_DISABLE_EXTENSIONS @@ -284,11 +284,11 @@ namespace libtorrent #ifndef TORRENT_DISABLE_GEO_IP int as_for_ip(address const& addr); - bool load_asnum_db(char const* file); - bool load_country_db(char const* file); + void load_asnum_db(char const* file); + void load_country_db(char const* file); #if TORRENT_USE_WSTRING - bool load_country_db(wchar_t const* file); - bool load_asnum_db(wchar_t const* file); + void load_country_db(wchar_t const* file); + void load_asnum_db(wchar_t const* file); #endif #endif @@ -302,7 +302,7 @@ namespace libtorrent #endif void set_ip_filter(ip_filter const& f); - ip_filter const& get_ip_filter() const; + ip_filter get_ip_filter() const; void set_port_filter(port_filter const& f); void set_peer_id(peer_id const& pid); @@ -354,24 +354,24 @@ namespace libtorrent void remove_torrent(const torrent_handle& h, int options = none); void set_settings(session_settings const& s); - session_settings const& settings(); + session_settings settings(); void set_peer_proxy(proxy_settings const& s); void set_web_seed_proxy(proxy_settings const& s); void set_tracker_proxy(proxy_settings const& s); - proxy_settings const& peer_proxy() const; - proxy_settings const& web_seed_proxy() const; - proxy_settings const& tracker_proxy() const; + proxy_settings peer_proxy() const; + proxy_settings web_seed_proxy() const; + proxy_settings tracker_proxy() const; #ifndef TORRENT_DISABLE_DHT void set_dht_proxy(proxy_settings const& s); - proxy_settings const& dht_proxy() const; + proxy_settings dht_proxy() const; #endif #if TORRENT_USE_I2P void set_i2p_proxy(proxy_settings const& s); - proxy_settings const& i2p_proxy() const; + proxy_settings i2p_proxy() const; #endif int upload_rate_limit() const; @@ -400,7 +400,7 @@ namespace libtorrent size_t set_alert_queue_size_limit(size_t queue_size_limit_); alert const* wait_for_alert(time_duration max_wait); - void set_alert_dispatch(boost::function const& fun); + void set_alert_dispatch(boost::function)> const& fun); connection_queue& get_connection_queue(); diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index f4690851e..434fecf4d 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -172,8 +172,7 @@ namespace libtorrent void on_resume_data_checked(int ret, disk_io_job const& j); void on_force_recheck(int ret, disk_io_job const& j); void on_piece_checked(int ret, disk_io_job const& j); - void files_checked_lock(); - void files_checked(mutex::scoped_lock const&); + void files_checked(); void start_checking(); void start_announcing(); @@ -228,6 +227,8 @@ namespace libtorrent bool is_sequential_download() const { return m_sequential_download; } + void queue_up(); + void queue_down(); void set_queue_position(int p); int queue_position() const { return m_sequence_number; } @@ -307,7 +308,7 @@ namespace libtorrent void file_progress(std::vector& fp, int flags = 0) const; - void use_interface(const char* net_interface); + void use_interface(std::string net_interface); tcp::endpoint get_interface() const { return m_net_interface; } void connect_to_url_seed(std::list::iterator url); @@ -408,6 +409,7 @@ namespace libtorrent bool want_more_peers() const; bool try_connect_peer(); void give_connect_points(int points); + void add_peer(tcp::endpoint const& adr, int source); // the number of peers that belong to this torrent int num_peers() const { return (int)m_connections.size(); } diff --git a/src/alert.cpp b/src/alert.cpp index 6188b5cdb..429914eed 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -336,7 +336,7 @@ namespace libtorrent { while (!m_alerts.empty()) { delete m_alerts.front(); - m_alerts.pop(); + m_alerts.pop_front(); } } @@ -367,21 +367,20 @@ namespace libtorrent { return m_alerts.front(); } - void alert_manager::set_dispatch_function(boost::function const& fun) + void alert_manager::set_dispatch_function(boost::function)> const& fun) { mutex::scoped_lock lock(m_mutex); m_dispatch = fun; - std::queue alerts = m_alerts; - while (!m_alerts.empty()) m_alerts.pop(); + std::deque alerts; + m_alerts.swap(alerts); lock.unlock(); while (!alerts.empty()) { - m_dispatch(*alerts.front()); - delete alerts.front(); - alerts.pop(); + m_dispatch(std::auto_ptr(alerts.front())); + alerts.pop_front(); } } @@ -399,12 +398,12 @@ namespace libtorrent { if (m_dispatch) { TORRENT_ASSERT(m_alerts.empty()); - m_ios.post(boost::bind(&dispatch_alert, m_dispatch, alert_.clone().release())); + m_dispatch(std::auto_ptr(alert_.clone())); return; } if (m_alerts.size() >= m_queue_size_limit) return; - m_alerts.push(alert_.clone().release()); + m_alerts.push_back(alert_.clone().release()); m_condition.signal(lock); m_condition.clear(lock); } @@ -413,10 +412,11 @@ namespace libtorrent { { mutex::scoped_lock lock(m_mutex); - TORRENT_ASSERT(!m_alerts.empty()); + if (m_alerts.empty()) + return std::auto_ptr(0); alert* result = m_alerts.front(); - m_alerts.pop(); + m_alerts.pop_front(); return std::auto_ptr(result); } diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 751a1cae3..470c39058 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -368,7 +368,7 @@ namespace libtorrent TORRENT_ASSERT(m_abort == true); } - void disk_io_thread::join() + void disk_io_thread::abort() { mutex::scoped_lock l(m_queue_mutex); disk_io_job j; @@ -376,10 +376,12 @@ namespace libtorrent j.action = disk_io_job::abort_thread; m_jobs.insert(m_jobs.begin(), j); m_signal.signal(l); - l.unlock(); + } + void disk_io_thread::join() + { m_disk_io_thread.join(); - l.lock(); + mutex::scoped_lock l(m_queue_mutex); TORRENT_ASSERT(m_abort == true); m_jobs.clear(); } diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index bf8815106..982c549fa 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -2392,7 +2392,7 @@ namespace libtorrent void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j , peer_request p, boost::shared_ptr t) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -3168,7 +3168,7 @@ namespace libtorrent void peer_connection::on_timeout() { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(m_connecting); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING @@ -4061,7 +4061,7 @@ namespace libtorrent void peer_connection::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); m_reading_bytes -= r.length; @@ -4379,7 +4379,7 @@ namespace libtorrent else { m_channel_state[download_channel] = peer_info::bw_network; - on_receive_data_nolock(ec, bytes_transferred); + on_receive_data(ec, bytes_transferred); } } @@ -4636,14 +4636,7 @@ namespace libtorrent void peer_connection::on_receive_data(const error_code& error , std::size_t bytes_transferred) { - mutex::scoped_lock l(m_ses.m_mutex); - on_receive_data_nolock(error, bytes_transferred); - } - - void peer_connection::on_receive_data_nolock(const error_code& error - , std::size_t bytes_transferred) - { - + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; // keep ourselves alive in until this function exits in @@ -4777,7 +4770,7 @@ namespace libtorrent void peer_connection::on_connect(int ticket) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); #ifdef TORRENT_DEBUG // in case we disconnect here, we need to // keep the connection alive until the @@ -4869,7 +4862,7 @@ namespace libtorrent { ptime completed = time_now(); - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -4932,7 +4925,7 @@ namespace libtorrent void peer_connection::on_send_data(error_code const& error , std::size_t bytes_transferred) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; diff --git a/src/session.cpp b/src/session.cpp index 10f9fdaae..dbd9acadd 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -229,6 +229,87 @@ namespace libtorrent return set; } + // wrapper around a function that's executed in the network thread + // ans synchronized in the client thread + template + void fun_ret(R* ret, bool* done, condition* e, mutex* m, boost::function f) + { + *ret = f(); + mutex::scoped_lock l(*m); + *done = true; + e->signal(l); + } + + void fun_wrap(bool* done, condition* e, mutex* m, boost::function f) + { + f(); + mutex::scoped_lock l(*m); + *done = true; + e->signal(l); + } + +#define TORRENT_ASYNC_CALL(x) \ + m_impl->m_io_service.post(boost::bind(&session_impl:: x, m_impl.get())) + +#define TORRENT_ASYNC_CALL1(x, a1) \ + m_impl->m_io_service.post(boost::bind(&session_impl:: x, m_impl.get(), a1)) + +#define TORRENT_ASYNC_CALL2(x, a1, a2) \ + m_impl->m_io_service.post(boost::bind(&session_impl:: x, m_impl.get(), a1, a2)) + +#define TORRENT_SYNC_CALL(x) \ + bool done = false; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_wrap, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get())))); \ + do { m_impl->cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL1(x, a1) \ + bool done = false; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_wrap, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get(), a1)))); \ + do { m_impl->cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL2(x, a1, a2) \ + bool done = false; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_wrap, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get(), a1, a2)))); \ + do { m_impl->cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL_RET(type, x) \ + bool done = false; \ + type r; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_ret, &r, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get())))); \ + do { m_impl->cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL_RET1(type, x, a1) \ + bool done = false; \ + type r; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_ret, &r, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get(), a1)))); \ + do { m_impl->cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL_RET2(type, x, a1, a2) \ + bool done = false; \ + type r; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_ret, &r, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get(), a1, a2)))); \ + do { m_impl->cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL_RET3(type, x, a1, a2, a3) \ + bool done = false; \ + type r; \ + mutex::scoped_lock l(m_impl->mut); \ + m_impl->cond.clear(l); \ + m_impl->m_io_service.post(boost::bind(&fun_ret, &r, &done, &m_impl->cond, &m_impl->mut, boost::function(boost::bind(&session_impl:: x, m_impl.get(), a1, a2, a3)))); \ + do { m_impl->cond.wait(l); } while(!done) + session::session( fingerprint const& id , std::pair listen_port_range @@ -310,7 +391,6 @@ namespace libtorrent session::~session() { - mutex::scoped_lock l(m_impl->m_mutex); #ifdef TORRENT_MEMDEBUG stop_malloc_debug(); #endif @@ -319,59 +399,55 @@ namespace libtorrent // abort the session and let the destructor // of the proxy to syncronize if (!m_impl.unique()) - m_impl->abort(); + { + TORRENT_ASYNC_CALL(abort); + } } void session::save_state(entry& e, boost::uint32_t flags) const { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->save_state(e, flags, l); + TORRENT_SYNC_CALL2(save_state, &e, flags); } void session::load_state(lazy_entry const& e) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->load_state(e); + // this needs to be synchronized since the lifespan + // of e is tied to the caller + TORRENT_SYNC_CALL1(load_state, &e); } #ifndef TORRENT_DISABLE_EXTENSIONS void session::add_extension(boost::function(torrent*, void*)> ext) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->add_extension(ext); + TORRENT_ASYNC_CALL1(add_extension, ext); } #endif #ifndef TORRENT_DISABLE_GEO_IP - bool session::load_asnum_db(char const* file) + void session::load_asnum_db(char const* file) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->load_asnum_db(file); + TORRENT_ASYNC_CALL1(load_asnum_db, std::string(file)); } - bool session::load_country_db(char const* file) + void session::load_country_db(char const* file) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->load_country_db(file); + TORRENT_ASYNC_CALL1(load_country_db, std::string(file)); } int session::as_for_ip(address const& addr) { - mutex::scoped_lock l(m_impl->m_mutex); return m_impl->as_for_ip(addr); } #if TORRENT_USE_WSTRING - bool session::load_asnum_db(wchar_t const* file) + void session::load_asnum_db(wchar_t const* file) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->load_asnum_db(file); + TORRENT_ASYNC_CALL1(load_asnum_db, std::wstring(file)); } - bool session::load_country_db(wchar_t const* file) + void session::load_country_db(wchar_t const* file) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->load_country_db(file); + TORRENT_ASYNC_CALL1(load_country_db, std::wstring(file)); } #endif // TORRENT_USE_WSTRING #endif // TORRENT_DISABLE_GEO_IP @@ -383,89 +459,80 @@ namespace libtorrent bencode(std::back_inserter(buf), ses_state); lazy_entry e; lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->load_state(e); + TORRENT_SYNC_CALL1(load_state, &e); } entry session::state() const { entry ret; - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->save_state(ret, 0xffffffff, l); + TORRENT_SYNC_CALL2(save_state, &ret, 0xffffffff); return ret; } #endif void session::set_ip_filter(ip_filter const& f) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_ip_filter(f); + TORRENT_ASYNC_CALL1(set_ip_filter, f); } - ip_filter const& session::get_ip_filter() const + ip_filter session::get_ip_filter() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->get_ip_filter(); + TORRENT_SYNC_CALL_RET(ip_filter, get_ip_filter); + return r; } void session::set_port_filter(port_filter const& f) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_port_filter(f); + TORRENT_ASYNC_CALL1(set_port_filter, f); } void session::set_peer_id(peer_id const& id) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_peer_id(id); + TORRENT_ASYNC_CALL1(set_peer_id, id); } peer_id session::id() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->get_peer_id(); + TORRENT_SYNC_CALL_RET(peer_id, get_peer_id); + return r; } io_service& session::get_io_service() { - mutex::scoped_lock l(m_impl->m_mutex); return m_impl->m_io_service; } void session::set_key(int key) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_key(key); + TORRENT_ASYNC_CALL1(set_key, key); } std::vector session::get_torrents() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->get_torrents(); + TORRENT_SYNC_CALL_RET(std::vector, get_torrents); + return r; } torrent_handle session::find_torrent(sha1_hash const& info_hash) const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->find_torrent_handle(info_hash); + TORRENT_SYNC_CALL_RET1(torrent_handle, find_torrent_handle, info_hash); + return r; } #ifndef BOOST_NO_EXCEPTIONS torrent_handle session::add_torrent(add_torrent_params const& params) { - mutex::scoped_lock l(m_impl->m_mutex); - error_code ec; - torrent_handle ret = m_impl->add_torrent(params, ec); + TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, ec); if (ec) throw libtorrent_exception(ec); - return ret; + return r; } #endif torrent_handle session::add_torrent(add_torrent_params const& params, error_code& ec) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->add_torrent(params, ec); + TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, ec); + return r; } #ifndef BOOST_NO_EXCEPTIONS @@ -542,58 +609,53 @@ namespace libtorrent void session::remove_torrent(const torrent_handle& h, int options) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->remove_torrent(h, options); + TORRENT_ASYNC_CALL2(remove_torrent, h, options); } bool session::listen_on( std::pair const& port_range , const char* net_interface, int flags) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->listen_on(port_range, net_interface, flags); + TORRENT_SYNC_CALL_RET3(bool, listen_on, port_range, net_interface, flags); + return r; } unsigned short session::listen_port() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->listen_port(); + TORRENT_SYNC_CALL_RET(unsigned short, listen_port); + return r; } session_status session::status() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->status(); + TORRENT_SYNC_CALL_RET(session_status, status); + return r; } void session::pause() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->pause(); + TORRENT_ASYNC_CALL(pause); } void session::resume() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->resume(); + TORRENT_ASYNC_CALL(resume); } bool session::is_paused() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->is_paused(); + TORRENT_SYNC_CALL_RET(bool, is_paused); + return r; } void session::get_cache_info(sha1_hash const& ih , std::vector& ret) const { - mutex::scoped_lock l(m_impl->m_mutex); m_impl->m_disk_thread.get_cache_info(ih, ret); } cache_status session::get_cache_status() const { - mutex::scoped_lock l(m_impl->m_mutex); return m_impl->m_disk_thread.status(); } @@ -601,53 +663,47 @@ namespace libtorrent void session::start_dht() { - mutex::scoped_lock l(m_impl->m_mutex); // the state is loaded in load_state() - m_impl->start_dht(); + TORRENT_ASYNC_CALL(start_dht); } void session::stop_dht() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->stop_dht(); + TORRENT_ASYNC_CALL(stop_dht); } void session::set_dht_settings(dht_settings const& settings) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_dht_settings(settings); + TORRENT_ASYNC_CALL1(set_dht_settings, settings); } #ifndef TORRENT_NO_DEPRECATE void session::start_dht(entry const& startup_state) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->start_dht(startup_state); + TORRENT_ASYNC_CALL1(start_dht, startup_state); } entry session::dht_state() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->dht_state(l); + TORRENT_SYNC_CALL_RET(entry, dht_state); + return r; } #endif void session::add_dht_node(std::pair const& node) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->add_dht_node(node); + TORRENT_ASYNC_CALL1(add_dht_node_name, node); } void session::add_dht_router(std::pair const& node) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->add_dht_router(node); + TORRENT_ASYNC_CALL1(add_dht_router, node); } bool session::is_dht_running() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->m_dht; + TORRENT_SYNC_CALL_RET(bool, is_dht_running); + return r; } #endif @@ -655,230 +711,211 @@ namespace libtorrent #ifndef TORRENT_DISABLE_ENCRYPTION void session::set_pe_settings(pe_settings const& settings) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_pe_settings(settings); + TORRENT_ASYNC_CALL1(set_pe_settings, settings); } - pe_settings const& session::get_pe_settings() const + pe_settings session::get_pe_settings() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->get_pe_settings(); + TORRENT_SYNC_CALL_RET(pe_settings, get_pe_settings); + return r; } #endif bool session::is_listening() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->is_listening(); + TORRENT_SYNC_CALL_RET(bool, is_listening); + return r; } void session::set_settings(session_settings const& s) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_settings(s); + TORRENT_ASYNC_CALL1(set_settings, s); } - session_settings const& session::settings() + session_settings session::settings() { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->settings(); + TORRENT_SYNC_CALL_RET(session_settings, settings); + return r; } void session::set_peer_proxy(proxy_settings const& s) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_peer_proxy(s); + TORRENT_ASYNC_CALL1(set_peer_proxy, s); } void session::set_web_seed_proxy(proxy_settings const& s) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_web_seed_proxy(s); + TORRENT_ASYNC_CALL1(set_web_seed_proxy, s); } void session::set_tracker_proxy(proxy_settings const& s) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_tracker_proxy(s); + TORRENT_ASYNC_CALL1(set_tracker_proxy, s); } - proxy_settings const& session::peer_proxy() const + proxy_settings session::peer_proxy() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->peer_proxy(); + TORRENT_SYNC_CALL_RET(proxy_settings, peer_proxy); + return r; } - proxy_settings const& session::web_seed_proxy() const + proxy_settings session::web_seed_proxy() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->web_seed_proxy(); + TORRENT_SYNC_CALL_RET(proxy_settings, web_seed_proxy); + return r; } - proxy_settings const& session::tracker_proxy() const + proxy_settings session::tracker_proxy() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->tracker_proxy(); + TORRENT_SYNC_CALL_RET(proxy_settings, tracker_proxy); + return r; } #ifndef TORRENT_DISABLE_DHT void session::set_dht_proxy(proxy_settings const& s) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_dht_proxy(s); + TORRENT_ASYNC_CALL1(set_dht_proxy, s); } - proxy_settings const& session::dht_proxy() const + proxy_settings session::dht_proxy() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->dht_proxy(); + TORRENT_SYNC_CALL_RET(proxy_settings, dht_proxy); + return r; } #endif #if TORRENT_USE_I2P void session::set_i2p_proxy(proxy_settings const& s) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_i2p_proxy(s); + TORRENT_ASYNC_CALL1(set_i2p_proxy, s); } - proxy_settings const& session::i2p_proxy() const + proxy_settings session::i2p_proxy() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->i2p_proxy(); + TORRENT_SYNC_CALL_RET(proxy_settings, i2p_proxy); + return r; } #endif int session::max_uploads() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->max_uploads(); + TORRENT_SYNC_CALL_RET(int, max_uploads); + return r; } void session::set_max_uploads(int limit) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_max_uploads(limit); + TORRENT_ASYNC_CALL1(set_max_uploads, limit); } int session::max_connections() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->max_connections(); + TORRENT_SYNC_CALL_RET(int, max_connections); + return r; } void session::set_max_connections(int limit) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_max_connections(limit); + TORRENT_ASYNC_CALL1(set_max_connections, limit); } int session::max_half_open_connections() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->max_half_open_connections(); + TORRENT_SYNC_CALL_RET(int, max_half_open_connections); + return r; } void session::set_max_half_open_connections(int limit) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_max_half_open_connections(limit); + TORRENT_ASYNC_CALL1(set_max_half_open_connections, limit); } int session::local_upload_rate_limit() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->local_upload_rate_limit(); + TORRENT_SYNC_CALL_RET(int, local_upload_rate_limit); + return r; } int session::local_download_rate_limit() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->local_download_rate_limit(); + TORRENT_SYNC_CALL_RET(int, local_download_rate_limit); + return r; } int session::upload_rate_limit() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->upload_rate_limit(); + TORRENT_SYNC_CALL_RET(int, upload_rate_limit); + return r; } int session::download_rate_limit() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->download_rate_limit(); + TORRENT_SYNC_CALL_RET(int, download_rate_limit); + return r; } void session::set_local_upload_rate_limit(int bytes_per_second) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_local_upload_rate_limit(bytes_per_second); + TORRENT_ASYNC_CALL1(set_local_upload_rate_limit, bytes_per_second); } void session::set_local_download_rate_limit(int bytes_per_second) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_local_download_rate_limit(bytes_per_second); + TORRENT_ASYNC_CALL1(set_local_download_rate_limit, bytes_per_second); } void session::set_upload_rate_limit(int bytes_per_second) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_upload_rate_limit(bytes_per_second); + TORRENT_ASYNC_CALL1(set_upload_rate_limit, bytes_per_second); } void session::set_download_rate_limit(int bytes_per_second) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_download_rate_limit(bytes_per_second); + TORRENT_ASYNC_CALL1(set_download_rate_limit, bytes_per_second); } int session::num_uploads() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->num_uploads(); + TORRENT_SYNC_CALL_RET(int, num_uploads); + return r; } int session::num_connections() const { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->num_connections(); + TORRENT_SYNC_CALL_RET(int, num_connections); + return r; } std::auto_ptr session::pop_alert() { - mutex::scoped_lock l(m_impl->m_mutex); return m_impl->pop_alert(); } - void session::set_alert_dispatch(boost::function const& fun) + void session::set_alert_dispatch(boost::function)> const& fun) { - // this function deliberately doesn't acquire the mutex - return m_impl->set_alert_dispatch(fun); + TORRENT_ASYNC_CALL1(set_alert_dispatch, fun); } alert const* session::wait_for_alert(time_duration max_wait) { - // this function deliberately doesn't acquire the mutex return m_impl->wait_for_alert(max_wait); } void session::set_alert_mask(int m) { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->set_alert_mask(m); + TORRENT_ASYNC_CALL1(set_alert_mask, m); } size_t session::set_alert_queue_size_limit(size_t queue_size_limit_) { - mutex::scoped_lock l(m_impl->m_mutex); - return m_impl->set_alert_queue_size_limit(queue_size_limit_); + TORRENT_SYNC_CALL_RET1(size_t, set_alert_queue_size_limit, queue_size_limit_); + return r; } #ifndef TORRENT_NO_DEPRECATE void session::set_severity_level(alert::severity_t s) { - mutex::scoped_lock l(m_impl->m_mutex); int m = 0; switch (s) { @@ -893,85 +930,44 @@ namespace libtorrent default: break; } - m_impl->set_alert_mask(m); + TORRENT_ASYNC_CALL1(set_alert_mask, m); } #endif void session::start_lsd() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->start_lsd(); + TORRENT_ASYNC_CALL(start_lsd); } natpmp* session::start_natpmp() { - mutex::scoped_lock l(m_impl->m_mutex); - if (m_impl->m_natpmp) return m_impl->m_natpmp.get(); - - // the natpmp constructor may fail and call the callbacks - // into the session_impl. We cannot hold the mutex then - l.unlock(); - natpmp* n = new (std::nothrow) natpmp(m_impl->m_io_service - , m_impl->m_listen_interface.address() - , boost::bind(&session_impl::on_port_mapping - , m_impl.get(), _1, _2, _3, 0) - , boost::bind(&session_impl::on_port_map_log - , m_impl.get(), _1, 0)); - l.lock(); - - if (n == 0) return 0; - - m_impl->start_natpmp(n); - return n; + TORRENT_SYNC_CALL_RET(natpmp*, start_natpmp); + return r; } upnp* session::start_upnp() { - mutex::scoped_lock l(m_impl->m_mutex); - - if (m_impl->m_upnp) return m_impl->m_upnp.get(); - - // the upnp constructor may fail and call the callbacks - // into the session_impl. We cannot hold the mutex then - l.unlock(); - upnp* u = new (std::nothrow) upnp(m_impl->m_io_service - , m_impl->m_half_open - , m_impl->m_listen_interface.address() - , m_impl->m_settings.user_agent - , boost::bind(&session_impl::on_port_mapping - , m_impl.get(), _1, _2, _3, 1) - , boost::bind(&session_impl::on_port_map_log - , m_impl.get(), _1, 1) - , m_impl->m_settings.upnp_ignore_nonrouters); - l.lock(); - - if (u == 0) return 0; - - m_impl->start_upnp(u); - return u; + TORRENT_SYNC_CALL_RET(upnp*, start_upnp); + return r; } void session::stop_lsd() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->stop_lsd(); + TORRENT_ASYNC_CALL(stop_lsd); } void session::stop_natpmp() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->stop_natpmp(); + TORRENT_ASYNC_CALL(stop_natpmp); } void session::stop_upnp() { - mutex::scoped_lock l(m_impl->m_mutex); - m_impl->stop_upnp(); + TORRENT_ASYNC_CALL(stop_upnp); } connection_queue& session::get_connection_queue() { - mutex::scoped_lock l(m_impl->m_mutex); return m_impl->m_half_open; } } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 7e1304765..fe0a0892c 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -750,8 +750,10 @@ namespace aux { m_thread.reset(new thread(boost::bind(&session_impl::main_thread, this))); } - void session_impl::save_state(entry& e, boost::uint32_t flags, mutex::scoped_lock& l) const + void session_impl::save_state(entry* eptr, boost::uint32_t flags) const { + entry& e = *eptr; + if (flags & session::save_settings) { // TODO: move these to session_settings @@ -780,12 +782,7 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT if (m_dht && (flags & session::save_dht_state)) { - condition cond; - entry& state = e["dht state"]; - bool done = false; - m_io_service.post(boost::bind(&session_impl::on_dht_state_callback - , this, boost::ref(cond), boost::ref(state), boost::ref(done))); - while (!done) cond.wait(l); + e["dht state"] = m_dht->state(); } #endif @@ -814,29 +811,29 @@ namespace aux { } - void session_impl::load_state(lazy_entry const& e) + void session_impl::load_state(lazy_entry const* e) { lazy_entry const* settings; - if (e.type() != lazy_entry::dict_t) return; + if (e->type() != lazy_entry::dict_t) return; - set_upload_rate_limit(e.dict_find_int_value("upload_rate_limit", 0)); - set_download_rate_limit(e.dict_find_int_value("download_rate_limit", 0)); - set_local_upload_rate_limit(e.dict_find_int_value("local_upload_rate_limit", 0)); - set_local_download_rate_limit(e.dict_find_int_value("local_download_rate_limit", 0)); - set_max_uploads(e.dict_find_int_value("max_uploads", 0)); - set_max_half_open_connections(e.dict_find_int_value("max_half_open_connections", 0)); - set_max_connections(e.dict_find_int_value("max_connections", 0)); + set_upload_rate_limit(e->dict_find_int_value("upload_rate_limit", 0)); + set_download_rate_limit(e->dict_find_int_value("download_rate_limit", 0)); + set_local_upload_rate_limit(e->dict_find_int_value("local_upload_rate_limit", 0)); + set_local_download_rate_limit(e->dict_find_int_value("local_download_rate_limit", 0)); + set_max_uploads(e->dict_find_int_value("max_uploads", 0)); + set_max_half_open_connections(e->dict_find_int_value("max_half_open_connections", 0)); + set_max_connections(e->dict_find_int_value("max_connections", 0)); for (int i = 0; i < sizeof(all_settings)/sizeof(all_settings[0]); ++i) { session_category const& c = all_settings[i]; - settings = e.dict_find_dict(c.name); + settings = e->dict_find_dict(c.name); if (!settings) continue; load_struct(*settings, reinterpret_cast(this) + c.offset, c.map, c.num_entries); } #ifndef TORRENT_DISABLE_DHT - settings = e.dict_find_dict("dht"); + settings = e->dict_find_dict("dht"); if (settings) { dht_settings s; @@ -844,7 +841,7 @@ namespace aux { , sizeof(dht_settings_map)/sizeof(dht_settings_map[0])); set_dht_settings(s); } - settings = e.dict_find_dict("dht state"); + settings = e->dict_find_dict("dht state"); if (settings) { m_dht_state = *settings; @@ -853,7 +850,7 @@ namespace aux { #endif #if TORRENT_USE_I2P - settings = e.dict_find_dict("i2p"); + settings = e->dict_find_dict("i2p"); if (settings) { proxy_settings s; @@ -863,7 +860,7 @@ namespace aux { } #endif #ifndef TORRENT_DISABLE_GEO_IP - settings = e.dict_find_dict("AS map"); + settings = e->dict_find_dict("AS map"); if (settings) { for (int i = 0; i < settings->dict_size(); ++i) @@ -1115,6 +1112,15 @@ namespace aux { // the uTP connections cannot be closed gracefully m_udp_socket.close(); m_external_udp_port = 0; + +#ifndef TORRENT_DISABLE_GEO_IP + if (m_asnum_db) GeoIP_delete(m_asnum_db); + if (m_country_db) GeoIP_delete(m_country_db); + m_asnum_db = 0; + m_country_db = 0; +#endif + + m_disk_thread.abort(); } void session_impl::set_port_filter(port_filter const& f) @@ -1635,13 +1641,12 @@ namespace aux { void session_impl::on_accept_connection(shared_ptr const& s , weak_ptr listen_socket, error_code const& e) { + TORRENT_ASSERT(is_network_thread()); boost::shared_ptr listener = listen_socket.lock(); if (!listener) return; if (e == asio::error::operation_aborted) return; - mutex::scoped_lock l(m_mutex); - if (m_abort) return; error_code ec; @@ -1918,8 +1923,8 @@ namespace aux { // wake them up void session_impl::on_disk_queue() { - mutex::scoped_lock l(m_mutex); - + TORRENT_ASSERT(is_network_thread()); + for (connection_map::iterator i = m_connections.begin(); i != m_connections.end();) { @@ -1948,7 +1953,7 @@ namespace aux { void session_impl::on_tick(error_code const& e) { - mutex::scoped_lock l(m_mutex); + TORRENT_ASSERT(is_network_thread()); ptime now = time_now_hires(); aux::g_current_time = now; @@ -2438,9 +2443,9 @@ namespace aux { void session_impl::on_dht_announce(error_code const& e) { + TORRENT_ASSERT(is_network_thread()); if (e) return; - mutex::scoped_lock l(m_mutex); if (m_abort) return; // announce to DHT every 15 minutes @@ -2464,9 +2469,9 @@ namespace aux { void session_impl::on_lsd_announce(error_code const& e) { + TORRENT_ASSERT(is_network_thread()); if (e) return; - mutex::scoped_lock l(m_mutex); if (m_abort) return; // announce on local network every 5 minutes @@ -2944,6 +2949,12 @@ namespace aux { void session_impl::main_thread() { +#ifdef TORRENT_DEBUG +#if defined BOOST_HAS_PTHREADS + m_network_thread = pthread_self(); +#endif +#endif + TORRENT_ASSERT(is_network_thread()); eh_initializer(); bool stop_loop = false; @@ -2961,7 +2972,6 @@ namespace aux { } m_io_service.reset(); - mutex::scoped_lock l(m_mutex); stop_loop = m_abort; } @@ -2969,7 +2979,6 @@ namespace aux { (*m_logger) << time_now_string() << " locking mutex\n"; #endif - mutex::scoped_lock l(m_mutex); /* #ifdef TORRENT_DEBUG for (torrent_map::iterator i = m_torrents.begin(); @@ -2993,6 +3002,8 @@ namespace aux { // session is locked! boost::weak_ptr session_impl::find_torrent(sha1_hash const& info_hash) { + TORRENT_ASSERT(is_network_thread()); + std::map >::iterator i = m_torrents.find(info_hash); #ifdef TORRENT_DEBUG @@ -3274,7 +3285,7 @@ namespace aux { void session_impl::on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih) { - mutex::scoped_lock l(m_mutex); + TORRENT_ASSERT(is_network_thread()); INVARIANT_CHECK; @@ -3308,7 +3319,8 @@ namespace aux { void session_impl::on_port_mapping(int mapping, int port , error_code const& ec, int map_transport) { - mutex::scoped_lock l(m_mutex); + TORRENT_ASSERT(is_network_thread()); + TORRENT_ASSERT(map_transport >= 0 && map_transport <= 1); if (mapping == m_udp_mapping[map_transport] && port != 0) @@ -3521,30 +3533,15 @@ namespace aux { m_dht_settings = settings; } - void session_impl::on_dht_state_callback(condition& c - , entry& e, bool& done) const - { - mutex::scoped_lock l(m_mutex); - if (m_dht) e = m_dht->state(); - done = true; - c.signal(l); - } - #ifndef TORRENT_NO_DEPRECATE - entry session_impl::dht_state(mutex::scoped_lock& l) const + entry session_impl::dht_state() const { - condition cond; if (!m_dht) return entry(); - entry e; - bool done = false; - m_io_service.post(boost::bind(&session_impl::on_dht_state_callback - , this, boost::ref(cond), boost::ref(e), boost::ref(done))); - while (!done) cond.wait(l); - return e; + return m_dht->state(); } #endif - void session_impl::add_dht_node(std::pair const& node) + void session_impl::add_dht_node_name(std::pair const& node) { TORRENT_ASSERT(m_dht); m_dht->add_node(node); @@ -3584,22 +3581,15 @@ namespace aux { session_impl::~session_impl() { - mutex::scoped_lock l(m_mutex); +#if defined BOOST_HAS_PTHREADS + TORRENT_ASSERT(!is_network_thread()); +#endif #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << "\n\n *** shutting down session *** \n\n"; #endif - abort(); - TORRENT_ASSERT(m_connections.empty()); + m_io_service.post(boost::bind(&session_impl::abort, this)); -#ifndef TORRENT_DISABLE_GEO_IP - if (m_asnum_db) GeoIP_delete(m_asnum_db); - if (m_country_db) GeoIP_delete(m_country_db); - m_asnum_db = 0; - m_country_db = 0; -#endif - - l.unlock(); // we need to wait for the disk-io thread to // die first, to make sure it won't post any // more messages to the io_service containing references @@ -3702,7 +3692,7 @@ namespace aux { m_upload_channel.throttle(bytes_per_second); } - void session_impl::set_alert_dispatch(boost::function const& fun) + void session_impl::set_alert_dispatch(boost::function)> const& fun) { m_alerts.set_dispatch_function(fun); } @@ -3712,9 +3702,7 @@ namespace aux { // too expensive // INVARIANT_CHECK; - if (m_alerts.pending()) - return m_alerts.get(); - return std::auto_ptr(0); + return m_alerts.get(); } alert const* session_impl::wait_for_alert(time_duration max_wait) @@ -3765,10 +3753,22 @@ namespace aux { m_lsd->use_broadcast(true); } - void session_impl::start_natpmp(natpmp* n) + natpmp* session_impl::start_natpmp() { INVARIANT_CHECK; + if (m_natpmp) return m_natpmp.get(); + + // the natpmp constructor may fail and call the callbacks + // into the session_impl. + natpmp* n = new (std::nothrow) natpmp(m_io_service + , m_listen_interface.address() + , boost::bind(&session_impl::on_port_mapping + , this, _1, _2, _3, 0) + , boost::bind(&session_impl::on_port_map_log + , this, _1, 0)); + if (n == 0) return 0; + m_natpmp = n; if (m_listen_interface.port() > 0) @@ -3783,10 +3783,25 @@ namespace aux { } } - void session_impl::start_upnp(upnp* u) + upnp* session_impl::start_upnp() { INVARIANT_CHECK; + if (m_upnp) return m_upnp.get(); + + // the upnp constructor may fail and call the callbacks + upnp* u = new (std::nothrow) upnp(m_io_service + , m_half_open + , m_listen_interface.address() + , m_settings.user_agent + , boost::bind(&session_impl::on_port_mapping + , this, _1, _2, _3, 1) + , boost::bind(&session_impl::on_port_map_log + , this, _1, 1) + , m_settings.upnp_ignore_nonrouters); + + if (u == 0) return 0; + m_upnp = u; m_upnp->discover_device(); diff --git a/src/smart_ban.cpp b/src/smart_ban.cpp index 73cac4286..2146b6132 100644 --- a/src/smart_ban.cpp +++ b/src/smart_ban.cpp @@ -167,7 +167,7 @@ namespace void on_read_failed_block(piece_block b, address a, int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_torrent.session().m_mutex); + TORRENT_ASSERT(m_torrent.session().is_network_thread()); disk_buffer_holder buffer(m_torrent.session(), j.buffer); @@ -248,7 +248,7 @@ namespace void on_read_ok_block(std::pair b, int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_torrent.session().m_mutex); + TORRENT_ASSERT(m_torrent.session().is_network_thread()); disk_buffer_holder buffer(m_torrent.session(), j.buffer); diff --git a/src/torrent.cpp b/src/torrent.cpp index da1416559..ba110c4d5 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -636,7 +636,7 @@ namespace libtorrent void torrent::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r, read_piece_struct* rp) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); disk_buffer_holder buffer(m_ses, j.buffer); @@ -716,7 +716,7 @@ namespace libtorrent void torrent::on_disk_write_complete(int ret, disk_io_job const& j , peer_request p) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -864,7 +864,7 @@ namespace libtorrent if (m_seed_mode) { - m_ses.m_io_service.post(boost::bind(&torrent::files_checked_lock, shared_from_this())); + m_ses.m_io_service.post(boost::bind(&torrent::files_checked, shared_from_this())); std::vector().swap(m_resume_data); lazy_entry().swap(m_resume_entry); return; @@ -937,7 +937,7 @@ namespace libtorrent void torrent::on_resume_data_checked(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (ret == piece_manager::fatal_disk_error) { @@ -1120,7 +1120,7 @@ namespace libtorrent } } - files_checked(l); + files_checked(); } else { @@ -1191,7 +1191,7 @@ namespace libtorrent void torrent::on_force_recheck(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (ret == piece_manager::fatal_disk_error) { @@ -1201,7 +1201,7 @@ namespace libtorrent if (ret == 0) { // if there are no files, just start - files_checked(l); + files_checked(); } else { @@ -1223,7 +1223,7 @@ namespace libtorrent void torrent::on_piece_checked(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; if (ret == piece_manager::disk_check_aborted) @@ -1263,15 +1263,15 @@ namespace libtorrent if (ret == piece_manager::need_full_check) return; dequeue_torrent_check(); - files_checked(l); + files_checked(); } - void torrent::use_interface(const char* net_interface) + void torrent::use_interface(std::string net_interface) { INVARIANT_CHECK; error_code ec; - address a(address::from_string(net_interface, ec)); + address a(address::from_string(net_interface.c_str(), ec)); if (ec) return; m_net_interface = tcp::endpoint(a, 0); } @@ -1287,7 +1287,7 @@ namespace libtorrent void torrent::on_tracker_announce() { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); m_waiting_tracker = false; if (m_abort) return; announce_with_tracker(); @@ -1537,7 +1537,7 @@ namespace libtorrent void torrent::tracker_warning(tracker_request const& req, std::string const& msg) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -1548,7 +1548,7 @@ namespace libtorrent void torrent::tracker_scrape_response(tracker_request const& req , int complete, int incomplete, int downloaded) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; TORRENT_ASSERT(req.kind == tracker_request::scrape_request); @@ -1574,7 +1574,7 @@ namespace libtorrent , int incomplete , address const& external_ip) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; TORRENT_ASSERT(r.kind == tracker_request::announce_request); @@ -1756,7 +1756,7 @@ namespace libtorrent #if TORRENT_USE_I2P void torrent::on_i2p_resolve(error_code const& ec, char const* dest) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -1773,7 +1773,7 @@ namespace libtorrent void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host , peer_id pid) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -2572,7 +2572,7 @@ namespace libtorrent void torrent::on_files_deleted(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (ret != 0) { @@ -2589,7 +2589,7 @@ namespace libtorrent void torrent::on_files_released(int ret, disk_io_job const& j) { /* - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (alerts().should_post()) { @@ -2606,7 +2606,7 @@ namespace libtorrent void torrent::on_save_resume_data(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (!j.resume_data) { @@ -2623,7 +2623,7 @@ namespace libtorrent void torrent::on_file_renamed(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (ret == 0) { @@ -2641,7 +2641,7 @@ namespace libtorrent void torrent::on_torrent_paused(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (alerts().should_post()) alerts().post_alert(torrent_paused_alert(get_handle())); @@ -3348,7 +3348,7 @@ namespace libtorrent void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host , std::list::iterator web) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -3411,7 +3411,7 @@ namespace libtorrent void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host , std::list::iterator web, tcp::endpoint proxy) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -3564,7 +3564,7 @@ namespace libtorrent void torrent::on_country_lookup(error_code const& error, tcp::resolver::iterator i , intrusive_ptr p) const { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; @@ -4688,14 +4688,9 @@ namespace libtorrent return index; } - void torrent::files_checked_lock() - { - mutex::scoped_lock l(m_ses.m_mutex); - files_checked(l); - } - - void torrent::files_checked(mutex::scoped_lock const& l) + void torrent::files_checked() { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(m_torrent_file->is_valid()); if (m_abort) return; @@ -4799,6 +4794,7 @@ namespace libtorrent void torrent::move_storage(std::string const& save_path) { + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; if (m_owning_storage.get()) @@ -4818,7 +4814,7 @@ namespace libtorrent void torrent::on_storage_moved(int ret, disk_io_job const& j) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); if (ret == 0) { @@ -4847,17 +4843,20 @@ namespace libtorrent torrent_handle torrent::get_handle() { + TORRENT_ASSERT(m_ses.is_network_thread()); return torrent_handle(shared_from_this()); } session_settings const& torrent::settings() const { + TORRENT_ASSERT(m_ses.is_network_thread()); return m_ses.settings(); } #ifdef TORRENT_DEBUG void torrent::check_invariant() const { + TORRENT_ASSERT(m_ses.is_network_thread()); if (is_paused()) TORRENT_ASSERT(num_peers() == 0); if (!should_check_files()) @@ -5005,10 +5004,25 @@ namespace libtorrent #endif void torrent::set_sequential_download(bool sd) - { m_sequential_download = sd; } + { + TORRENT_ASSERT(m_ses.is_network_thread()); + m_sequential_download = sd; + } + + void torrent::queue_up() + { + set_queue_position(queue_position() == 0 + ? queue_position() : queue_position() - 1); + } + + void torrent::queue_down() + { + set_queue_position(queue_position() + 1); + } void torrent::set_queue_position(int p) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT((p == -1) == is_finished() || (!m_auto_managed && p == -1) || (m_abort && p == -1)); @@ -5080,6 +5094,7 @@ namespace libtorrent void torrent::set_max_uploads(int limit) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(limit >= -1); if (limit <= 0) limit = (std::numeric_limits::max)(); m_max_uploads = limit; @@ -5087,6 +5102,7 @@ namespace libtorrent void torrent::set_max_connections(int limit) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(limit >= -1); if (limit <= 0) limit = (std::numeric_limits::max)(); m_max_connections = limit; @@ -5094,6 +5110,7 @@ namespace libtorrent void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(limit >= -1); peer_iterator i = std::find_if(m_connections.begin(), m_connections.end() , boost::bind(&peer_connection::remote, _1) == ip); @@ -5103,6 +5120,7 @@ namespace libtorrent void torrent::set_peer_download_limit(tcp::endpoint ip, int limit) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(limit >= -1); peer_iterator i = std::find_if(m_connections.begin(), m_connections.end() , boost::bind(&peer_connection::remote, _1) == ip); @@ -5112,6 +5130,7 @@ namespace libtorrent void torrent::set_upload_limit(int limit) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(limit >= -1); if (limit <= 0) limit = 0; m_bandwidth_channel[peer_connection::upload_channel].throttle(limit); @@ -5119,6 +5138,7 @@ namespace libtorrent int torrent::upload_limit() const { + TORRENT_ASSERT(m_ses.is_network_thread()); int limit = m_bandwidth_channel[peer_connection::upload_channel].throttle(); if (limit == (std::numeric_limits::max)()) limit = -1; return limit; @@ -5126,6 +5146,7 @@ namespace libtorrent void torrent::set_download_limit(int limit) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(limit >= -1); if (limit <= 0) limit = 0; m_bandwidth_channel[peer_connection::download_channel].throttle(limit); @@ -5133,6 +5154,7 @@ namespace libtorrent int torrent::download_limit() const { + TORRENT_ASSERT(m_ses.is_network_thread()); int limit = m_bandwidth_channel[peer_connection::download_channel].throttle(); if (limit == (std::numeric_limits::max)()) limit = -1; return limit; @@ -5140,6 +5162,7 @@ namespace libtorrent void torrent::delete_files() { + TORRENT_ASSERT(m_ses.is_network_thread()); #if defined TORRENT_VERBOSE_LOGGING for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) @@ -5161,6 +5184,7 @@ namespace libtorrent void torrent::clear_error() { + TORRENT_ASSERT(m_ses.is_network_thread()); if (!m_error) return; bool checking_files = should_check_files(); if (m_ses.m_auto_manage_time_scaler > 2) @@ -5175,6 +5199,7 @@ namespace libtorrent void torrent::set_error(error_code const& ec, std::string const& error_file) { + TORRENT_ASSERT(m_ses.is_network_thread()); bool checking_files = should_check_files(); m_error = ec; m_error_file = error_file; @@ -5189,6 +5214,7 @@ namespace libtorrent void torrent::auto_managed(bool a) { + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; if (m_auto_managed == a) return; @@ -5214,6 +5240,7 @@ namespace libtorrent // the higher seed rank, the more important to seed int torrent::seed_rank(session_settings const& s) const { + TORRENT_ASSERT(m_ses.is_network_thread()); enum flags { seed_ratio_not_met = 0x400000, @@ -5276,6 +5303,7 @@ namespace libtorrent // this is an async operation triggered by the client void torrent::save_resume_data() { + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; if (!m_owning_storage.get()) @@ -5304,6 +5332,7 @@ namespace libtorrent bool torrent::should_check_files() const { + TORRENT_ASSERT(m_ses.is_network_thread()); // #error should m_allow_peers really affect checking? return (m_state == torrent_status::checking_files || m_state == torrent_status::queued_for_checking) @@ -5314,23 +5343,27 @@ namespace libtorrent void torrent::flush_cache() { + TORRENT_ASSERT(m_ses.is_network_thread()); m_storage->async_release_files( boost::bind(&torrent::on_cache_flushed, shared_from_this(), _1, _2)); } void torrent::on_cache_flushed(int ret, disk_io_job const& j) { + TORRENT_ASSERT(m_ses.is_network_thread()); if (alerts().should_post()) alerts().post_alert(cache_flushed_alert(get_handle())); } bool torrent::is_paused() const { + TORRENT_ASSERT(m_ses.is_network_thread()); return !m_allow_peers || m_ses.is_paused(); } void torrent::pause() { + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; if (!m_allow_peers) return; @@ -5352,6 +5385,7 @@ namespace libtorrent void torrent::do_pause() { + TORRENT_ASSERT(m_ses.is_network_thread()); if (!is_paused()) return; #ifndef TORRENT_DISABLE_EXTENSIONS @@ -5397,6 +5431,7 @@ namespace libtorrent void torrent::set_allow_peers(bool b) { + TORRENT_ASSERT(m_ses.is_network_thread()); if (m_allow_peers == b) return; bool checking_files = should_check_files(); @@ -5421,6 +5456,7 @@ namespace libtorrent void torrent::resume() { + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; if (m_allow_peers @@ -5439,6 +5475,7 @@ namespace libtorrent void torrent::do_resume() { + TORRENT_ASSERT(m_ses.is_network_thread()); if (is_paused()) return; #ifndef TORRENT_DISABLE_EXTENSIONS @@ -5465,6 +5502,7 @@ namespace libtorrent void torrent::update_tracker_timer(ptime now) { + TORRENT_ASSERT(m_ses.is_network_thread()); if (!m_announcing) return; ptime next_announce = max_time(); @@ -5511,6 +5549,7 @@ namespace libtorrent void torrent::start_announcing() { + TORRENT_ASSERT(m_ses.is_network_thread()); if (is_paused()) return; // if we don't have metadata, we need to announce // before checking files, to get peers to @@ -5552,6 +5591,7 @@ namespace libtorrent void torrent::stop_announcing() { + TORRENT_ASSERT(m_ses.is_network_thread()); if (!m_announcing) return; error_code ec; @@ -5571,6 +5611,7 @@ namespace libtorrent void torrent::second_tick(stat& accumulator, int tick_interval_ms) { + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; ptime now = time_now(); @@ -5749,6 +5790,7 @@ namespace libtorrent void torrent::refresh_explicit_cache(int cache_size) { + TORRENT_ASSERT(m_ses.is_network_thread()); if (!ready_for_connections()) return; // rotate the cached pieces @@ -5835,6 +5877,7 @@ namespace libtorrent void torrent::get_suggested_pieces(std::vector& s) const { + TORRENT_ASSERT(m_ses.is_network_thread()); if (settings().suggest_mode == session_settings::no_piece_suggestions) { s.clear(); @@ -5869,6 +5912,7 @@ namespace libtorrent void torrent::add_stats(stat const& s) { + TORRENT_ASSERT(m_ses.is_network_thread()); // these stats are propagated to the session // stats the next time second_tick is called m_stat += s; @@ -5876,6 +5920,7 @@ namespace libtorrent void torrent::request_time_critical_pieces() { + TORRENT_ASSERT(m_ses.is_network_thread()); // build a list of peers and sort it by download_queue_time std::vector peers; peers.reserve(m_connections.size()); @@ -5975,6 +6020,7 @@ namespace libtorrent std::set torrent::web_seeds(web_seed_entry::type_t type) const { + TORRENT_ASSERT(m_ses.is_network_thread()); std::set ret; for (std::list::const_iterator i = m_web_seeds.begin() , end(m_web_seeds.end()); i != end; ++i) @@ -5987,6 +6033,7 @@ namespace libtorrent void torrent::retry_web_seed(peer_connection* p, int retry) { + TORRENT_ASSERT(m_ses.is_network_thread()); std::list::iterator i = std::find_if(m_web_seeds.begin(), m_web_seeds.end() , (boost::bind(&web_seed_entry::connection, _1) == p)); @@ -5998,6 +6045,7 @@ namespace libtorrent bool torrent::try_connect_peer() { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(want_more_peers()); if (m_deficit_counter < 100) return false; m_deficit_counter -= 100; @@ -6007,14 +6055,23 @@ namespace libtorrent void torrent::give_connect_points(int points) { + TORRENT_ASSERT(m_ses.is_network_thread()); TORRENT_ASSERT(points <= 100); TORRENT_ASSERT(points > 0); TORRENT_ASSERT(want_more_peers()); m_deficit_counter += points; } + void torrent::add_peer(tcp::endpoint const& adr, int source) + { + TORRENT_ASSERT(m_ses.is_network_thread()); + peer_id id(0); + m_policy.add_peer(adr, id, source, 0); + } + void torrent::async_verify_piece(int piece_index, boost::function const& f) { + TORRENT_ASSERT(m_ses.is_network_thread()); // INVARIANT_CHECK; TORRENT_ASSERT(m_storage); @@ -6044,7 +6101,7 @@ namespace libtorrent void torrent::on_piece_verified(int ret, disk_io_job const& j , boost::function f) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); // return value: // 0: success, piece passed hash check @@ -6472,7 +6529,7 @@ namespace libtorrent , int response_code, error_code const& ec, const std::string& msg , int retry_interval) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); INVARIANT_CHECK; diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 8eef17756..87868855d 100644 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -61,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/utf8.hpp" +#include "libtorrent/thread.hpp" #if defined(_MSC_VER) && _MSC_VER < 1300 namespace std @@ -72,50 +73,124 @@ namespace std using libtorrent::aux::session_impl; -#ifdef BOOST_NO_EXCEPTIONS - -#define TORRENT_FORWARD(call) \ - boost::shared_ptr t = m_torrent.lock(); \ - if (!t) return; \ - mutex::scoped_lock l(t->session().m_mutex); \ - t->call - -#define TORRENT_FORWARD_RETURN(call, def) \ - boost::shared_ptr t = m_torrent.lock(); \ - if (!t) return def; \ - mutex::scoped_lock l(t->session().m_mutex); \ - return t->call - -#define TORRENT_FORWARD_RETURN2(call, def) \ - boost::shared_ptr t = m_torrent.lock(); \ - if (!t) return def; \ - mutex::scoped_lock l(t->session().m_mutex); \ - t->call - -#else - -#define TORRENT_FORWARD(call) \ - boost::shared_ptr t = m_torrent.lock(); \ - if (!t) throw_invalid_handle(); \ - mutex::scoped_lock l(t->session().m_mutex); \ - t->call - -#define TORRENT_FORWARD_RETURN(call, def) \ - boost::shared_ptr t = m_torrent.lock(); \ - if (!t) throw_invalid_handle(); \ - mutex::scoped_lock l(t->session().m_mutex); \ - return t->call - -#define TORRENT_FORWARD_RETURN2(call, def) \ - boost::shared_ptr t = m_torrent.lock(); \ - if (!t) throw_invalid_handle(); \ - mutex::scoped_lock l(t->session().m_mutex); \ - t->call - -#endif - namespace libtorrent { + + template + void fun_ret(R* ret, bool* done, condition* e, mutex* m, boost::function f) + { + *ret = f(); + mutex::scoped_lock l(*m); + *done = true; + e->signal(l); + } + + // defined in session.cpp + void fun_wrap(bool* done, condition* e, mutex* m, boost::function f); + +#define TORRENT_ASYNC_CALL(x) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return; \ + session_impl& ses = t->session(); \ + ses.m_io_service.post(boost::bind(&torrent:: x, t)) + +#define TORRENT_ASYNC_CALL1(x, a1) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return; \ + session_impl& ses = t->session(); \ + ses.m_io_service.post(boost::bind(&torrent:: x, t, a1)) + +#define TORRENT_ASYNC_CALL2(x, a1, a2) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return; \ + session_impl& ses = t->session(); \ + ses.m_io_service.post(boost::bind(&torrent:: x, t, a1, a2)) + +#define TORRENT_ASYNC_CALL3(x, a1, a2, a3) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return; \ + session_impl& ses = t->session(); \ + ses.m_io_service.post(boost::bind(&torrent:: x, t, a1, a2, a3)) + +#define TORRENT_SYNC_CALL(x) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return; \ + bool done = false; \ + session_impl& ses = t->session(); \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_wrap, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t)))); \ + do { ses.cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL1(x, a1) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (t) { \ + bool done = false; \ + session_impl& ses = t->session(); \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_wrap, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t, a1)))); \ + t.reset(); \ + do { ses.cond.wait(l); } while(!done); } + +#define TORRENT_SYNC_CALL2(x, a1, a2) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (t) { \ + bool done = false; \ + session_impl& ses = t->session(); \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_wrap, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t, a1, a2)))); \ + t.reset(); \ + do { ses.cond.wait(l); } while(!done); } + +#define TORRENT_SYNC_CALL3(x, a1, a2, a3) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (t) { \ + bool done = false; \ + session_impl& ses = t->session(); \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_wrap, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t, a1, a2, a3)))); \ + t.reset(); \ + do { ses.cond.wait(l); } while(!done); } + +#define TORRENT_SYNC_CALL_RET(type, def, x) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return def; \ + bool done = false; \ + session_impl& ses = t->session(); \ + type r; \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_ret, &r, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t)))); \ + t.reset(); \ + do { ses.cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL_RET1(type, def, x, a1) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return def; \ + bool done = false; \ + session_impl& ses = t->session(); \ + type r; \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_ret, &r, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t, a1)))); \ + t.reset(); \ + do { ses.cond.wait(l); } while(!done) + +#define TORRENT_SYNC_CALL_RET2(type, def, x, a1, a2) \ + boost::shared_ptr t = m_torrent.lock(); \ + if (!t) return def; \ + bool done = false; \ + session_impl& ses = t->session(); \ + type r; \ + mutex::scoped_lock l(ses.mut); \ + ses.cond.clear(l); \ + ses.m_io_service.post(boost::bind(&fun_ret, &r, &done, &ses.cond, &ses.mut, boost::function(boost::bind(&torrent:: x, t, a1, a2)))); \ + t.reset(); \ + do { ses.cond.wait(l); } while(!done) + #ifndef BOOST_NO_EXCEPTIONS void throw_invalid_handle() { @@ -134,86 +209,91 @@ namespace libtorrent { INVARIANT_CHECK; const static sha1_hash empty; - TORRENT_FORWARD_RETURN(torrent_file().info_hash(), empty); + TORRENT_SYNC_CALL_RET(sha1_hash, empty, info_hash); + return r; } int torrent_handle::max_uploads() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(max_uploads(), 0); + TORRENT_SYNC_CALL_RET(int, 0, max_uploads); + return r; } void torrent_handle::set_max_uploads(int max_uploads) const { INVARIANT_CHECK; TORRENT_ASSERT(max_uploads >= 2 || max_uploads == -1); - TORRENT_FORWARD(set_max_uploads(max_uploads)); + TORRENT_ASYNC_CALL1(set_max_uploads, max_uploads); } void torrent_handle::use_interface(const char* net_interface) const { INVARIANT_CHECK; - TORRENT_FORWARD(use_interface(net_interface)); + TORRENT_ASYNC_CALL1(use_interface, std::string(net_interface)); } int torrent_handle::max_connections() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(max_connections(), 0); + TORRENT_SYNC_CALL_RET(int, 0, max_connections); + return r; } void torrent_handle::set_max_connections(int max_connections) const { INVARIANT_CHECK; TORRENT_ASSERT(max_connections >= 2 || max_connections == -1); - TORRENT_FORWARD(set_max_connections(max_connections)); + TORRENT_ASYNC_CALL1(set_max_connections, max_connections); } void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const { INVARIANT_CHECK; TORRENT_ASSERT(limit >= -1); - TORRENT_FORWARD(set_peer_upload_limit(ip, limit)); + TORRENT_ASYNC_CALL2(set_peer_upload_limit, ip, limit); } void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const { INVARIANT_CHECK; TORRENT_ASSERT(limit >= -1); - TORRENT_FORWARD(set_peer_download_limit(ip, limit)); + TORRENT_ASYNC_CALL2(set_peer_download_limit, ip, limit); } void torrent_handle::set_upload_limit(int limit) const { INVARIANT_CHECK; TORRENT_ASSERT(limit >= -1); - TORRENT_FORWARD(set_upload_limit(limit)); + TORRENT_ASYNC_CALL1(set_upload_limit, limit); } int torrent_handle::upload_limit() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(upload_limit(), 0); + TORRENT_SYNC_CALL_RET(int, 0, upload_limit); + return r; } void torrent_handle::set_download_limit(int limit) const { INVARIANT_CHECK; TORRENT_ASSERT(limit >= -1); - TORRENT_FORWARD(set_download_limit(limit)); + TORRENT_ASYNC_CALL1(set_download_limit, limit); } int torrent_handle::download_limit() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(download_limit(), 0); + TORRENT_SYNC_CALL_RET(int, 0, download_limit); + return r; } void torrent_handle::move_storage( std::string const& save_path) const { INVARIANT_CHECK; - TORRENT_FORWARD(move_storage(save_path)); + TORRENT_ASYNC_CALL1(move_storage, save_path); } #if TORRENT_USE_WSTRING @@ -223,7 +303,7 @@ namespace libtorrent INVARIANT_CHECK; std::string utf8; wchar_utf8(save_path, utf8); - TORRENT_FORWARD(move_storage(utf8)); + TORRENT_ASYNC_CALL1(move_storage, utf8); } void torrent_handle::rename_file(int index, std::wstring const& new_name) const @@ -231,14 +311,14 @@ namespace libtorrent INVARIANT_CHECK; std::string utf8; wchar_utf8(new_name, utf8); - TORRENT_FORWARD(rename_file(index, utf8)); + TORRENT_ASYNC_CALL2(rename_file, index, utf8); } #endif // TORRENT_USE_WSTRING void torrent_handle::rename_file(int index, std::string const& new_name) const { INVARIANT_CHECK; - TORRENT_FORWARD(rename_file(index, new_name)); + TORRENT_ASYNC_CALL2(rename_file, index, new_name); } void torrent_handle::add_extension( @@ -246,141 +326,148 @@ namespace libtorrent , void* userdata) { INVARIANT_CHECK; - TORRENT_FORWARD(add_extension(ext, userdata)); + TORRENT_ASYNC_CALL2(add_extension, ext, userdata); } bool torrent_handle::has_metadata() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(valid_metadata(), false); + TORRENT_SYNC_CALL_RET(bool, false, valid_metadata); + return r; } bool torrent_handle::set_metadata(char const* metadata, int size) const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(set_metadata(metadata, size), false); + TORRENT_SYNC_CALL_RET2(bool, false, set_metadata, metadata, size); + return r; } bool torrent_handle::is_seed() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(is_seed(), false); + TORRENT_SYNC_CALL_RET(bool, false, is_seed); + return r; } bool torrent_handle::is_finished() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(is_finished(), false); + TORRENT_SYNC_CALL_RET(bool, false, is_finished); + return r; } bool torrent_handle::is_paused() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(is_torrent_paused(), false); + TORRENT_SYNC_CALL_RET(bool, false, is_torrent_paused); + return r; } void torrent_handle::pause() const { INVARIANT_CHECK; - TORRENT_FORWARD(pause()); + TORRENT_ASYNC_CALL(pause); } void torrent_handle::set_upload_mode(bool b) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_upload_mode(b)); + TORRENT_ASYNC_CALL1(set_upload_mode, b); } void torrent_handle::flush_cache() const { INVARIANT_CHECK; - TORRENT_FORWARD(flush_cache()); + TORRENT_ASYNC_CALL(flush_cache); } void torrent_handle::save_resume_data() const { INVARIANT_CHECK; - TORRENT_FORWARD(save_resume_data()); + TORRENT_ASYNC_CALL(save_resume_data); } bool torrent_handle::need_save_resume_data() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(need_save_resume_data(), false); + TORRENT_SYNC_CALL_RET(bool, false, need_save_resume_data); + return r; } void torrent_handle::force_recheck() const { INVARIANT_CHECK; - TORRENT_FORWARD(force_recheck()); + TORRENT_ASYNC_CALL(force_recheck); } void torrent_handle::resume() const { INVARIANT_CHECK; - TORRENT_FORWARD(resume()); + TORRENT_ASYNC_CALL(resume); } bool torrent_handle::is_auto_managed() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(is_auto_managed(), true); + TORRENT_SYNC_CALL_RET(bool, false, is_auto_managed); + return r; } void torrent_handle::auto_managed(bool m) const { INVARIANT_CHECK; - TORRENT_FORWARD(auto_managed(m)); + TORRENT_ASYNC_CALL1(auto_managed, m); } void torrent_handle::set_priority(int p) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_priority(p)); + TORRENT_ASYNC_CALL1(set_priority, p); } int torrent_handle::queue_position() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(queue_position(), -1); + TORRENT_SYNC_CALL_RET(int, -1, queue_position); + return r; } void torrent_handle::queue_position_up() const { INVARIANT_CHECK; - TORRENT_FORWARD(set_queue_position(t->queue_position() == 0 - ? t->queue_position() : t->queue_position() - 1)); + TORRENT_ASYNC_CALL(queue_down); } void torrent_handle::queue_position_down() const { INVARIANT_CHECK; - TORRENT_FORWARD(set_queue_position(t->queue_position() + 1)); + TORRENT_ASYNC_CALL(queue_up); } void torrent_handle::queue_position_top() const { INVARIANT_CHECK; - TORRENT_FORWARD(set_queue_position(0)); + TORRENT_ASYNC_CALL1(set_queue_position, 0); } void torrent_handle::queue_position_bottom() const { INVARIANT_CHECK; - TORRENT_FORWARD(set_queue_position((std::numeric_limits::max)())); + TORRENT_ASYNC_CALL1(set_queue_position, INT_MAX); } void torrent_handle::clear_error() const { INVARIANT_CHECK; - TORRENT_FORWARD(clear_error()); + TORRENT_ASYNC_CALL(clear_error); } void torrent_handle::set_tracker_login(std::string const& name , std::string const& password) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_tracker_login(name, password)); + TORRENT_ASYNC_CALL2(set_tracker_login, name, password); } #ifndef TORRENT_NO_DEPRECATE @@ -388,7 +475,7 @@ namespace libtorrent void torrent_handle::file_progress(std::vector& progress) const { INVARIANT_CHECK; - TORRENT_FORWARD(file_progress(progress)); + TORRENT_SYNC_CALL1(file_progress, boost::ref(progress)); } #endif #endif @@ -396,88 +483,93 @@ namespace libtorrent void torrent_handle::file_progress(std::vector& progress, int flags) const { INVARIANT_CHECK; - TORRENT_FORWARD(file_progress(progress, flags)); + TORRENT_SYNC_CALL2(file_progress, boost::ref(progress), flags); } torrent_status torrent_handle::status(boost::uint32_t flags) const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(status(flags), torrent_status()); + TORRENT_SYNC_CALL_RET1(torrent_status, torrent_status(), status, flags); + return r; } void torrent_handle::set_sequential_download(bool sd) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_sequential_download(sd)); + TORRENT_ASYNC_CALL1(set_sequential_download, sd); } bool torrent_handle::is_sequential_download() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(is_sequential_download(), false); + TORRENT_SYNC_CALL_RET(bool, false, is_sequential_download); + return r; } std::string torrent_handle::name() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(name(), ""); + TORRENT_SYNC_CALL_RET(std::string, "", name); + return r; } void torrent_handle::piece_availability(std::vector& avail) const { INVARIANT_CHECK; - TORRENT_FORWARD(piece_availability(avail)); + TORRENT_SYNC_CALL1(piece_availability, boost::ref(avail)); } void torrent_handle::piece_priority(int index, int priority) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_piece_priority(index, priority)); + TORRENT_ASYNC_CALL2(set_piece_priority, index, priority); } int torrent_handle::piece_priority(int index) const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(piece_priority(index), 0); + TORRENT_SYNC_CALL_RET1(int, 0, piece_priority, index); + return r; } void torrent_handle::prioritize_pieces(std::vector const& pieces) const { INVARIANT_CHECK; - TORRENT_FORWARD(prioritize_pieces(pieces)); + TORRENT_ASYNC_CALL1(prioritize_pieces, pieces); } std::vector torrent_handle::piece_priorities() const { INVARIANT_CHECK; std::vector ret; - TORRENT_FORWARD_RETURN2(piece_priorities(ret), ret); + TORRENT_SYNC_CALL1(piece_priorities, boost::ref(ret)); return ret; } void torrent_handle::file_priority(int index, int priority) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_file_priority(index, priority)); + TORRENT_ASYNC_CALL2(set_file_priority, index, priority); } int torrent_handle::file_priority(int index) const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(file_priority(index), 0); + TORRENT_SYNC_CALL_RET1(int, 0, file_priority, index); + return r; } void torrent_handle::prioritize_files(std::vector const& files) const { INVARIANT_CHECK; - TORRENT_FORWARD(prioritize_files(files)); + TORRENT_ASYNC_CALL1(prioritize_files, files); } std::vector torrent_handle::file_priorities() const { INVARIANT_CHECK; std::vector ret; - TORRENT_FORWARD_RETURN2(file_priorities(ret), ret); + TORRENT_SYNC_CALL1(file_priorities, ret); return ret; } @@ -487,33 +579,34 @@ namespace libtorrent void torrent_handle::filter_piece(int index, bool filter) const { INVARIANT_CHECK; - TORRENT_FORWARD(filter_piece(index, filter)); + TORRENT_ASYNC_CALL2(filter_piece, index, filter); } void torrent_handle::filter_pieces(std::vector const& pieces) const { INVARIANT_CHECK; - TORRENT_FORWARD(filter_pieces(pieces)); + TORRENT_ASYNC_CALL1(filter_pieces, pieces); } bool torrent_handle::is_piece_filtered(int index) const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(is_piece_filtered(index), false); + TORRENT_SYNC_CALL_RET1(bool, false, is_piece_filtered, index); + return r; } std::vector torrent_handle::filtered_pieces() const { INVARIANT_CHECK; std::vector ret; - TORRENT_FORWARD_RETURN2(filtered_pieces(ret), ret); + TORRENT_SYNC_CALL1(filtered_pieces, ret); return ret; } void torrent_handle::filter_files(std::vector const& files) const { INVARIANT_CHECK; - TORRENT_FORWARD(filter_files(files)); + TORRENT_ASYNC_CALL1(filter_files, files); } // ============ end deprecation =============== @@ -523,76 +616,80 @@ namespace libtorrent { INVARIANT_CHECK; const static std::vector empty; - TORRENT_FORWARD_RETURN(trackers(), empty); + TORRENT_SYNC_CALL_RET(std::vector, empty, trackers); + return r; } void torrent_handle::add_url_seed(std::string const& url) const { INVARIANT_CHECK; - TORRENT_FORWARD(add_web_seed(url, web_seed_entry::url_seed)); + TORRENT_ASYNC_CALL2(add_web_seed, url, web_seed_entry::url_seed); } void torrent_handle::remove_url_seed(std::string const& url) const { INVARIANT_CHECK; - TORRENT_FORWARD(remove_web_seed(url, web_seed_entry::url_seed)); + TORRENT_ASYNC_CALL2(remove_web_seed, url, web_seed_entry::url_seed); } std::set torrent_handle::url_seeds() const { INVARIANT_CHECK; const static std::set empty; - TORRENT_FORWARD_RETURN(web_seeds(web_seed_entry::url_seed), empty); + TORRENT_SYNC_CALL_RET1(std::set, empty, web_seeds, web_seed_entry::url_seed); + return r; } void torrent_handle::add_http_seed(std::string const& url) const { INVARIANT_CHECK; - TORRENT_FORWARD(add_web_seed(url, web_seed_entry::http_seed)); + TORRENT_ASYNC_CALL2(add_web_seed, url, web_seed_entry::http_seed); } void torrent_handle::remove_http_seed(std::string const& url) const { INVARIANT_CHECK; - TORRENT_FORWARD(remove_web_seed(url, web_seed_entry::http_seed)); + TORRENT_ASYNC_CALL2(remove_web_seed, url, web_seed_entry::http_seed); } std::set torrent_handle::http_seeds() const { INVARIANT_CHECK; const static std::set empty; - TORRENT_FORWARD_RETURN(web_seeds(web_seed_entry::http_seed), empty); + TORRENT_SYNC_CALL_RET1(std::set, empty, web_seeds, web_seed_entry::http_seed); + return r; } void torrent_handle::replace_trackers( std::vector const& urls) const { INVARIANT_CHECK; - TORRENT_FORWARD(replace_trackers(urls)); + TORRENT_ASYNC_CALL1(replace_trackers, urls); } void torrent_handle::add_tracker(announce_entry const& url) const { INVARIANT_CHECK; - TORRENT_FORWARD(add_tracker(url)); + TORRENT_ASYNC_CALL1(add_tracker, url); } void torrent_handle::add_piece(int piece, char const* data, int flags) const { INVARIANT_CHECK; - TORRENT_FORWARD(add_piece(piece, data, flags)); + TORRENT_SYNC_CALL3(add_piece, piece, data, flags); } void torrent_handle::read_piece(int piece) const { INVARIANT_CHECK; - TORRENT_FORWARD(read_piece(piece)); + TORRENT_ASYNC_CALL1(read_piece, piece); } storage_interface* torrent_handle::get_storage_impl() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(get_storage(), 0); + TORRENT_SYNC_CALL_RET(storage_interface*, 0, get_storage); + return r; } torrent_info const& torrent_handle::get_torrent_info() const @@ -608,7 +705,7 @@ namespace libtorrent #else throw_invalid_handle(); #endif - mutex::scoped_lock l(t->session().m_mutex); +// mutex::scoped_lock l(t->session().m_mutex); if (!t->valid_metadata()) #ifdef BOOST_NO_EXCEPTIONS return empty; @@ -630,8 +727,18 @@ namespace libtorrent INVARIANT_CHECK; entry ret(entry::dictionary_t); - TORRENT_FORWARD_RETURN2(write_resume_data(ret), ret); - t->filesystem().write_resume_data(ret); + TORRENT_SYNC_CALL1(write_resume_data, boost::ref(ret)); + if (t) + { + bool done = false; + session_impl& ses = t->session(); + mutex::scoped_lock l(ses.mut); + ses.cond.clear(l); + ses.m_io_service.post(boost::bind(&fun_wrap, &done, &ses.cond + , &ses.mut, boost::function(boost::bind( + &piece_manager::write_resume_data, &t->filesystem(), boost::ref(ret))))); + do { ses.cond.wait(l); } while(!done); + } return ret; } @@ -640,64 +747,54 @@ namespace libtorrent std::string torrent_handle::save_path() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(save_path(), std::string()); + TORRENT_SYNC_CALL_RET(std::string, "", save_path); + return r; } void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const { INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - if (!t) -#ifdef BOOST_NO_EXCEPTIONS - return; -#else - throw_invalid_handle(); -#endif - mutex::scoped_lock l(t->session().m_mutex); - - peer_id id; - std::fill(id.begin(), id.end(), 0); - t->get_policy().add_peer(adr, id, source, 0); + TORRENT_ASYNC_CALL2(add_peer, adr, source); } void torrent_handle::force_reannounce( boost::posix_time::time_duration duration) const { INVARIANT_CHECK; - TORRENT_FORWARD(force_tracker_request(time_now() + seconds(duration.total_seconds()))); + TORRENT_ASYNC_CALL1(force_tracker_request, time_now() + seconds(duration.total_seconds())); } #ifndef TORRENT_DISABLE_DHT void torrent_handle::force_dht_announce() const { INVARIANT_CHECK; - TORRENT_FORWARD(dht_announce()); + TORRENT_ASYNC_CALL(dht_announce); } #endif void torrent_handle::force_reannounce() const { INVARIANT_CHECK; - TORRENT_FORWARD(force_tracker_request()); + TORRENT_ASYNC_CALL1(force_tracker_request, time_now()); } void torrent_handle::scrape_tracker() const { INVARIANT_CHECK; - TORRENT_FORWARD(scrape_tracker()); + TORRENT_ASYNC_CALL(scrape_tracker); } bool torrent_handle::super_seeding() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(super_seeding(), false); + TORRENT_SYNC_CALL_RET(bool, false, super_seeding); + return r; } void torrent_handle::super_seeding(bool on) const { INVARIANT_CHECK; - TORRENT_FORWARD(super_seeding(on)); + TORRENT_ASYNC_CALL1(super_seeding, on); } void torrent_handle::set_ratio(float ratio) const @@ -707,45 +804,46 @@ namespace libtorrent TORRENT_ASSERT(ratio >= 0.f); if (ratio < 1.f && ratio > 0.f) ratio = 1.f; - TORRENT_FORWARD(set_ratio(ratio)); + TORRENT_ASYNC_CALL1(set_ratio, ratio); } #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES void torrent_handle::resolve_countries(bool r) { INVARIANT_CHECK; - TORRENT_FORWARD(resolve_countries(r)); + TORRENT_ASYNC_CALL1(resolve_countries, r); } bool torrent_handle::resolve_countries() const { INVARIANT_CHECK; - TORRENT_FORWARD_RETURN(resolving_countries(), false); + TORRENT_SYNC_CALL_RET(bool, false, resolving_countries); + return r; } #endif void torrent_handle::get_full_peer_list(std::vector& v) const { INVARIANT_CHECK; - TORRENT_FORWARD(get_full_peer_list(v)); + TORRENT_SYNC_CALL1(get_full_peer_list, boost::ref(v)); } void torrent_handle::get_peer_info(std::vector& v) const { INVARIANT_CHECK; - TORRENT_FORWARD(get_peer_info(v)); + TORRENT_SYNC_CALL1(get_peer_info, boost::ref(v)); } void torrent_handle::get_download_queue(std::vector& queue) const { INVARIANT_CHECK; - TORRENT_FORWARD(get_download_queue(queue)); + TORRENT_SYNC_CALL1(get_download_queue, boost::ref(queue)); } void torrent_handle::set_piece_deadline(int index, int deadline, int flags) const { INVARIANT_CHECK; - TORRENT_FORWARD(set_piece_deadline(index, deadline, flags)); + TORRENT_ASYNC_CALL3(set_piece_deadline, index, deadline, flags); } } diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 53ca90201..8846b3a7a 100644 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -172,13 +172,13 @@ namespace libtorrent void tracker_manager::sent_bytes(int bytes) { -// mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); m_ses.m_stat.sent_tracker_bytes(bytes); } void tracker_manager::received_bytes(int bytes) { - mutex::scoped_lock l(m_ses.m_mutex); + TORRENT_ASSERT(m_ses.is_network_thread()); m_ses.m_stat.received_tracker_bytes(bytes); } diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 0cc4c72f7..05f0e6c93 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -384,6 +384,7 @@ void run_elevator_test() // this is not guaranteed, but very very likely TEST_CHECK(turns > 20); + dio.abort(); dio.join(); } } @@ -574,6 +575,7 @@ void run_storage_tests(boost::intrusive_ptr info ios.poll(ec); if (ec) std::cerr << "poll: " << ec.message() << std::endl; + io.abort(); io.join(); remove_all(combine_path(test_path, "temp_storage2"), ec); if (ec) std::cerr << "remove_all: " << ec.message() << std::endl; @@ -723,6 +725,7 @@ void test_check_files(std::string const& test_path TEST_EQUAL(pieces[1], false); TEST_EQUAL(pieces[2], false); TEST_EQUAL(pieces[3], true); + io.abort(); io.join(); } diff --git a/test/test_transfer.cpp b/test/test_transfer.cpp index 22e7c405d..aacfcda89 100644 --- a/test/test_transfer.cpp +++ b/test/test_transfer.cpp @@ -112,9 +112,9 @@ void test_rate() } -void print_alert(alert const& a) +void print_alert(std::auto_ptr) { - std::cout << "ses1 (alert dispatch function): " << a.message() << std::endl; + std::cout << "ses1 (alert dispatch function): "/* << a.message() */ << std::endl; } // simulate a full disk